2.2 KiB
2.2 KiB
| read_when | ||
|---|---|---|
|
Architecture Overview
ClickClack ships as one Go binary serving a Svelte SPA, JSON API, websocket endpoint, embedded SQLite migrations, local SQLite data, and local upload files.
Durable state lives in SQLite. WebSockets are an update pipe only; clients
recover missed durable events through GET /api/realtime/events?after_cursor=...
or by reconnecting the websocket with a cursor.
Layers
apps/api/cmd/clickclack— CLI and single-binary entrypoint. See ../cli.md.apps/api/internal/httpapi— chi router, auth resolution, REST/WS handlers, SPA serving.apps/api/internal/store— backend-facing store contract and domain types (Storeinterface intypes.go).apps/api/internal/store/sqlite— SQLite implementation, embedded SQL migrations, search/FTS, backup, JSON export.apps/api/internal/realtime— in-process workspace event hub (Hub).apps/api/internal/config— flag/env/file resolution.apps/api/internal/webassets—go:embedfor the built SPA.apps/web— Svelte 5 SPA, API-only client behavior.packages/protocol— OpenAPI contract, source of truth.packages/sdk-ts— generated OpenAPI types plus framework-neutral TypeScript wrapper.
Storage rules
- SQLite uses
modernc.org/sqliteand WAL. - Foreign keys on;
busy_timeout=5000. - Single writer discipline:
db.SetMaxOpenConns(1). - Transactions stay short. Outbox
eventsrows are inserted in the same commit as the durable write that produced them, so subscribers can't see a message that isn't in the DB. - IDs are sortable ULID text with semantic prefixes (see ../data-model.md).
- Postgres should be added behind the store layer without changing API handlers.
Cross-cutting docs
- ../api/overview.md — REST + WS surface.
- ../data-model.md — tables, IDs, invariants.
- ../features/realtime.md — durable vs ephemeral events, cursor recovery.
- ../features/auth.md — auth resolution and precedence.