# Cairnquire - Project Plan **Version:** 1.2\ **Date:** 2026-05-14\ **Status:** In Progress — Milestones 1-3 Complete ## Vision A minimal-dependency, ultra-fast documentation platform that publishes markdown notes as a responsive web application. Features wiki-style linking, collaborative comments, offline-capable sync, and fine-grained access control — all deployable via a single `docker-compose.yml` with zero vendor lock-in. ## Design Principles 1. **Paranoid Security**: Cryptographic content verification, battle-tested dependencies only, supply-chain attack mitigation through minimal external code 2. **Operational Simplicity**: Single binary, single SQLite database, filesystem storage — nothing that can't be understood in an afternoon 3. **Performance First**: Sub-100ms initial page loads, instant client-side navigation, no JavaScript required for reading 4. **Offline Capability**: Read cached, sync when connected 5. **No Vendor Lock-in**: Works on any Docker host; no cloud-specific APIs --- ## Milestones ### Milestone 1: Foundation ✅ COMPLETE **Goal:** Working server that can serve markdown files as HTML - [x] Go HTTP server with chi router - [x] libsql database with schema migration system - [x] Markdown-to-HTML pipeline with most common extensions enabled - [x] Static file serving for attachments - [x] Basic Dockerfile and docker-compose.yml - [x] Dev mode with `air` live reload + Vite HMR proxy - [x] Miller column document browser with folder navigation - [x] `index.md` default rendering for folders - [x] Content-addressed attachment storage with secure serving - [x] WebSocket real-time updates (document change notifications) **Acceptance Criteria:** - [x] Server starts and listens on configurable port - [x] Database auto-migrates on startup - [x] Markdown files with wiki-links, tags, callouts, mermaid, math render correctly - [x] Attachments served securely with content-type headers - [x] Docker compose brings up full stack with one command - [x] All dependencies pinned with checksum verification - [x] Build reproducible (same input → same binary hash) **Notes:** - Mermaid diagrams and math blocks now render client-side after server-rendered markdown loads. - Dev mode uses `air` for Go live reload and Vite proxy for frontend HMR. --- ### Milestone 2: Sync Protocol (Weeks 3-4) ✅ COMPLETE **Goal:** Bidirectional file sync between server and filesystem/web client - [x] Content-addressed storage (SHA-256 filesystem layout) - [x] WebSocket sync protocol implementation - [x] File watcher for local filesystem sync - [x] Client-side IndexedDB cache - [x] Offline queue with conflict detection **Acceptance Criteria:** - [x] File changes on disk automatically sync to server within 5 seconds - [x] Web client can sync after reconnection, even with changes made offline - [x] Concurrent edits to different files succeed without conflict - [x] Concurrent edits to same file detected and queued for resolution - [x] All synced content verified against SHA-256 hashes - [x] Sync protocol documented with state machine diagrams **What's Done:** - Real-time file watcher using `fsnotify` — detects create/write/remove/rename events on `.md` files - Changes trigger immediate `SyncSourceDir()` and broadcast `document_version` events via WebSocket - Browser shows reload notification when current document or folder structure changes - Fallback polling every 30 seconds ensures nothing is missed - Go-served editor caches pages and pending edits in IndexedDB for offline reads and recovery - Offline saves queue locally and sync after reconnection with a visible pending changes panel - Server-side save conflicts return 409 responses with base/current hashes and server content - Conflict resolution screen shows server copy vs queued edit, then resolves into a Monaco editor - Static assets from the content directory can be embedded from markdown documents - Markdown rendering now supports raw HTML when authored in trusted content - File watcher debounces editor save bursts and ignores hidden/temp files - SimpleSync spec documents the intended browser, watcher, realtime, and native-client feature set - Go-level multi-client sync tests cover different-file success, same-file conflicts, and resolution behavior - 100-file sync performance validation covers source sync and snapshot/delta paths - IndexedDB uses a simple fixed cap for cached rendered pages/content while preserving pending edits **Deferred:** - WebSocket authentication and logout-driven cache clearing move to Milestone 3 application auth - Browser-level automated sync tests and larger load benchmarks move to production hardening --- ### Milestone 3: Authentication & Authorization (Weeks 5-6) **Goal:** Secure access control with passkeys and granular permissions - [x] Passkey (WebAuthn) primary authentication - [x] Password fallback with Argon2id - [x] Session management with opaque server-side sessions - [x] Role-based access control (RBAC) - [x] Scoped API tokens with device-code flow for developer clients - [ ] Content signing with Ed25519 (deferred optional hardening) **Acceptance Criteria:** - [x] Users can register and log in with passkeys on modern browsers - [x] Password fallback works with proper hashing - [x] Sessions expire securely and are revocable - [x] Scoped API tokens and device-code flow support developer clients - [x] Read/write/admin permissions work at route and role level - [ ] Per-document and per-collection permission UI (deferred until collaboration resource modeling) - [x] All auth endpoints rate-limited - [x] Auth events logged - [x] Security implementation review: no plaintext session/token secrets, constant-time password/token comparison **What's Done:** - WebAuthn begin/finish registration and login endpoints - Argon2id password registration/login with first-user admin bootstrap - Opaque session cookies stored as server-side hashes - Scoped bearer API tokens stored as hashes and shown once - First-party device-code flow for CLI/client onboarding - Route middleware enforcing viewer/editor/admin roles plus token scopes - In-memory auth/device-flow rate limiter for self-hosted deployments under 100 users - Go-served login, account, API-token, role-management, and device-approval screens - Password change and account deletion endpoints - Public registration hardening so credentials cannot be attached to existing accounts without a session - Device-code replay hardening so approved codes mint only one API token **What's Next:** - Complete the independent penetration-test checklist during production hardening - Decide how deep per-document/per-collection permissions should go before collaboration features - Add optional multiple-passkey management and session refresh polish if real usage calls for it --- ### Milestone 4: Collaboration Features (Weeks 7-8) **Goal:** Comments, notifications, and conflict resolution - Comment system linked to file versions (by hash) - Email notifications via Postmark adapter - Web-based conflict resolution UI - Notification preferences (per-file, per-folder, global, digest) - Comment threading and email replies **Acceptance Criteria:** - [ ] Users can comment on specific lines/sections of a document - [ ] Comments persist and are linked to document versions - [ ] Email notifications sent for watched file changes - [ ] Replying to notification email creates a comment - [ ] Conflicts display side-by-side diff with resolution actions - [ ] Digest mode batches notifications by time window --- ### Milestone 5: Search & UI Polish (Weeks 9-10) **Goal:** Fast search, design system, and production readiness - Full-text search with SQLite FTS5 - Client-side search index sync - Design system with browser-based CSS editor - Responsive mobile layout - Error boundaries and loading states - Performance benchmarking - Client-side Mermaid and KaTeX rendering **Acceptance Criteria:** - [ ] Search returns results in <50ms on client - [ ] Search works offline after initial sync - [ ] Design system documented at `/design` route - [ ] All screens responsive down to 320px width - [ ] Lighthouse score >90 on all metrics - [ ] Initial page load <100ms (server-rendered HTML) - [x] Mermaid diagrams render client-side - [x] Math blocks render with KaTeX --- ### Milestone 6: Production Hardening (Weeks 11-12) **Goal:** Deploy with confidence - Comprehensive test suite (unit, integration, e2e) - Security audit and penetration testing guide - Backup and restore procedures - Monitoring and health checks - Documentation for operators **Acceptance Criteria:** - [ ] 80% test coverage - [ ] No critical or high-severity security findings - [ ] Backup script exports database + attachments as tar.gz - [ ] Health check endpoint returns status of all dependencies - [ ] Operator docs cover: install, upgrade, backup, security incident response - [ ] Load test: 1000 concurrent readers, 100 concurrent editors --- ## Architecture Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ Client Browser │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ Preact UI │ │ File Sync │ │ Search Index │ │ │ │ (hydrated) │ │ (IndexedDB) │ │ (FTS5) │ │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ WebSocket / HTTP │ ┌─────────────────────────────────────────────────────────────┐ │ Go Application Server │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐ │ │ │ HTTP │ │ WebSocket │ │ Markdown │ │ Auth │ │ │ │ Router │ │ Sync │ │ Renderer │ │ (WebAuthn)│ │ │ └────────────┘ └────────────┘ └────────────┘ └──────────┘ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ Email │ │ Search │ │ File Watch │ │ │ │ (Postmark)│ │ (FTS5) │ │ (fsnotify)│ │ │ └────────────┘ └────────────┘ └────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ┌──────────────────┴──────────────────┐ │ │ ┌──────────────┐ ┌──────────────┐ │ libsql │ │ Content- │ │ (SQLite) │ │ Addressed │ │ │ │ Filesystem │ └──────────────┘ └──────────────┘ ``` See [architecture-overview.md](architecture-overview.md) for detailed component design. --- ## Technology Stack ### Backend (Go 1.24+) | Component | Library | Justification | | ------------- | ------------------------------------------- | ---------------------------------------- | | HTTP Router | `github.com/go-chi/chi` | Minimal, idiomatic, stdlib-compatible | | Database | `github.com/tursodatabase/go-libsql` | Embedded SQLite with replication option | | Migrations | Internal migration runner | Simple, no extra dependency | | Auth/Passkeys | `github.com/go-webauthn/webauthn` | Reference implementation, well-audited | | Password Hash | `golang.org/x/crypto/argon2` | Winner of Password Hashing Competition | | 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 | | Crypto | `crypto/ed25519`, `crypto/sha256` | Standard library, no external deps | | Templates | `html/template` | Stdlib, auto-escaping, SSR-safe | ### Frontend (Preact + TypeScript) | Component | Library | Justification | | --------- | ------------------------------ | --------------------------------------- | | Framework | `preact` (10KB) | React API, tiny bundle, fast hydration | | Routing | `preact-iso` | Lightweight isomorphic routing | | Markdown | `marked` + `micromark` | Server+client compatible | | Search | `flexsearch` | Client-side full-text, zero server load | | Styling | Native CSS + custom properties | No build-time CSS processing needed | | Icons | Inline SVG | No icon font dependency | | Build | `vite` | Fast HMR, modern output, minimal config | ### Infrastructure | Component | Technology | Justification | | ------------- | ------------------ | --------------------------------------------- | | Container | Docker + Compose | Universal deployment target | | Reverse Proxy | Traefik (optional) | Auto-HTTPS, included in compose | | Database | libsql/SQLite | Single file, zero external dependency | | Storage | Local filesystem | Content-addressed, immutable, backup-friendly | --- ## Security Model ### Threats Addressed 1. **Supply Chain Attacks**: Minimal external dependencies; all pinned with go.sum; vendored if needed 2. **Data Tampering**: All document versions SHA-256 hashed; optional Ed25519 signatures 3. **Unauthorized Access**: RBAC with principle of least privilege; content never served without auth check 4. **Session Hijacking**: Signed cookies with HttpOnly, Secure, SameSite=Strict; short expiry with refresh 5. **CSRF**: Double-submit cookie pattern for state-changing operations 6. **XSS**: Go html/template auto-escaping; strict CSP headers; no inline scripts except nonce-tagged 7. **DoS**: Rate limiting on auth endpoints; file upload size limits; query timeouts ### Content Security - Attachment uploads: Magic number validation, extension whitelist, size limits - Markdown rendering: Trusted content may include raw HTML; templates still auto-escape application data - File paths: Canonicalization prevents directory traversal ### Audit & Compliance - Every data modification logged with user, timestamp, IP, and content hash - Immutable history table — updates are inserts - GDPR-compliant: full data export and deletion capability --- ## Performance Targets | Metric | Target | Measurement | | ------------------- | ------------------------- | -------------------------------- | | Initial Page Load | <100ms | TTFB + First Contentful Paint | | Time to Interactive | <200ms | Hydration complete | | Search Query | <50ms | Client-side after initial sync | | File Sync | <5s | From disk save to server persist | | Bundle Size | <100KB | Gzipped JS + CSS | | Concurrent Users | 1000 readers, 100 editors | Load tested | --- ## Monorepo Structure ``` cairnquire/ ├── README.md ├── docker-compose.yml ├── Dockerfile ├── mise.toml ├── docs/ # Project documentation │ ├── project-plan.md # This file │ ├── architecture-overview.md # System architecture │ ├── adrs/ # Architecture Decision Records │ ├── milestones/ # Detailed milestone plans │ └── specs/ # Technical specifications ├── apps/ │ ├── server/ # Go HTTP application │ │ ├── cmd/cairnquire/ │ │ ├── internal/ │ │ │ ├── app/ # Application orchestration │ │ │ ├── config/ # Configuration management │ │ │ ├── database/ # Database & migrations │ │ │ ├── docs/ # Document service & repository │ │ │ ├── httpserver/ # HTTP handlers & templates │ │ │ ├── markdown/ # Markdown rendering pipeline │ │ │ ├── realtime/ # WebSocket hub │ │ │ └── store/ # Content-addressed filesystem │ │ ├── static/ # Static assets │ │ └── templates/ # Go HTML templates │ └── web/ # Preact frontend application │ ├── src/ │ ├── index.html │ └── vite.config.ts ├── content/ # Markdown source files ├── data/ # SQLite database & attachments └── packages/ └── protocol/ # Shared sync protocol spec ``` --- ## Risk Register | Risk | Likelihood | Impact | Mitigation | | -------------------------------- | ---------- | ------ | ----------------------------------------------------------------------------------- | | 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 | | 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 | --- ## Next Steps 1. ✅ Complete Milestone 1: Foundation 2. ✅ Complete Milestone 2: Sync Protocol 3. 🔄 Finish Milestone 3 hardening - Add browser login/account management screens - Complete security review checklist 4. Implement SQLite FTS5 search (Milestone 5) 5. Add Renovate with dependency update cooldown policies --- ## Glossary - **ADR**: Architecture Decision Record - **CRDT**: Conflict-free Replicated Data Type (not used, but considered) - **CSRF**: Cross-Site Request Forgery - **CSP**: Content Security Policy - **FTS5**: SQLite Full-Text Search version 5 - **RBAC**: Role-Based Access Control - **SSR**: Server-Side Rendering - **TTFB**: Time to First Byte - **WebAuthn**: Web Authentication API (passkeys)