Add Cloudflare email and collaboration workflows
This commit is contained in:
@@ -1,64 +1,74 @@
|
||||
# Project Status Report
|
||||
|
||||
**Generated:** 2026-06-24
|
||||
**Updated:** 2026-07-22
|
||||
**Branch:** main
|
||||
**Last Commit:** b6d2ded - passkey existing (2026-06-16)
|
||||
**Last Commit:** 09f51d1 - Add queued email notifications for collaboration events
|
||||
|
||||
## Quick Stats
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total Tracked Files | 189 |
|
||||
| Go Files | 46 |
|
||||
| Swift Files | 14 (macOS app) |
|
||||
| Test Files | 10 |
|
||||
| Avg Test Coverage | ~39% (markdown 87%, store 70%, auth 55%, sync 54%) |
|
||||
| Total Tracked Files | 201 |
|
||||
| Go Files | 63 |
|
||||
| Swift Files | 15 (macOS app and package manifest) |
|
||||
| Go Test Files | 18 |
|
||||
| Aggregate Go Test Coverage | 52.4% |
|
||||
| Milestones Complete | 3/6 (50%) |
|
||||
|
||||
## Recent Activity (since 2026-06-01 report)
|
||||
## Verification
|
||||
|
||||
16 commits on `main` between `fb0673a` (2026-06-01) and `b6d2ded` (2026-06-16):
|
||||
71 files changed, +7908 / -812 lines.
|
||||
- `go test -coverpkg=./... -coverprofile=... ./...` passes with 52.4% aggregate statement coverage.
|
||||
- `swift build` passes for the macOS app and CLI.
|
||||
- Focused race tests pass for email, collaboration, and HTTP packages. A full `go test -race ./...` exceeds the current five-minute local timeout.
|
||||
- `govulncheck` currently fails because Go 1.24.2 has 31 reachable standard-library vulnerabilities; the pinned Go toolchain must be upgraded before production sign-off.
|
||||
- Highest package coverage: Markdown 87.0%, email 77.9%, store 70.0%, config 67.9%, auth 54.9%, and sync 54.2%.
|
||||
- Collaboration, configuration, email-provider, and collaboration HTTP integration tests are present; database, logging, and realtime still lack direct suites.
|
||||
|
||||
Highlights:
|
||||
- `b6d2ded` passkey existing-user login flow
|
||||
- `4655008` text editor link autocomplete
|
||||
- `0adb980` CodeMirror editor integration
|
||||
- `c39c50b` dropdown menu + comment side panel (wires M4 comment UI)
|
||||
- `6c30fd8` sync service update
|
||||
- `04a1f2b` ops design + app scaffolding (`entrypoint.sh`)
|
||||
- `632621b`/`1e939f3` macOS menu-bar app: live search popover, drop-target icon
|
||||
- `ddc7d5c` accounts and email wiring
|
||||
- `93e96be`/`73d505a` UI CSS expansion (~1900 lines) and workspace browser polish
|
||||
- New untracked subsystems: `permissions_handlers.go` (RBAC sharing UI), `tags.js`/`tag.gohtml` (tagging), `keyboard-nav.js`, `mobile.js`, `archive.js`
|
||||
## Recent Activity
|
||||
|
||||
Recent work has moved the project beyond the previous 2026-06-24 report:
|
||||
|
||||
- Durable email queue with retry/backoff and failed-delivery inspection.
|
||||
- Postmark outbound sender with API-level tests.
|
||||
- Cloudflare Email Service REST sender with retry/permanent-error classification and API-level tests.
|
||||
- File-change and comment notifications now enqueue email delivery.
|
||||
- Notification bell/list/read UI is active.
|
||||
- Document watch/unwatch controls are active, watcher subscriptions are deduplicated, and ancestor-folder matching is fixed.
|
||||
- Nested comment replies, whole-thread resolution, and resolved-history UI are active.
|
||||
- Notification dispatch rechecks the watcher's current document permission.
|
||||
- Existing users can add another passkey from their account page.
|
||||
- Resource permission UI and private-by-default filtering cover documents, folders, navigation, search, API document lists, and native sync snapshots.
|
||||
- CodeMirror editor, wiki-link autocomplete, keyboard navigation, mobile drawers, archive UI, and tag pages are present.
|
||||
- The macOS menu-bar app and CLI compile successfully.
|
||||
|
||||
## Milestone Progress
|
||||
|
||||
- [x] Milestone 1: Foundation
|
||||
- [x] Milestone 2: Sync Protocol
|
||||
- [x] Milestone 3: Authentication
|
||||
- [ ] Milestone 4: Collaboration (comments UI wired; email integration in progress; digest/preferences pending)
|
||||
- [ ] Milestone 5: Search & UI (server FTS5 done; design-system CSS, keyboard nav, mobile responsive shipped; `/design` route, Flexsearch, a11y audits pending)
|
||||
- [ ] Milestone 6: Production (not started)
|
||||
- [ ] Milestone 4: Collaboration (threaded comments, notification bell, watch controls, and queued Postmark/Cloudflare/SMTP delivery shipped; preferences, digest, inbound replies, mention/conflict triggers, and live-provider tests remain)
|
||||
- [ ] Milestone 5: Search & UI (server FTS5, tags, keyboard navigation, and responsive foundations shipped; offline client search, `/design`, performance, and accessibility validation remain)
|
||||
- [ ] Milestone 6: Production (health/readiness endpoints, CI, deployment scaffolding, and some integration tests exist; hardening acceptance criteria remain open)
|
||||
|
||||
**Current Focus:** M4 Email Integration (Postmark adapter, templates, queue with retry)
|
||||
## Current Focus
|
||||
|
||||
## Untracked Subsystems (not in original plan)
|
||||
Milestone 4 collaboration completion:
|
||||
|
||||
These shipped but are not milestone-tracked. Tracked via `notes/untracked-subsystems.md`:
|
||||
- Add notification preferences and digest delivery.
|
||||
- Add inbound email replies through a verified webhook flow.
|
||||
- Add mention and conflict notification triggers.
|
||||
- Test watcher-to-email delivery against live Postmark and Cloudflare accounts.
|
||||
|
||||
- **Permissions / RBAC sharing UI** — `permissions_handlers.go` (431 lines), `permissions.gohtml`, `permissions.js`. Per-resource read/write/admin grants.
|
||||
- **Tagging** — `tags.js`, `tag.gohtml`. Document tags.
|
||||
- **CodeMirror inline editor** — `editor.js` (+620), `codemirror.bundle.js`, link autocomplete.
|
||||
- **macOS menu-bar app** — 14 Swift files, live search popover, drag-drop target. Beyond web-first plan scope.
|
||||
- **API tokens** — `token_create.gohtml`, `auth.APIKey` types.
|
||||
- **Password reset flow** — `password_reset.gohtml`, `auth.PasswordResetToken` repository methods.
|
||||
## Known Gaps Requiring Human Review
|
||||
|
||||
## Notes for Human Review
|
||||
|
||||
- `collaboration.Service` defines its own `EmailSender` interface duplicating `email.Sender`. Consolidate when convenient.
|
||||
- `Service.notifyWatchersOfComment` and `NotifyDocumentChanged` create in-app notifications only; never invoke `s.email`. `Notification.EmailedAt` field unused.
|
||||
- `email.SMTPSender` uses unauthenticated SMTP (fine for local Mailpit, not Postmark).
|
||||
- Go 1.24.2 is below the patched versions reported by `govulncheck`, including fixes for `html/template`, `crypto/tls`, `net/http`, and `crypto/x509` vulnerabilities.
|
||||
- WebSocket broadcasts are authenticated but not filtered by per-document permissions.
|
||||
- Content-hash downloads are not tied back to effective document permission.
|
||||
- Browser caches are not cleared on logout.
|
||||
- Raw HTML is enabled in authored Markdown while the security specification says it should be disabled.
|
||||
- Folder/collection permission administration is only fully discoverable for documents.
|
||||
- The implementation uses JSON for SimpleSync while protocol documentation still leaves JSON versus protobuf unresolved.
|
||||
- Backup documentation does not match the named data volume in Compose.
|
||||
|
||||
---
|
||||
*This report updated 2026-06-24 by hand. Next refresh when M4 email work lands.*
|
||||
*This report is maintained from the implementation and verification results, not milestone checkbox state alone.*
|
||||
|
||||
@@ -7,7 +7,14 @@ Accepted
|
||||
The platform needs to send email notifications for: file changes (to watchers), new comments, conflict alerts, and digest summaries. It must also receive email replies and convert them to comments. Requirement: use Postmark email gateway with plain-text only.
|
||||
|
||||
## Decision
|
||||
**Postmark HTTP API for outgoing email, Postmark inbound webhook for incoming email.**
|
||||
**Postmark or Cloudflare Email Service HTTP API for outgoing email, with a
|
||||
provider-specific verified inbound webhook for incoming email.**
|
||||
|
||||
Amended 2026-07-22: Cloudflare Email Service is supported as an alternative
|
||||
transactional outbound provider. The same durable queue and plain-text
|
||||
templates are shared by Postmark, Cloudflare, and local SMTP. Cloudflare-hosted
|
||||
Workers would normally use an Email binding, but Cairnquire is a standalone Go
|
||||
application and therefore uses the authenticated REST API.
|
||||
|
||||
### Implementation
|
||||
|
||||
|
||||
@@ -97,12 +97,14 @@ Cairnquire is a self-hosted documentation platform. A single Go binary serves HT
|
||||
- Client syncs index to IndexedDB for offline search
|
||||
- Index rebuilds incrementally on file changes
|
||||
|
||||
### 7. Email (Postmark)
|
||||
- Go adapter using Postmark HTTP API
|
||||
### 7. Email (Postmark or Cloudflare Email Service)
|
||||
- Go adapters use the Postmark or Cloudflare Email Sending REST API
|
||||
- Local development uses SMTP with Mailpit
|
||||
- A durable SQLite queue handles asynchronous delivery and bounded retries
|
||||
- Plain-text emails only (no HTML)
|
||||
- Threading via Message-ID / In-Reply-To headers
|
||||
- Webhook endpoint receives email replies, converts to comments
|
||||
- Templates: notification, digest, conflict alert
|
||||
- Planned: threading via Message-ID / In-Reply-To headers
|
||||
- Planned: verified inbound webhook converts email replies to comments
|
||||
- Implemented templates: file change, comment, mention, and conflict; digest remains planned
|
||||
|
||||
### 8. File Store (Content-Addressed)
|
||||
- Files stored by SHA-256 hash: `store/ab/cd/abcdef1234...`
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
- [x] Comment system (backend + UI wired)
|
||||
- [x] Comment creation endpoint (web)
|
||||
- [x] Comment threading (parent/child) - schema supports it
|
||||
- [x] Comment threading (parent/child) with nested browser replies
|
||||
- [x] Line/section anchoring (hash-based)
|
||||
- [x] Comment resolution (mark as resolved)
|
||||
- [x] Whole-thread resolution with resolved-history view
|
||||
- [x] Comment display in the Go-served browser UI (`c39c50b` dropdown menu + comment side panel, `comments.js` +330 lines)
|
||||
|
||||
- [x] Notification system (backend complete)
|
||||
@@ -21,10 +21,10 @@
|
||||
- [ ] Global notification settings
|
||||
- [ ] Digest mode (hourly/daily batches)
|
||||
|
||||
- [x] Web notification UI (backend complete, JS partial)
|
||||
- [x] Notification bell with unread count - API exists
|
||||
- [x] Notification list dropdown - API exists
|
||||
- [x] Mark as read functionality - API exists
|
||||
- [x] Web notification UI
|
||||
- [x] Notification bell with unread count
|
||||
- [x] Notification list dropdown
|
||||
- [x] Mark one/all as read functionality
|
||||
- [ ] Notification preferences page
|
||||
|
||||
### Week 8: Email Integration & Conflict Resolution
|
||||
@@ -34,6 +34,7 @@
|
||||
- [x] Postmark adapter (`email/postmark.go`)
|
||||
- [x] Plain-text email templates (`email/templates.go`)
|
||||
- [x] Outgoing email queue with retry (`email/queue.go` + migration 000016)
|
||||
- [x] Cloudflare Email Service REST adapter (`email/cloudflare.go`)
|
||||
- [ ] Webhook endpoint for inbound email
|
||||
|
||||
- [x] Email notification types
|
||||
@@ -60,20 +61,20 @@
|
||||
### Functional
|
||||
- [x] Users can add comments to specific lines in a document (API exists)
|
||||
- [x] Comments are linked to document version (hash)
|
||||
- [x] Comment threading works (reply to reply) (schema supports it)
|
||||
- [x] Users can watch files or folders for changes (API exists)
|
||||
- [x] Email notifications sent within 1 minute of event (Postmark adapter + queue with retry)
|
||||
- [x] Comment threading works (reply to reply) in the browser and API
|
||||
- [x] Users can watch files or folders for changes (document UI + APIs)
|
||||
- [x] Email notifications queued within 1 minute of event (Postmark, Cloudflare, or SMTP sender)
|
||||
- [ ] Replying to notification email creates a comment
|
||||
- [ ] Digest emails batch notifications by time window
|
||||
- [x] Conflicts display side-by-side diff (M2 sync)
|
||||
- [x] Conflicts display a unified diff (M2 sync)
|
||||
- [x] Users can resolve conflicts via web UI (M2 sync)
|
||||
- [ ] Resolved comments are hidden but accessible in history
|
||||
- [x] Resolved comments are hidden but accessible in history
|
||||
|
||||
### Non-Functional
|
||||
- [x] Emails are plain-text only (no HTML) — enforced by templates, verified by test
|
||||
- [ ] Email threading works in Gmail, Outlook, Apple Mail
|
||||
- [ ] Webhook signature verified for inbound email
|
||||
- [x] Failed emails retried 3 times with exponential backoff — queue.go, verified by test
|
||||
- [x] Temporary email failures retried 3 times with exponential backoff; permanent provider rejections fail immediately
|
||||
- [x] Email queue doesn't block web requests (async processing) — worker runs in goroutine
|
||||
|
||||
### Email Template Examples
|
||||
@@ -166,7 +167,7 @@ CREATE TABLE watchers (
|
||||
|
||||
- [ ] All acceptance criteria pass
|
||||
- [ ] Email flows tested with real Postmark account
|
||||
- [ ] Comment threading tested with 3+ levels
|
||||
- [x] Comment threading tested with 3+ levels
|
||||
- [ ] Conflict resolution tested with 2+ concurrent editors
|
||||
- [ ] Notification preferences persist across sessions
|
||||
- [ ] Digest mode tested with 24-hour window
|
||||
|
||||
@@ -150,19 +150,19 @@ A minimal-dependency, ultra-fast documentation platform that publishes markdown
|
||||
**Goal:** Comments, notifications, and conflict resolution
|
||||
|
||||
- [x] Comment system linked to file versions (by hash) - backend complete
|
||||
- [ ] Email notifications via Postmark adapter - SMTP stub exists
|
||||
- [x] Queued email notifications via Postmark, Cloudflare Email Service, or local SMTP
|
||||
- [x] Web-based conflict resolution UI (Milestone 2)
|
||||
- [ ] Notification preferences (per-file, per-folder, global, digest)
|
||||
- [x] Comment threading schema - UI needs wiring
|
||||
- [x] Comment threading schema and browser reply UI
|
||||
- [ ] Email replies create comments
|
||||
|
||||
**Acceptance Criteria:**
|
||||
|
||||
- [x] Users can comment on specific lines/sections of a document (API)
|
||||
- [x] Comments persist and are linked to document versions
|
||||
- [ ] Email notifications sent for watched file changes (NoOp sender)
|
||||
- [x] Email notifications queued for watched file changes with retry
|
||||
- [ ] Replying to notification email creates a comment
|
||||
- [x] Conflicts display side-by-side diff with resolution actions (M2)
|
||||
- [x] Conflicts display a unified diff with resolution actions (M2)
|
||||
- [ ] Digest mode batches notifications by time window
|
||||
|
||||
---
|
||||
@@ -265,7 +265,7 @@ See [architecture-overview.md](architecture-overview.md) for detailed component
|
||||
| Markdown | `github.com/yuin/goldmark` + extensions | Fast, extensible, CommonMark compliant |
|
||||
| WebSocket | `github.com/gorilla/websocket` | Most widely used Go WS library |
|
||||
| File Watch | `github.com/fsnotify/fsnotify` | Cross-platform, stdlib-adjacent |
|
||||
| Email | `github.com/keighl/postmark` + `net/smtp` | Postmark adapter + SMTP fallback |
|
||||
| Email | `net/http` + `net/smtp` | Postmark/Cloudflare REST adapters + local SMTP |
|
||||
| Crypto | `crypto/ed25519`, `crypto/sha256` | Standard library, no external deps |
|
||||
| Templates | `html/template` | Stdlib, auto-escaping, SSR-safe |
|
||||
|
||||
@@ -371,7 +371,7 @@ cairnquire/
|
||||
| WebAuthn/passkey adoption issues | Medium | Medium | Password fallback always available; extensive browser testing |
|
||||
| SQLite performance at scale | Low | High | libsql replication path; FTS5 for search; benchmark early |
|
||||
| Markdown extension parser bugs | Medium | Medium | Fuzz testing; strict CommonMark base; gradual feature rollout |
|
||||
| Email deliverability | Medium | Medium | Postmark reputation monitoring; SPF/DKIM setup; SMTP fallback |
|
||||
| Email deliverability | Medium | Medium | Provider reputation monitoring; SPF/DKIM/DMARC setup; provider fallback |
|
||||
| Frontend bundle bloat | Medium | Medium | Bundle analysis in CI; tree-shaking enforced; lazy loading |
|
||||
| File sync conflicts in teams | High | Medium | Clear UX for conflict resolution; email notification; automatic merge when possible |
|
||||
|
||||
@@ -383,11 +383,9 @@ cairnquire/
|
||||
2. ✅ Complete Milestone 2: Sync Protocol
|
||||
3. ✅ Complete Milestone 3: Authentication
|
||||
4. 🔄 Finish Milestone 4: Collaboration
|
||||
- Wire up comment UI in browser (JS exists, needs integration)
|
||||
- Wire up notification bell UI
|
||||
- Implement actual email sending (Postmark or SMTP)
|
||||
- Add notification preferences page
|
||||
- Test watcher-driven notifications end-to-end
|
||||
- Complete inbound email replies, mention notifications, and conflict notifications
|
||||
- Add global/per-resource notification preferences and digest scheduling
|
||||
- Test watcher-driven notifications against live Postmark and Cloudflare accounts
|
||||
5. 🔄 Finish Milestone 5: Search & UI Polish
|
||||
- Tag filtering in search
|
||||
- Design system /design route
|
||||
@@ -395,11 +393,11 @@ cairnquire/
|
||||
- Mobile-responsive layout polish
|
||||
- Accessibility improvements
|
||||
6. ⏳ Milestone 6: Production Hardening
|
||||
- Increase test coverage from 39% to 80%+
|
||||
- Increase test coverage from 52.4% to 80%+
|
||||
- Add integration tests for auth, sync, collaboration
|
||||
- Security audit checklist
|
||||
- Backup/restore scripts
|
||||
- Health check and monitoring endpoints
|
||||
- Complete dependency health checks and add monitoring endpoints
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -53,8 +53,12 @@ deployment, only `CAIRNQUIRE_PUBLIC_ORIGIN` must be supplied in `.env`.
|
||||
| Variable | Required | Compose default | Description |
|
||||
|----------|----------|-----------------|-------------|
|
||||
| `CAIRNQUIRE_PUBLIC_ORIGIN` | Yes | None | Exact external HTTPS origin. Passkeys and device-flow URLs depend on this value. |
|
||||
| `CAIRNQUIRE_EMAIL_PROVIDER` | No | `smtp` | Outbound provider: `smtp`, `postmark`, `cloudflare`, or `noop`. |
|
||||
| `CAIRNQUIRE_EMAIL_SMTP_HOST` | No | `mailpit` | SMTP server used for notifications. |
|
||||
| `CAIRNQUIRE_EMAIL_SMTP_PORT` | No | `1025` | SMTP server port. |
|
||||
| `CAIRNQUIRE_EMAIL_POSTMARK_TOKEN` | For Postmark | Empty | Postmark server token. |
|
||||
| `CAIRNQUIRE_EMAIL_CLOUDFLARE_ACCOUNT_ID` | For Cloudflare | Empty | Account with Cloudflare Email Sending enabled. |
|
||||
| `CAIRNQUIRE_EMAIL_CLOUDFLARE_API_TOKEN` | For Cloudflare | Empty | API token with Email Sending permission. Store it as a deployment secret. |
|
||||
| `CAIRNQUIRE_EMAIL_FROM` | No | `notifications@cairnquire.local` | Notification sender address. |
|
||||
| `CAIRNQUIRE_LOG_LEVEL` | No | `INFO` | Application log level. |
|
||||
|
||||
@@ -72,6 +76,23 @@ checked-in Compose deployment:
|
||||
| `CAIRNQUIRE_CONFIG` | Empty | Optional JSON configuration file. Environment variables override it. |
|
||||
| `CAIRNQUIRE_DEV_MODE` | `false` | Local-only auth shortcut. Never enable this on a deployed server. |
|
||||
|
||||
### Cloudflare Email Service
|
||||
|
||||
Cairnquire is an external Go application, so it uses Cloudflare Email
|
||||
Service's REST API rather than a Workers binding. Before enabling the provider:
|
||||
|
||||
1. Enable Email Sending for the sender domain in Cloudflare, or run `npx wrangler email sending enable example.com`.
|
||||
2. Create a Cloudflare API token with Email Sending permission for the account.
|
||||
3. Set `CAIRNQUIRE_EMAIL_PROVIDER=cloudflare`, the account ID, API token, and a `CAIRNQUIRE_EMAIL_FROM` address on the onboarded domain.
|
||||
|
||||
Cloudflare Email Service is used only for transactional notifications. API
|
||||
tokens must be supplied through deployment secrets and must not be committed.
|
||||
The durable queue retries Cloudflare `429` and server errors; validation and
|
||||
permanent-bounce responses are retained immediately as failed deliveries.
|
||||
|
||||
Cloudflare Email Routing for inbound comment replies is a separate Milestone 4
|
||||
feature and is not enabled by these outbound settings.
|
||||
|
||||
## Persistent Data
|
||||
|
||||
Compose mounts:
|
||||
|
||||
Reference in New Issue
Block a user