--- phase: 01-foundation plan: 02 type: execute wave: 2 depends_on: ["01-01"] files_modified: - src/lib/server/db/repository.ts - src/hooks.server.ts - src/routes/+page.server.ts - src/routes/+page.svelte - data/.gitkeep autonomous: true must_haves: truths: - "Repository provides create, read, update, delete operations for entries" - "Database initializes automatically on first server request" - "Data directory structure exists with .gitkeep" - "Basic page shows database connection status" artifacts: - path: "src/lib/server/db/repository.ts" provides: "EntryRepository with typed CRUD operations" exports: ["entryRepository", "EntryRepository"] - path: "src/hooks.server.ts" provides: "Server hooks for database initialization" contains: "handle" - path: "data/.gitkeep" provides: "Data directory placeholder for git" key_links: - from: "src/lib/server/db/repository.ts" to: "src/lib/server/db/index.ts" via: "import db" pattern: "import.*db.*from" - from: "src/hooks.server.ts" to: "src/lib/server/db/index.ts" via: "import db for init" pattern: "import.*db" - from: "src/routes/+page.server.ts" to: "src/lib/server/db/repository.ts" via: "import repository" pattern: "import.*repository" --- Create the repository layer for typed CRUD operations and wire up database initialization with a verification page. Purpose: Provides the data access layer that all future features will use, and verifies the foundation works end-to-end. Output: Working repository with CRUD operations, auto-initializing database, and a verification page proving everything connects. @/home/tho/.claude/get-shit-done/workflows/execute-plan.md @/home/tho/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/01-foundation/01-01-SUMMARY.md @src/lib/server/db/schema.ts @src/lib/server/db/index.ts Task 1: Create EntryRepository with typed CRUD operations src/lib/server/db/repository.ts Create `src/lib/server/db/repository.ts` implementing the repository pattern: ```typescript import { eq, desc } from 'drizzle-orm'; import { db } from './index'; import { entries, type Entry, type NewEntry } from './schema'; import { nanoid } from 'nanoid'; export interface EntryRepository { create(entry: Omit): Entry; getById(id: string): Entry | undefined; getAll(options?: { limit?: number; offset?: number }): Entry[]; update(id: string, updates: Partial>): Entry | undefined; delete(id: string): boolean; count(): number; } class SQLiteEntryRepository implements EntryRepository { create(entry: Omit): Entry { const now = new Date().toISOString(); const newEntry: NewEntry = { ...entry, id: nanoid(), createdAt: now, updatedAt: now, }; db.insert(entries).values(newEntry).run(); return this.getById(newEntry.id)!; } getById(id: string): Entry | undefined { return db.select().from(entries).where(eq(entries.id, id)).get(); } getAll(options: { limit?: number; offset?: number } = {}): Entry[] { const { limit = 100, offset = 0 } = options; return db .select() .from(entries) .orderBy(desc(entries.createdAt)) .limit(limit) .offset(offset) .all(); } update(id: string, updates: Partial>): Entry | undefined { const existing = this.getById(id); if (!existing) return undefined; db.update(entries) .set({ ...updates, updatedAt: new Date().toISOString(), }) .where(eq(entries.id, id)) .run(); return this.getById(id); } delete(id: string): boolean { const existing = this.getById(id); if (!existing) return false; db.delete(entries).where(eq(entries.id, id)).run(); return true; } count(): number { const result = db.select().from(entries).all(); return result.length; } } // Singleton instance export const entryRepository: EntryRepository = new SQLiteEntryRepository(); ``` This provides: - Type-safe CRUD operations using Drizzle ORM - Automatic ID generation with nanoid - Automatic timestamp management (createdAt, updatedAt) - Pagination support via limit/offset - Singleton pattern for consistent access Create a quick test by importing the repository: ```typescript import { entryRepository } from './repository'; const entry = entryRepository.create({ content: 'Test', type: 'thought' }); console.log(entry); // Should have id, createdAt, updatedAt const retrieved = entryRepository.getById(entry.id); console.log(retrieved); // Should match entry entryRepository.delete(entry.id); ``` TypeScript compilation should pass with `npm run check`. EntryRepository interface and implementation exist with create, getById, getAll, update, delete, count methods. All methods are type-safe with Drizzle schema types. Task 2: Create data directory, server hooks, and verification page data/.gitkeep data/attachments/.gitkeep src/hooks.server.ts src/routes/+page.server.ts src/routes/+page.svelte 1. Create data directory structure for persistence: ```bash mkdir -p data/attachments touch data/.gitkeep touch data/attachments/.gitkeep ``` Add to `.gitignore`: ``` # Data directory (persistent data) data/*.db data/*.db-wal data/*.db-shm data/attachments/* !data/.gitkeep !data/attachments/.gitkeep ``` 2. Create `src/hooks.server.ts` for database initialization: ```typescript import type { Handle } from '@sveltejs/kit'; import { db } from '$lib/server/db'; import { entries } from '$lib/server/db/schema'; import { sql } from 'drizzle-orm'; // Ensure database tables exist on first request let initialized = false; export const handle: Handle = async ({ event, resolve }) => { if (!initialized) { // Run a simple query to ensure connection works // Drizzle with push handles schema creation, but this verifies connectivity try { db.select().from(entries).limit(1).all(); initialized = true; console.log('Database initialized successfully'); } catch (error) { console.error('Database initialization failed:', error); // Don't block - let the error propagate to the request } } return resolve(event); }; ``` 3. Create `src/routes/+page.server.ts` for verification data: ```typescript import type { PageServerLoad } from './$types'; import { entryRepository } from '$lib/server/db/repository'; export const load: PageServerLoad = async () => { const count = entryRepository.count(); // Create a test entry if none exist (for verification) let testEntry = null; if (count === 0) { testEntry = entryRepository.create({ title: 'Foundation Test', content: 'This entry was created to verify the foundation is working.', type: 'thought', }); } const entries = entryRepository.getAll({ limit: 5 }); return { dbStatus: 'connected', entryCount: testEntry ? count + 1 : count, recentEntries: entries, }; }; ``` 4. Update `src/routes/+page.svelte` to show verification status: ```svelte

TaskPlanner

Foundation Phase Complete

System Status

Database: {data.dbStatus}
Entries in database: {data.entryCount}
Repository layer: operational
{#if data.recentEntries.length > 0}

Recent Entries

    {#each data.recentEntries as entry}
  • {entry.title || '(no title)'}
    {entry.content}
    Type: {entry.type} | Created: {new Date(entry.createdAt).toLocaleString()}
  • {/each}
{/if}
```
1. `ls data/` - should show .gitkeep and attachments/ 2. `npm run dev` - server starts without errors 3. Visit http://localhost:5173 - page shows: - "Database: connected" - "Entries in database: 1" (or more) - "Repository layer: operational" - The test entry displayed in "Recent Entries" 4. Check `data/taskplaner.db` exists 5. Run `npm run check` - no TypeScript errors Data directory structure created with .gitkeep files. Server hooks initialize database on first request. Verification page displays database status and entry count. Full end-to-end data flow works: hooks -> repository -> page.
1. Repository CRUD operations work (create, read, update, delete) 2. Database auto-initializes on first server request 3. Data directory exists with attachments subdirectory 4. Verification page shows green status for all systems 5. Test entry appears in recent entries list 6. `npm run check` passes 7. `npm run dev` serves the page without errors - EntryRepository provides typed create, getById, getAll, update, delete, count operations - Database initializes automatically via server hooks - Data directory structure exists (data/, data/attachments/) - Verification page confirms database connected, entry count, repository operational - Test entry created and displayed proving end-to-end data flow After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`