docs(01): create phase 1 plan — 5 plans across 4 waves

This commit is contained in:
2026-03-29 10:55:52 +02:00
parent 70c73f404c
commit 9624323c9b
6 changed files with 1960 additions and 2 deletions
@@ -0,0 +1,384 @@
---
phase: 01-grundger-st-tippmechanik
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- package.json
- tsconfig.json
- vite.config.ts
- biome.json
- index.html
- .gitignore
- src/main.ts
- src/types.ts
- src/storage/db.ts
- src/styles/main.css
- public/config.example.json
autonomous: true
requirements:
- FNDN-01
- FNDN-02
- FNDN-03
- FNDN-04
- PLSH-06
must_haves:
truths:
- "npm run dev startet Vite auf 0.0.0.0:5173 ohne Fehler"
- "Alle Verzeichnisse aus Spec Abschnitt 13 existieren"
- "TypeScript-Interfaces sind exportiert und typisiert"
- "IndexedDB oeffnet mit 5 Stores und schliesst nicht bei reload"
- "CSS Custom Properties fuer alle Farben und Fonts sind definiert"
artifacts:
- path: "package.json"
provides: "Project dependencies and scripts"
contains: "vite"
- path: "src/types.ts"
provides: "All shared TypeScript interfaces"
exports: ["Progress", "ForestElement", "CompanionAssets", "Level", "Settings", "StyleReference"]
- path: "src/storage/db.ts"
provides: "IndexedDB wrapper with 5 stores"
exports: ["openDB", "getProgress", "saveProgress", "getSettings", "saveSettings"]
- path: "src/styles/main.css"
provides: "CSS palette and typography"
contains: "--bg-cream"
key_links:
- from: "src/storage/db.ts"
to: "src/types.ts"
via: "imports Progress, Settings, ForestElement etc."
pattern: "import.*from.*types"
- from: "src/main.ts"
to: "src/storage/db.ts"
via: "initializes DB on app start"
pattern: "openDB"
---
<objective>
Scaffold the complete Vite project, define all TypeScript interfaces, create the IndexedDB wrapper, and establish the CSS design system.
Purpose: Every subsequent plan depends on the project existing, types being defined, storage being available, and styles being set.
Output: A runnable Vite dev server with types, IndexedDB, and CSS custom properties — no visible UI yet beyond a blank styled page.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-grundger-st-tippmechanik/01-CONTEXT.md
@SPEC.md (sections 6.2, 6.3, 7.2, 13)
</context>
<tasks>
<task type="auto">
<name>Task 1: Vite project scaffold + project structure + CSS design system</name>
<files>
package.json, tsconfig.json, vite.config.ts, biome.json, index.html,
.gitignore, src/main.ts, src/styles/main.css, public/config.example.json
</files>
<read_first>
SPEC.md (section 13 for project structure, section 6.2 for tech stack, section 7.2 for CSS palette)
.planning/phases/01-grundger-st-tippmechanik/01-CONTEXT.md
</read_first>
<action>
1. Initialize Vite project with vanilla-ts template:
`npm create vite@latest . -- --template vanilla-ts` (or manually create files if directory not empty).
2. Install dependencies:
- `npm install` (vite, typescript)
- `npm install -D vitest @biomejs/biome`
3. Configure vite.config.ts (per D-01, spec section 0):
```typescript
import { defineConfig } from 'vite'
export default defineConfig({
server: { host: '0.0.0.0', port: 5173 },
preview: { host: '0.0.0.0', port: 4173 }
})
```
4. Configure tsconfig.json: `"strict": true`, target ES2020, module ESNext, moduleResolution bundler.
5. Configure biome.json: enable formatter and linter, indent with tabs, line width 100.
6. Configure package.json scripts:
```json
{
"dev": "vite --host",
"build": "tsc && vite build",
"preview": "vite preview --host --port 4173",
"test": "vitest run",
"test:watch": "vitest",
"lint": "biome check .",
"lint:fix": "biome check --write ."
}
```
7. Create .gitignore with: node_modules, dist, public/config.json, *.local
8. Create ALL directories from spec section 13:
- src/game/, src/forest/, src/companion/, src/api/, src/storage/, src/ui/, src/styles/
- src/assets/companions/fee-lila/, src/assets/companions/einhorn-stella/,
src/assets/companions/fuchs-finn/, src/assets/companions/eule-elsa/
- src/assets/style-reference/, src/assets/fallback-images/
- scripts/
- public/
Place empty .gitkeep in asset directories that have no files yet.
9. Create public/config.example.json:
```json
{
"geminiApiKey": "YOUR_API_KEY_HERE",
"geminiModel": "gemini-2.5-flash",
"imageModel": "gemini-3.1-flash-image-preview"
}
```
10. Create index.html with:
- DOCTYPE html, lang="de"
- Google Fonts link: Quicksand (400, 600, 700) + Nunito (400, 600)
- Link to src/styles/main.css (via Vite)
- 5 screen sections per D-01: `<section id="screen-welcome" class="screen">`,
`<section id="screen-forest" class="screen">`,
`<section id="screen-lesson" class="screen">`,
`<section id="screen-reward" class="screen">`,
`<section id="screen-parent" class="screen">`
- Only screen-welcome gets class `screen--active` initially
- `<script type="module" src="/src/main.ts"></script>`
11. Create src/styles/main.css with ALL CSS custom properties from spec section 7.2:
```css
:root {
--bg-cream: #FFF8F0;
--bg-forest: #E8F5E4;
--text-dark: #3D3225;
--text-warm: #5C4A3A;
--text-light: #8B7D6B;
--accent-green: #6DB87D;
--accent-gold: #E8B84B;
--accent-pink: #E88BAE;
--accent-purple: #9B7DC4;
--accent-blue: #7DB8D4;
--finger-l-pinky: #E8B4C8;
--finger-l-ring: #C4A8D4;
--finger-l-mid: #A8C4E0;
--finger-l-index: #A8D8B8;
--finger-r-index: #D4D8A8;
--finger-r-mid: #E0C4A8;
--finger-r-ring: #D4A8A8;
--finger-r-pinky: #C8B4E8;
--finger-thumb: #D4CFC8;
}
```
Body: font-family 'Nunito', sans-serif; background var(--bg-cream); color var(--text-dark); min font-size 16px; margin 0; padding 0.
Headings (h1h3): font-family 'Quicksand', sans-serif.
Screen base: `.screen { display: none; opacity: 0; transition: opacity 0.3s ease; }` and `.screen--active { display: flex; flex-direction: column; align-items: center; opacity: 1; min-height: 100vh; }`.
12. Create src/main.ts as minimal entry: import './styles/main.css', console.log('Zauberwald loaded').
</action>
<verify>
<automated>cd /home/dev/workspace/zauberwald && npm run dev -- --strictPort 2>&1 &amp; sleep 3 && curl -s http://localhost:5173 | grep -q "Zauberwald" || curl -s http://localhost:5173 | grep -q "screen-welcome" && kill %1 && echo "PASS"</automated>
</verify>
<acceptance_criteria>
- package.json contains "vite" in devDependencies and scripts "dev", "build", "preview", "test", "lint"
- vite.config.ts contains `host: '0.0.0.0'` and `port: 5173`
- tsconfig.json contains `"strict": true`
- biome.json exists and contains `"formatter"` and `"linter"`
- .gitignore contains `public/config.json` and `node_modules`
- index.html contains 5 `<section` tags with ids screen-welcome, screen-forest, screen-lesson, screen-reward, screen-parent
- index.html contains `class="screen screen--active"` on screen-welcome
- src/styles/main.css contains `--bg-cream: #FFF8F0` and `--finger-l-pinky: #E8B4C8` and `--finger-thumb: #D4CFC8`
- src/styles/main.css contains `font-family:` with `Quicksand` and `Nunito`
- Directories exist: src/game, src/forest, src/companion, src/api, src/storage, src/ui, src/assets/companions
- public/config.example.json contains `geminiApiKey` and `geminiModel`
- `npm run dev` starts without errors
</acceptance_criteria>
<done>Vite project runs, all directories exist per spec section 13, CSS custom properties match spec section 7.2, index.html has 5 screen sections</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: TypeScript interfaces + IndexedDB wrapper</name>
<files>
src/types.ts, src/storage/db.ts, src/storage/db.test.ts
</files>
<read_first>
SPEC.md (section 6.3 for IndexedDB stores, section 4.1 for level structure, section 5.2 for companion types)
src/types.ts (after Task 1 creates it — may be empty placeholder)
</read_first>
<behavior>
- Test: openDB() resolves to an IDBDatabase with 5 object store names
- Test: saveProgress({ currentLevel: 1, ... }) then getProgress() returns same data
- Test: saveSettings({ audioEnabled: true, ... }) then getSettings() returns same data
- Test: getProgress() on empty DB returns null (not crash)
- Test: getSettings() on empty DB returns null (not crash)
</behavior>
<action>
1. Create src/types.ts with ALL interfaces per spec section 6.3 (per FNDN-03):
```typescript
// Companion types
export type CompanionType = 'fee' | 'einhorn' | 'fuchs' | 'eule';
export type KeyboardLayout = 'de' | 'ch';
// Level status for the forest map
export type LevelStatus = 'locked' | 'current' | 'completed';
// Progress store
export interface Progress {
id: 1; // singleton row
currentLevel: number;
completedLevels: number[];
totalSessions: number;
sessionDates: string[]; // ISO date strings (days only)
selectedCharacter: CompanionType;
selectedLayout: KeyboardLayout;
}
// Companion assets store
export interface CompanionAssets {
characterType: CompanionType;
characterSheet: Blob;
avatarImage: Blob;
generatedAt: string; // ISO date
}
// Style reference store
export interface StyleReference {
id: 1; // singleton
imageBlob: Blob;
generatedAt: string;
}
// Forest element store
export interface ForestElement {
id?: number; // auto-increment
levelCompleted: number;
imageBlob: Blob;
imagePrompt: string;
description: string;
companionText: string;
position: { x: number; y: number };
createdAt: string;
}
// Settings store
export interface Settings {
id: 1; // singleton
audioEnabled: boolean;
apiKey: string;
}
// Level definition (used in game/levels.ts)
export interface Level {
level: number;
newKeys: string[];
allKeys: string[]; // cumulative keys up to this level
fingerMap: Record<string, string>; // key -> CSS variable name for finger color
}
// Typing exercise state
export interface TypingExerciseState {
currentLetterIndex: number;
letters: string[];
intervalMs: number;
correctStreak: number;
totalCorrect: number;
totalErrors: number;
}
// Screen names
export type ScreenName = 'welcome' | 'forest' | 'lesson' | 'reward' | 'parent';
```
2. Create src/storage/db.ts — IndexedDB wrapper (per D-02, all 5 stores created, only progress + settings fully used):
```typescript
import type { Progress, Settings, ForestElement, CompanionAssets, StyleReference } from '../types';
const DB_NAME = 'zauberwald';
const DB_VERSION = 1;
export function openDB(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains('progress')) {
db.createObjectStore('progress', { keyPath: 'id' });
}
if (!db.objectStoreNames.contains('companionAssets')) {
db.createObjectStore('companionAssets', { keyPath: 'characterType' });
}
if (!db.objectStoreNames.contains('styleReference')) {
db.createObjectStore('styleReference', { keyPath: 'id' });
}
if (!db.objectStoreNames.contains('forestElements')) {
db.createObjectStore('forestElements', { keyPath: 'id', autoIncrement: true });
}
if (!db.objectStoreNames.contains('settings')) {
db.createObjectStore('settings', { keyPath: 'id' });
}
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
export async function getProgress(db: IDBDatabase): Promise<Progress | null> { ... }
export async function saveProgress(db: IDBDatabase, progress: Progress): Promise<void> { ... }
export async function getSettings(db: IDBDatabase): Promise<Settings | null> { ... }
export async function saveSettings(db: IDBDatabase, settings: Settings): Promise<void> { ... }
```
Each get/save function wraps IDB transaction in a Promise. Use 'readonly' for gets, 'readwrite' for saves. Store name matches interface.
3. Create src/storage/db.test.ts using vitest with fake-indexeddb:
- `npm install -D fake-indexeddb`
- Import `import 'fake-indexeddb/auto'` at top of test
- Test all behaviors listed above
</action>
<verify>
<automated>cd /home/dev/workspace/zauberwald && npx vitest run src/storage/db.test.ts</automated>
</verify>
<acceptance_criteria>
- src/types.ts exports: Progress, ForestElement, CompanionAssets, Settings, StyleReference, Level, CompanionType, KeyboardLayout, LevelStatus, ScreenName, TypingExerciseState
- src/types.ts contains `type CompanionType = 'fee' | 'einhorn' | 'fuchs' | 'eule'`
- src/types.ts contains `type KeyboardLayout = 'de' | 'ch'`
- src/storage/db.ts exports: openDB, getProgress, saveProgress, getSettings, saveSettings
- src/storage/db.ts contains `const DB_NAME = 'zauberwald'`
- src/storage/db.ts contains all 5 store names: 'progress', 'companionAssets', 'styleReference', 'forestElements', 'settings'
- src/storage/db.test.ts exists and `npx vitest run src/storage/db.test.ts` exits 0
- package.json contains `fake-indexeddb` in devDependencies
</acceptance_criteria>
<done>All TypeScript interfaces exported, IndexedDB wrapper creates 5 stores, read/write for progress and settings works, all tests pass</done>
</task>
</tasks>
<verification>
- `npm run dev` starts without errors on port 5173
- `npx vitest run` passes all DB tests
- `npx biome check .` shows no errors (or only warnings)
- All directories from spec section 13 exist
- index.html has 5 screen sections
- CSS custom properties match spec section 7.2 exactly
</verification>
<success_criteria>
- Vite dev server accessible at 0.0.0.0:5173
- TypeScript compiles without errors in strict mode
- IndexedDB wrapper tested and working with 5 stores
- CSS design system complete with all palette colors and typography
- Project structure matches spec section 13
</success_criteria>
<output>
After completion, create `.planning/phases/01-grundger-st-tippmechanik/01-01-SUMMARY.md`
</output>