Files
Thomas Richter 92e0d5188a docs(01): create phase 1 foundation plans
Phase 01: Foundation
- 2 plans in 2 waves
- Wave 1: Project setup with SvelteKit + Drizzle schema
- Wave 2: Repository layer + verification page
- Ready for execution

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 04:26:48 +01:00

11 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
phase plan type wave depends_on files_modified autonomous must_haves
01-foundation 02 execute 2
01-01
src/lib/server/db/repository.ts
src/hooks.server.ts
src/routes/+page.server.ts
src/routes/+page.svelte
data/.gitkeep
true
truths artifacts key_links
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
path provides exports
src/lib/server/db/repository.ts EntryRepository with typed CRUD operations
entryRepository
EntryRepository
path provides contains
src/hooks.server.ts Server hooks for database initialization handle
path provides
data/.gitkeep Data directory placeholder for git
from to via pattern
src/lib/server/db/repository.ts src/lib/server/db/index.ts import db import.*db.*from
from to via pattern
src/hooks.server.ts src/lib/server/db/index.ts import db for init import.*db
from to via pattern
src/routes/+page.server.ts src/lib/server/db/repository.ts import repository 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.

<execution_context> @/home/tho/.claude/get-shit-done/workflows/execute-plan.md @/home/tho/.claude/get-shit-done/templates/summary.md </execution_context>

@.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:
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<NewEntry, 'id' | 'createdAt' | 'updatedAt'>): Entry;
  getById(id: string): Entry | undefined;
  getAll(options?: { limit?: number; offset?: number }): Entry[];
  update(id: string, updates: Partial<Omit<Entry, 'id' | 'createdAt'>>): Entry | undefined;
  delete(id: string): boolean;
  count(): number;
}

class SQLiteEntryRepository implements EntryRepository {
  create(entry: Omit<NewEntry, 'id' | 'createdAt' | 'updatedAt'>): 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<Omit<Entry, 'id' | 'createdAt'>>): 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:
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:
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
  1. Create src/hooks.server.ts for database initialization:
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);
};
  1. Create src/routes/+page.server.ts for verification data:
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,
  };
};
  1. Update src/routes/+page.svelte to show verification status:
<script lang="ts">
  let { data } = $props();
</script>

<main class="min-h-screen bg-gray-50 p-8">
  <div class="max-w-2xl mx-auto">
    <h1 class="text-3xl font-bold text-gray-900 mb-2">TaskPlanner</h1>
    <p class="text-gray-600 mb-8">Foundation Phase Complete</p>

    <div class="bg-white rounded-lg shadow p-6 mb-6">
      <h2 class="text-lg font-semibold text-gray-800 mb-4">System Status</h2>

      <div class="space-y-3">
        <div class="flex items-center gap-2">
          <span class="w-3 h-3 rounded-full bg-green-500"></span>
          <span class="text-gray-700">Database: {data.dbStatus}</span>
        </div>
        <div class="flex items-center gap-2">
          <span class="w-3 h-3 rounded-full bg-green-500"></span>
          <span class="text-gray-700">Entries in database: {data.entryCount}</span>
        </div>
        <div class="flex items-center gap-2">
          <span class="w-3 h-3 rounded-full bg-green-500"></span>
          <span class="text-gray-700">Repository layer: operational</span>
        </div>
      </div>
    </div>

    {#if data.recentEntries.length > 0}
      <div class="bg-white rounded-lg shadow p-6">
        <h2 class="text-lg font-semibold text-gray-800 mb-4">Recent Entries</h2>
        <ul class="space-y-2">
          {#each data.recentEntries as entry}
            <li class="p-3 bg-gray-50 rounded">
              <div class="font-medium text-gray-900">{entry.title || '(no title)'}</div>
              <div class="text-sm text-gray-600">{entry.content}</div>
              <div class="text-xs text-gray-400 mt-1">
                Type: {entry.type} | Created: {new Date(entry.createdAt).toLocaleString()}
              </div>
            </li>
          {/each}
        </ul>
      </div>
    {/if}
  </div>
</main>
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

<success_criteria>

  • 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 </success_criteria>
After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`