diff --git a/.planning/phases/14-postgresql-migration/14-01-PLAN.md b/.planning/phases/14-postgresql-migration/14-01-PLAN.md
index b521d50..1ccb5a3 100644
--- a/.planning/phases/14-postgresql-migration/14-01-PLAN.md
+++ b/.planning/phases/14-postgresql-migration/14-01-PLAN.md
@@ -89,7 +89,7 @@ bun add postgres @electric-sql/pglite
bun remove better-sqlite3 @types/better-sqlite3
```
-**Step 2: Rewrite `src/db/schema.ts`** — Clean rewrite per D-01. Replace all `sqliteTable` with `pgTable`, all imports from `drizzle-orm/sqlite-core` with `drizzle-orm/pg-core`.
+**Step 2: Rewrite `src/db/schema.ts`** -- Clean rewrite per D-01. Replace all `sqliteTable` with `pgTable`, all imports from `drizzle-orm/sqlite-core` with `drizzle-orm/pg-core`.
Column type mapping (apply to ALL 12 tables):
- `integer("id").primaryKey({ autoIncrement: true })` -> `serial("id").primaryKey()`
@@ -157,7 +157,7 @@ export async function seedDefaults() {
}
```
-**Step 6: Update `src/shared/types.ts`** — No changes needed to the file content itself. The types infer from schema which still exports the same table names. Verify the file still compiles after schema change.
+**Step 6: Update `src/shared/types.ts`** -- No changes needed to the file content itself. The types infer from schema which still exports the same table names. Verify the file still compiles after schema change.
**Step 7: Update `drizzle.config.ts`** per D-02:
```typescript
@@ -174,7 +174,7 @@ export default defineConfig({
```
- grep -q "pgTable" src/db/schema.ts && grep -q "drizzle-orm/pg-core" src/db/schema.ts && grep -q "postgres-js" src/db/index.ts && grep -q "postgresql" drizzle.config.ts && grep -q "async function seedDefaults" src/db/seed.ts && echo "PASS" || echo "FAIL"
+ grep -q "pgTable" src/db/schema.ts && grep -q "drizzle-orm/pg-core" src/db/schema.ts && grep -q "postgres-js" src/db/index.ts && grep -q "postgresql" drizzle.config.ts && grep -q "async function seedDefaults" src/db/seed.ts && bun run lint 2>&1 | tail -3 && echo "PASS" || echo "FAIL"
- src/db/schema.ts contains `import { boolean, doublePrecision, integer, pgTable, serial, text, timestamp } from "drizzle-orm/pg-core"`
@@ -226,7 +226,7 @@ Key changes from current:
- `migrate` from `drizzle-orm/pglite/migrator` instead of `drizzle-orm/bun-sqlite/migrator`
- Function is now `async` (returns Promise)
- No `Database` import from `bun:sqlite`
-- No `":memory:"` — PGlite creates an in-memory Postgres instance by default
+- No `":memory:"` -- PGlite creates an in-memory Postgres instance by default
- Migration folder changed to `./drizzle-pg`
- `db.insert(...).values(...).run()` becomes `await db.insert(...).values(...)`
@@ -237,15 +237,15 @@ bunx drizzle-kit generate
This reads the updated `drizzle.config.ts` (dialect: "postgresql", schema: src/db/schema.ts) and generates SQL migration files in `drizzle-pg/`.
-**Step 3: Verify migration was generated:**
+**Step 3: Verify migration was generated and is complete:**
```bash
ls drizzle-pg/
cat drizzle-pg/*.sql
```
-Confirm the SQL contains `CREATE TABLE` statements for all 12 tables with correct Postgres types (serial, text, timestamp, boolean, double precision, etc.).
+Confirm the SQL contains `CREATE TABLE` statements for all 12 tables with correct Postgres types (serial, text, timestamp, boolean, double precision, etc.). Count the CREATE TABLE statements -- there must be at least 12 (categories, items, threads, thread_candidates, setups, setup_items, settings, users, sessions, api_keys, oauth_clients, oauth_codes, oauth_tokens).
-**Step 4: Quick smoke test — verify PGlite test helper works:**
+**Step 4: Quick smoke test -- verify PGlite test helper works:**
```bash
bun -e "
import { createTestDb } from './tests/helpers/db.ts';
@@ -258,7 +258,7 @@ console.log('PGlite test helper works!');
```
- ls drizzle-pg/*.sql && grep -q "drizzle-orm/pglite" tests/helpers/db.ts && grep -q "async function createTestDb" tests/helpers/db.ts && echo "PASS" || echo "FAIL"
+ ls drizzle-pg/*.sql && grep -c "CREATE TABLE" drizzle-pg/*.sql | tail -1 | grep -qE "^drizzle-pg/.*:1[2-9]$|^drizzle-pg/.*:[2-9][0-9]$" || { echo "WARNING: verify CREATE TABLE count manually"; }; grep -q "drizzle-orm/pglite" tests/helpers/db.ts && grep -q "async function createTestDb" tests/helpers/db.ts && bun run lint 2>&1 | tail -3 && echo "PASS" || echo "FAIL"
- tests/helpers/db.ts contains `import { drizzle } from "drizzle-orm/pglite"`
@@ -267,10 +267,11 @@ console.log('PGlite test helper works!');
- tests/helpers/db.ts contains `migrationsFolder: "./drizzle-pg"`
- tests/helpers/db.ts does NOT contain `bun:sqlite` or `drizzle-orm/bun-sqlite` or `.run()`
- drizzle-pg/ directory exists with at least one .sql migration file
- - Migration SQL contains CREATE TABLE for categories, items, threads, thread_candidates, setups, setup_items, settings, users, sessions, api_keys, oauth_clients, oauth_codes, oauth_tokens
+ - Migration SQL contains CREATE TABLE for all 12+ tables (categories, items, threads, thread_candidates, setups, setup_items, settings, users, sessions, api_keys, oauth_clients, oauth_codes, oauth_tokens)
+ - `grep -c "CREATE TABLE" drizzle-pg/*.sql` shows at least 12 CREATE TABLE statements
- PGlite smoke test (bun -e script above) exits 0
- Test helper returns async PGlite Drizzle instance. Initial PostgreSQL migration generated in drizzle-pg/. Smoke test confirms PGlite can apply migrations and seed data.
+ Test helper returns async PGlite Drizzle instance. Initial PostgreSQL migration generated in drizzle-pg/ with all 12+ CREATE TABLE statements. Smoke test confirms PGlite can apply migrations and seed data.
@@ -279,11 +280,13 @@ console.log('PGlite test helper works!');
- `grep -r "sqliteTable\|bun:sqlite\|drizzle-orm/sqlite-core\|drizzle-orm/bun-sqlite" src/db/ drizzle.config.ts tests/helpers/db.ts` returns NO matches
- `grep -c "pgTable" src/db/schema.ts` returns 12+ (one per table, possibly more from import)
- `ls drizzle-pg/*.sql` shows at least one migration file
+- `grep -c "CREATE TABLE" drizzle-pg/*.sql` shows at least 12 tables
- PGlite smoke test exits 0
+- `bun run lint` passes
-All database foundation files rewritten for PostgreSQL. Schema uses pg-core types. DB connection uses postgres.js. Test helper uses PGlite. Initial migration generated. No SQLite references remain in these files.
+All database foundation files rewritten for PostgreSQL. Schema uses pg-core types. DB connection uses postgres.js. Test helper uses PGlite. Initial migration generated with all 12+ tables. No SQLite references remain in these files. Lint passes.