Foundation: Drizzle setup + nuke 17 hand-rolled migrations #839

Closed
opened 2026-05-04 20:27:55 +00:00 by claude-desktop · 0 comments
Collaborator

As a maintainer, I want Drizzle wired up alongside bun:sqlite with current schema captured as a single snapshot and all 17 hand-rolled migrations deleted, so that future schema changes are TS-driven and the migration ladder no longer carries dead one-shot data backfills.

Decision context (chat 2026-05-04): repo is pure-dev, no prod, no preservation needed. Wipe-and-reseed is acceptable.

Acceptance criteria

Deps + config

  • drizzle-orm + drizzle-kit added to apps/server/package.json.
  • drizzle.config.ts at apps/server/, dialect sqlite, driver bun:sqlite, output apps/server/src/infrastructure/database/drizzle/.
  • Schema directory apps/server/src/infrastructure/database/schema/ created (one file per aggregate, populated incrementally by later stories).
  • Convention: snake_case TS field names that mirror SQL column names (bridge style — no caller-side renames). Documented in new docs/database.md.

Snapshot generation

  • drizzle-kit generate produces 0000_init.sql capturing every table currently in agents.db.
  • Same for tasks.db0000_init_tasks.sql.
  • Diff check (sqlite3 .schema normalized vs generated SQL) is empty before merge.

Migration runner

  • ensureSchema(db) in db.ts rewritten: if agents table absent → run 0000_init.sql; else assume up-to-date.
  • Future migrations applied via drizzle-kit migrate style — read SQL files from drizzle/, apply in order, track applied set in __drizzle_migrations table.
  • All 17 runXxxMigration files in apps/server/src/infrastructure/database/migrations/ deleted.
  • All runXxxMigration imports + calls in db.ts removed.
  • task-store.ts::ensureSchema rewritten same pattern over tasks.db.

Tooling

  • just db-generate recipe — calls drizzle-kit generate.
  • just db-check recipe — fails CI if schema/ has drifted from generated SQL (no uncommitted migration).
  • CI step in .forgejo/workflows/qa.yml runs just db-check.

Wipe + reseed

  • Local ~/.local/state/claude-hooks/agents.db and tasks.db wiped manually before first boot.
  • Service boots, seedDefaultAgents + ensureDefaultForTypes populate defaults; OAuth re-flows trigger on next webhook.
  • just qa green.

Tests

  • All existing *.test.ts in infrastructure/database/ pass against new ensureSchema.
  • New test: ensureSchema on fresh DB produces schema bit-identical to live agents.db .schema (after normalization).

Out of scope

  • Rewriting any aggregate's CRUD to Drizzle (covered in #2–#10 of this milestone).
  • Splitting db.ts god-file (begins in pilot story).
  • Deleting db.ts itself (final cleanup story).

References

  • Decision: pure-dev, no prod, no preservation — chat 2026-05-04.
  • docs/inheritance-contract.md — Drizzle migrations must respect add-only.
  • apps/server/src/infrastructure/database/db.ts:64-600 — current ensureSchema.
**As a** maintainer, **I want** Drizzle wired up alongside `bun:sqlite` with current schema captured as a single snapshot and all 17 hand-rolled migrations deleted, **so that** future schema changes are TS-driven and the migration ladder no longer carries dead one-shot data backfills. Decision context (chat 2026-05-04): repo is pure-dev, no prod, no preservation needed. Wipe-and-reseed is acceptable. ## Acceptance criteria ### Deps + config - [ ] `drizzle-orm` + `drizzle-kit` added to `apps/server/package.json`. - [ ] `drizzle.config.ts` at `apps/server/`, dialect `sqlite`, driver `bun:sqlite`, output `apps/server/src/infrastructure/database/drizzle/`. - [ ] Schema directory `apps/server/src/infrastructure/database/schema/` created (one file per aggregate, populated incrementally by later stories). - [ ] Convention: **snake_case TS field names** that mirror SQL column names (bridge style — no caller-side renames). Documented in new `docs/database.md`. ### Snapshot generation - [ ] `drizzle-kit generate` produces `0000_init.sql` capturing every table currently in `agents.db`. - [ ] Same for `tasks.db` → `0000_init_tasks.sql`. - [ ] Diff check (`sqlite3 .schema` normalized vs generated SQL) is empty before merge. ### Migration runner - [ ] `ensureSchema(db)` in `db.ts` rewritten: if `agents` table absent → run `0000_init.sql`; else assume up-to-date. - [ ] Future migrations applied via `drizzle-kit migrate` style — read SQL files from `drizzle/`, apply in order, track applied set in `__drizzle_migrations` table. - [ ] All 17 `runXxxMigration` files in `apps/server/src/infrastructure/database/migrations/` deleted. - [ ] All `runXxxMigration` imports + calls in `db.ts` removed. - [ ] `task-store.ts::ensureSchema` rewritten same pattern over `tasks.db`. ### Tooling - [ ] `just db-generate` recipe — calls `drizzle-kit generate`. - [ ] `just db-check` recipe — fails CI if `schema/` has drifted from generated SQL (no uncommitted migration). - [ ] CI step in `.forgejo/workflows/qa.yml` runs `just db-check`. ### Wipe + reseed - [ ] Local `~/.local/state/claude-hooks/agents.db` and `tasks.db` wiped manually before first boot. - [ ] Service boots, `seedDefaultAgents` + `ensureDefaultForTypes` populate defaults; OAuth re-flows trigger on next webhook. - [ ] `just qa` green. ### Tests - [ ] All existing `*.test.ts` in `infrastructure/database/` pass against new `ensureSchema`. - [ ] New test: `ensureSchema` on fresh DB produces schema bit-identical to live `agents.db .schema` (after normalization). ## Out of scope - Rewriting any aggregate's CRUD to Drizzle (covered in #2–#10 of this milestone). - Splitting `db.ts` god-file (begins in pilot story). - Deleting `db.ts` itself (final cleanup story). ## References - Decision: pure-dev, no prod, no preservation — chat 2026-05-04. - `docs/inheritance-contract.md` — Drizzle migrations must respect add-only. - `apps/server/src/infrastructure/database/db.ts:64-600` — current `ensureSchema`.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks#839
No description provided.