Reference

Architecture Overview

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
  • (Store interface in types.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/webassetsgo:embed for 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/sqlite and WAL.
  • Foreign keys on; busy_timeout=5000.
  • Single writer discipline: db.SetMaxOpenConns(1).
  • Transactions stay short. Outbox events rows 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 lives behind the same store layer as SQLite. API handlers call store
  • methods and do not embed dialect-specific SQL.

#Cross-cutting docs