Add Mosaic's own backlog-of-record on the existing Postgres storage layer,
replacing the former Hermes adapter (no Hermes dependency) and the earlier
sqlite idea (no sqlite, no new client).
- packages/db: `backlog` table (drizzle) + enum + migration 0011; BacklogService
taking a Db handle so it runs on both createDb (server PG) and createPgliteDb
(embedded). Atomic claim via SELECT ... FOR UPDATE SKIP LOCKED inside one tx,
TTL claims + reclaim of expired, deps DAG gate, idempotency-key dedup, stats.
- packages/mosaic: `mosaic fleet backlog <sub> --json` (create/list/claim/
reclaim/link/stats/block/complete). Embedded PGlite default at
<mosaicHome>/fleet/backlog; full Postgres via DATABASE_URL — same code.
Migrations run on first use.
- install.sh: preserve fleet/backlog across `mosaic update`.
- docs/fleet/backlog-conventions.md: schema, phase convention, atomic-claim +
TTL semantics, PGlite-default/Postgres-by-config, Mosaic-native (no Hermes).
- Tests (in-memory PGlite, real PG semantics): create/list, exactly-one-winner
concurrency (and N-card no-double-claim), deps gate, reclaim of expired, stats.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The migration file 0001_cynical_ultimatum.sql existed on disk but was not
registered in the Drizzle journal (_journal.json). This caused fresh-database
migrations (CI) to skip creating tables (agent_logs, insights, preferences,
skills, summarization_jobs), then 0002_nebulous_mimic.sql would fail trying
to ALTER the non-existent preferences table.
Fix: insert cynical_ultimatum at idx 1 in the journal and shift all
subsequent entries (idx 2-7).
Verified: pnpm test passes (347 tests, 35 tasks).
- DB client: configure connection pool (max=20, idle_timeout=30s, connect_timeout=5s)
- DB schema: add missing indexes for auth sessions, accounts, conversations, agent_logs
- DB schema: promote preferences(user_id,key) to UNIQUE index for ON CONFLICT upsert
- Drizzle migration: 0003_p8003_perf_indexes.sql
- preferences.service: replace 2-query SELECT+INSERT/UPDATE with single-round-trip upsert
- conversations repo: add ORDER BY + LIMIT to findAll (200) and findMessages (500)
- session-gc.service: make onModuleInit fire-and-forget (removes cold-start TTFB block)
- next.config.ts: enable compress, productionBrowserSourceMaps:false, image avif/webp
- docs/PERFORMANCE.md: full profiling report and change impact notes