chore: mark US-005 complete in prd.json and update progress log

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Roberto Musso
2026-02-19 16:56:48 +01:00
parent 1794ab0416
commit 14e0a3aca6
2 changed files with 21 additions and 2 deletions

View File

@@ -86,8 +86,8 @@
"Typecheck passes" "Typecheck passes"
], ],
"priority": 5, "priority": 5,
"passes": false, "passes": true,
"notes": "" "notes": "Completed: clients.list (ordered by name), clients.create (UUID + createdAt), clients.update (partial), clients.delete (guard returns error payload if children exist), clients.deleteWithCascade (BFS recursive — nulls orphaned tasks.projectId, deletes projects, then clients). All queries use .all()/.run() for drizzle better-sqlite3 sync driver."
}, },
{ {
"id": "US-006", "id": "US-006",

View File

@@ -3,6 +3,8 @@
- electron-trpc uses `exposeElectronTRPC()` in preload and `createIPCHandler({ router, windows })` in main; renderer uses `ipcLink()` from `electron-trpc/renderer` - electron-trpc uses `exposeElectronTRPC()` in preload and `createIPCHandler({ router, windows })` in main; renderer uses `ipcLink()` from `electron-trpc/renderer`
- appRouter lives at `src/main/router/index.ts`; renderer client at `src/renderer/lib/trpc.ts` - appRouter lives at `src/main/router/index.ts`; renderer client at `src/renderer/lib/trpc.ts`
- `@/*` path alias maps to `src/renderer/*` (configured in tsconfig.json paths) - `@/*` path alias maps to `src/renderer/*` (configured in tsconfig.json paths)
- Drizzle ORM with better-sqlite3 (sync driver): SELECT queries MUST end with `.all()` to execute; INSERT/UPDATE/DELETE MUST end with `.run()`
- `inArray(column, values)` works with nullable columns when values is `string[]` (TypeScript covariance allows string[] → (string | null)[])
- All DB tables use `CREATE TABLE IF NOT EXISTS` for non-destructive migrations - All DB tables use `CREATE TABLE IF NOT EXISTS` for non-destructive migrations
- All IDs are UUIDs generated via `crypto.randomUUID()` - All IDs are UUIDs generated via `crypto.randomUUID()`
- TypeScript strict mode + noUncheckedIndexedAccess enabled; always account for possible undefined on array access - TypeScript strict mode + noUncheckedIndexedAccess enabled; always account for possible undefined on array access
@@ -48,3 +50,20 @@
- ESLint `import/no-unresolved` requires `eslint-import-resolver-typescript` with `alwaysTryTypes: true` to resolve TypeScript path aliases - ESLint `import/no-unresolved` requires `eslint-import-resolver-typescript` with `alwaysTryTypes: true` to resolve TypeScript path aliases
- The `writingMode: 'vertical-rl'` + `transform: 'rotate(180deg)'` CSS pattern creates bottom-to-top text for vertical affordance labels - The `writingMode: 'vertical-rl'` + `transform: 'rotate(180deg)'` CSS pattern creates bottom-to-top text for vertical affordance labels
--- ---
## 2026-02-19 - US-005
- What was implemented:
- Full clients tRPC router replacing stubs in `src/main/router/index.ts`
- Added imports: `eq`, `asc`, `inArray` from `drizzle-orm`; `getDb` from `../db`; `clients`, `projects`, `tasks` from `../db/schema`
- `clients.list`: `db.select().from(clients).orderBy(asc(clients.name)).all()`
- `clients.create`: inserts with `crypto.randomUUID()` + `Date.now()` via `.run()`
- `clients.update`: partial update — only sets fields that are defined in input, skips if no-op
- `clients.delete`: checks for child clients and child projects; returns `{ error: string }` payload if any exist; otherwise deletes and returns `{ success: true }`
- `clients.deleteWithCascade`: BFS loop collects all descendant client IDs, finds their projects, nulls `projectId` on orphaned tasks, deletes projects, then deletes all clients
- Files changed: `src/main/router/index.ts`, `prd.json`, `progress.txt`
- **Learnings for future iterations:**
- Drizzle ORM with better-sqlite3 sync driver: SELECT must call `.all()` to get an array; INSERT/UPDATE/DELETE must call `.run()` to execute — NOT calling these causes TypeScript errors (query builder ≠ result)
- `inArray(nullableColumn, string[])` is TypeScript-safe because `string[]` is assignable to `(string | null)[]` via covariance
- Guard against empty arrays before using `inArray` — while `allClientIds` is never empty (starts with input.id), `projectIds` could be empty; guarded with `if (projectIds.length > 0)` block
- `@typescript-eslint/no-non-null-assertion` is configured as a warning (not error) in this project — `queue.shift()!` is fine after a `length > 0` check
---