diff --git a/.dockerignore b/.dockerignore index 91f473d..9d8699b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,9 +4,5 @@ data tmp -**/node_modules -**/dist -**/.vite - coverage *.log diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..72024e1 --- /dev/null +++ b/.env.example @@ -0,0 +1,11 @@ +# Required for deployed passkeys and device authorization URLs. +CAIRNQUIRE_PUBLIC_ORIGIN=https://cairnquire.example.com + +# Optional SMTP settings. The bundled Compose file defaults to its local +# Mailpit service so notifications can be inspected during initial deployment. +CAIRNQUIRE_EMAIL_SMTP_HOST=mailpit +CAIRNQUIRE_EMAIL_SMTP_PORT=1025 +CAIRNQUIRE_EMAIL_FROM=notifications@cairnquire.local + +# Optional: INFO, DEBUG, WARN, or ERROR. +CAIRNQUIRE_LOG_LEVEL=INFO diff --git a/.gitignore b/.gitignore index 3c111d1..1ac0d6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,7 @@ data/ tmp/ -node_modules/ -dist/ coverage/ +.env .DS_Store *.log -apps/web/node_modules/ -apps/web/dist/ apps/server/bin/ - diff --git a/.project/README.md b/.project/README.md index c1c03c8..ee73aac 100644 --- a/.project/README.md +++ b/.project/README.md @@ -11,9 +11,9 @@ | Document | Decision | |----------|----------| -| [ADR-001: Tech Stack](adrs/adr-001-tech-stack.md) | Go backend + Preact frontend | +| [ADR-001: Tech Stack](adrs/adr-001-tech-stack.md) | Go server with embedded web assets | | [ADR-002: Sync Protocol](adrs/adr-002-sync-protocol.md) | SimpleSync content-addressed protocol | -| [ADR-003: SSR Strategy](adrs/adr-003-ssr-strategy.md) | Go templates with Preact hydration | +| [ADR-003: SSR Strategy](adrs/adr-003-ssr-strategy.md) | Go templates with embedded browser scripts | | [ADR-004: Auth Strategy](adrs/adr-004-auth-strategy.md) | Passkeys primary, passwords fallback | | [ADR-005: Storage Strategy](adrs/adr-005-storage-strategy.md) | libsql + content-addressed filesystem | | [ADR-006: Email Strategy](adrs/adr-006-email-strategy.md) | Postmark gateway, plain-text only | @@ -84,8 +84,7 @@ cairnquire/ │ ├── security-specification.md │ └── deployment-guide.md ├── apps/ -│ ├── server/ # Go application -│ └── web/ # Preact frontend +│ └── server/ # Go application, templates, and static assets ├── packages/ │ └── protocol/ # Shared types ├── docker-compose.yml diff --git a/.project/adrs/adr-001-tech-stack.md b/.project/adrs/adr-001-tech-stack.md index 02a889d..5cbc2c7 100644 --- a/.project/adrs/adr-001-tech-stack.md +++ b/.project/adrs/adr-001-tech-stack.md @@ -1,53 +1,54 @@ -# ADR-001: Go Backend with Preact Frontend +# ADR-001: Go Server with Embedded Web Assets ## Status Accepted ## Context -We need to choose a backend language/framework and frontend technology for a documentation platform with these requirements: -- Ultra-fast performance -- Minimal external dependencies -- No vendor lock-in -- Battle-tested security -- Server-side rendering for non-interactive pages -- Offline-capable web client +We need a documentation platform with fast page delivery, minimal external +dependencies, secure server-side rendering, and a straightforward deployment +artifact. ## Decision -**Backend**: Go 1.22+ with standard library plus minimal, well-audited packages -**Frontend**: Preact 10 with TypeScript, Vite build system +Use Go 1.24+ with the standard library plus minimal, audited packages. The Go +binary serves HTML templates and embeds its CSS, images, and small browser +scripts. There is no separate SPA, Node dependency tree, or frontend build +pipeline. + +Browser scripts progressively add editing, offline caching, WebSocket updates, +comments, and authentication interactions to server-rendered pages. ## Consequences ### Positive -- Go's standard library is comprehensive and security-audited -- Single static binary deployment — no runtime dependencies -- Preact is 10KB (vs 40KB+ React) with identical API -- Go's `html/template` provides safe SSR with auto-escaping -- TypeScript gives type safety without runtime overhead -- Both ecosystems have excellent supply-chain security (Go modules with checksums, npm audit) +- One application binary and one build toolchain +- Go `html/template` provides auto-escaped server rendering +- Embedded assets deploy with the server binary +- Fewer supply-chain dependencies and fewer moving parts in CI +- Pages remain readable before browser scripts execute ### Negative -- Go template syntax is less expressive than JSX -- WebSocket sync logic must be implemented manually (no framework like Socket.io) -- Preact ecosystem smaller than React (mitigated by using mostly native APIs) +- Template syntax is less expressive than JSX +- Browser behavior uses small framework-free modules +- WebSocket and offline behavior must be maintained directly ## Alternatives Considered +### Separate Preact SPA +- **Pros**: Component model, client-side routing, TypeScript ecosystem +- **Cons**: Adds Node tooling, package dependencies, a second build pipeline, + and duplicate UI surfaces +- **Rejected**: The Go-served UI already covers the application surface + ### Rust + Axum - **Pros**: Memory safety guarantees, excellent performance -- **Cons**: Longer compile times, smaller talent pool, steeper learning curve for team -- **Rejected**: Go's pragmatic balance of safety and velocity better fits project timeline - -### Deno Fresh -- **Pros**: Island architecture, native TypeScript, no build step -- **Cons**: Newer ecosystem, fewer audited libraries, Deno runtime less battle-tested than Go -- **Rejected**: Go's maturity and deployment simplicity preferred +- **Cons**: Longer compile times and steeper learning curve +- **Rejected**: Go better fits the project deployment model ### Next.js / React Server Components - **Pros**: Mature ecosystem, built-in SSR -- **Cons**: Heavy bundle size, complex build system, RSC lock-in, many dependencies -- **Rejected**: Violates "minimal dependencies" and "no vendor lock-in" principles +- **Cons**: Heavy build system and more runtime complexity +- **Rejected**: Violates the minimal dependency goal ## References - Go Security Policy: https://go.dev/security -- Preact Size Comparison: https://bundlephobia.com/package/preact@10.19.3 +- Go `html/template`: https://pkg.go.dev/html/template diff --git a/.project/adrs/adr-003-ssr-strategy.md b/.project/adrs/adr-003-ssr-strategy.md index fa9c6e5..cd0fcea 100644 --- a/.project/adrs/adr-003-ssr-strategy.md +++ b/.project/adrs/adr-003-ssr-strategy.md @@ -1,67 +1,55 @@ -# ADR-003: SSR Strategy - Go Templates with Preact Hydration +# ADR-003: SSR Strategy - Go Templates with Embedded Browser Scripts ## Status Accepted ## Context -The application needs to serve document pages that are readable without JavaScript (for performance and accessibility), while providing rich interactivity (comments, editing, search) when JavaScript is available. We need a server-side rendering strategy that works with our Go backend and Preact frontend. +Document pages must be readable quickly and safely while still supporting +editing, authentication, comments, offline caching, and real-time updates. ## Decision -**Strategy C**: Go's `html/template` renders initial HTML for all pages. Preact hydrates interactive components on the client. +Go `html/template` renders complete HTML pages. The server embeds and serves +small framework-free browser scripts for progressive enhancement. ### Implementation Details 1. **Server Rendering**: - - Go handlers query database for document content - - Markdown parsed to HTML server-side (Goldmark) - - `html/template` renders full page with document HTML embedded - - No JavaScript required for reading + - Go handlers query document and account data + - Goldmark parses Markdown to HTML server-side + - `html/template` renders complete pages + - Pages are readable before JavaScript executes -2. **Client Hydration**: - - Preact components mount into designated DOM containers - - Comments, search, editor are Preact islands - - Static content remains server-rendered HTML - - `preact-iso` handles client-side navigation between pages - -3. **Data Passing**: - - Initial state embedded as JSON in ` - -
- - -