System Architecture

Components

API Server (cmd/api/)

HTTP server built with Gin. Handles all client requests:
LayerPackageResponsibility
Handlershttpapi/handlers/Request parsing, validation, response formatting
Middlewarehttpapi/middleware/Auth, rate limiting, timeouts, logging, panic recovery
Authauth/JWT minting/validation, refresh token rotation, OAuth verification
Syncsyncstore/Delta sync with cursor-based pagination and tombstones
URLurlcanon/URL normalization (strip tracking, lowercase domain)
Searchvia handlersHybrid search using FTS + trigram + pgvector
Real-timerealtime/WebSocket hub, Postgres LISTEN integration

Enrichment Worker (cmd/worker/)

Background process that picks up pending enrichment jobs and runs the AI pipeline:
  1. Poll for pending jobs in the database
  2. Fetch page content (platform-aware: YouTube, TikTok, X, etc.)
  3. Run AI enrichment (Gemini) or heuristic fallback
  4. Write results back to the bookmark record
  5. Cache results globally by normalized URL

PostgreSQL

Single Postgres 16 instance with extensions:
ExtensionPurpose
pgvectorSemantic search via vector embeddings
pg_trgmFuzzy text matching (trigram similarity)
Built-in FTSFull-text search with stemming and ranking

Migration Tool (cmd/migrate/)

Database migrations via Goose v3. SQL migration files in migrations/.

Data Model

Design Principles

Offline-First

Clients save locally first, sync when connected. Delta sync with cursors ensures no data is lost.

Server-Authoritative Enrichment

AI-generated fields (summary, tags, saveWhy) are always set by the server. Clients never write these fields.

Last-Write-Wins

Conflict resolution is simple: the server stamps updated_at = now() on every write. Most recent write wins.

Soft Deletes

All deletes are soft (tombstones). Required for delta sync — clients need to know what was deleted.

Request Lifecycle

Every API request flows through:
  1. OpenTelemetry — trace propagation
  2. Request ID — unique ID for tracing (X-Request-Id header)
  3. Access Log — structured JSON logging
  4. Panic Recovery — catches panics, returns 500 JSON error
  5. Timeout — 30-second deadline for all v1 endpoints
  6. Rate Limit — IP-based for auth endpoints (2 req/s burst 10)
  7. Auth — JWT validation, user context injection
  8. Handler — business logic