docs: STATUS.md als Single Source of Truth für Cards-Onboarding

Bisherige Doku war über CLAUDE.md, README.md, SMOKE_TEST.md,
LESSONS_FROM_MANA_MONOREPO.md plus mana/docs/playbooks/CARDS_GREENFIELD.md
zerstreut — eine fresh-AI-Session musste sich Status zusammenstückeln.

STATUS.md zentralisiert:
- TL;DR + Architektur-Topologie
- Architektur-Entscheidungen (festgenagelt)
- Phasen-Status-Tabelle (/🚧/⏸ pro Phase mit Verifikations-Hinweis)
- Lokal-Lauf-Anleitung (5 Schritte zu cards-api + cards-web im Browser)
- Verifizierte Endpoints-Liste
- Pre-Flight für Phase 2 + Live-Föderation
- Wichtige Pointer: Konventionen, Stack, Files, Cross-Repo-Doks
- Git-Historie (6 Commits)
- 6 Architektur-Subtilitäten, die nicht offensichtlich sind:
  Reviews-plaintext, SubIndex-Granularität, Protocol-Mirror-TEMPORARY,
  Inbox-Auto-Create, Dev-Auth-temporär, mana-monorepo-Decommission
- Onboarding-Sequenz (5-Min-Lese-Plan)
- Vorschläge für nächste Phasen

Cross-References:
- CLAUDE.md verweist als erstes auf STATUS.md
- README.md ebenso
- mana/docs/playbooks/CARDS_GREENFIELD.md (im Plattform-Repo) verweist
  zurück auf cards/STATUS.md für aktuellen Stand — Playbook ist der
  Plan, STATUS.md ist die Lage.

Konvention: bei Phasen-Wechsel STATUS.md aktualisieren, nicht den
Playbook (sonst Doku-Drift).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till 2026-05-08 17:18:16 +02:00
parent 0328caa333
commit 2bed28212d
3 changed files with 336 additions and 0 deletions

View file

@ -2,6 +2,12 @@
Guidance for Claude Code when working in this repository.
> **Wenn du gerade neu bist:** lies zuerst [`STATUS.md`](STATUS.md) — dort
> steht der aktuelle Phasen-Stand, was schon läuft, was offen ist, und
> wie du lokal verifizierst. Dieses CLAUDE.md ist nur die Konventions-
> und Architektur-Referenz; der Status lebt in STATUS.md, damit er nicht
> zwischen mehreren Dateien drifted.
## Was dieses Repo ist
**Cards** — eigenständige föderierte Spaced-Repetition-App des

View file

@ -9,6 +9,8 @@ Notizen aus Mana, Web-Schnipsel aus dem Browser-Plugin).
→ Live (geplant): <https://cardecky.mana.how>
**Aktueller Stand und Pickup-Onboarding: [`STATUS.md`](STATUS.md).**
## Stack
- **Frontend:** SvelteKit 2 + Svelte 5 (runes-only)

328
STATUS.md Normal file
View file

@ -0,0 +1,328 @@
# Cards — Projekt-Status & Onboarding
**Letztes Update:** 2026-05-08
**Wenn du gerade neu bist (Mensch oder KI):** dieses Dokument soll dir
in 5 Minuten den vollen Kontext geben. Lies es vor allem anderen.
---
## TL;DR
- **Cards** ist die föderierte Spaced-Repetition-App des Vereins
**mana e.V.** Strategie-B-Greenfield (beschlossen 2026-05-08): kein
Code-Übernahme aus dem alten `mana-monorepo`, sauber neu gebaut.
- **6 saubere Commits** auf `main`. Type-check 4/4 grün, **70 Tests
grün**, lokaler E2E-Smoke-Test (Postgres → API → Frontend → Föderations-
Endpunkte) durch.
- **Phasen 0, 1, 3, 4, 5 sind durch** und verifiziert. Phase 2 (Auth-
Föderation) ist auf user-side Pre-Flight blockiert.
- Cards läuft lokal, ist im Browser benutzbar, hat alle Föderations-
Endpoints aus dem `app-manifest.json` implementiert.
```
┌─────────────────────────────────┐
│ cards/ (this repo) │
│ │
│ apps/web/ SvelteKit + Svelte 5 ← cardecky.mana.how
│ apps/api/ Hono + Bun + Drizzle ← Postgres `cards`
│ packages/cards-domain/ Pure-TS ← FSRS, Schemas, Protocol-Mirror
│ app-manifest.json Föderations-Vertrag
└─────────────────────────────────┘
│ HTTP, JWT, Manifest
┌─────────────────────────────────┐
│ mana/ Plattform │
│ mana-auth, mana-share, │
│ mana-links, mana-mcp, │
│ mana-search, mana-credits, … │
└─────────────────────────────────┘
```
---
## Architektur-Entscheidungen (festgenagelt)
Diese stehen — nicht ohne explizite Diskussion antasten:
1. **Strategie B (Greenfield).** Kein Code aus mana-monorepo.
2. **Server-authoritative MVP.** Keine Dexie, keine eigene Sync-Engine.
Local-First später via mana-sync-Federation, nicht durch eigenen
Stack.
3. **Eigene Postgres-DB `cards`** mit Schema-Isolation `pgSchema('cards')`.
4. **Föderations-Endpoints als Pflicht** — alle aus `app-manifest.json`
implementiert (siehe Phase 5 unten).
5. **Encryption initial AUS.** Nachrüstbar via mana-auth-MK.
6. **MVP-Card-Types nur `basic` + `basic-reverse`.** Schema vorbereitet
auf full-set (cloze, type-in, image-occlusion, audio, multiple-choice).
Vollständiger Plan: [`mana/docs/playbooks/CARDS_GREENFIELD.md`](../mana/docs/playbooks/CARDS_GREENFIELD.md)
(im Plattform-Repo, weil er Verein-übergreifend gilt).
---
## Phasen-Status
| # | Phase | Status | Verifikation |
|---|---|---|---|
| 0 | Read-Day mana-monorepo-Cards-Code lesen | ✅ | `docs/LESSONS_FROM_MANA_MONOREPO.md` |
| 1 | Repo-Skelett (Turbo, pnpm, Bun, Docker, CI) | ✅ | `pnpm install` durch, 136 packages |
| 2 | Auth-Föderation (mana-auth Registrierung, JWT-Verify) | 🚧 blockiert | siehe „Pre-Flight" unten |
| 3 | Domain-Modell + Drizzle + CRUD-API | ✅ | 8 Tabellen, FSRS via ts-fsrs, 46 Tests grün, E2E-Smoke durch |
| 4 | Frontend-Core (SvelteKit, Tailwind 4, Markdown-Editor, Study-View) | ✅ | type-check + build grün, manuell testbar im Browser |
| 5 | Föderations-Endpunkte (share, tools, search, dsgvo) | ✅ | 70 Tests grün, E2E-Smoke (Quote→Inbox→Search→DSGVO-Roundtrip) |
| 6 | Subscriptions/Credits via mana-credits | ⏸ offen | autonom möglich |
| 7 | AI/MCP-Integration | ⏸ offen | braucht laufende mana-mcp |
| 8 | Anki-Import (.apkg-Parser + mana-media-Upload) | ⏸ offen | autonom möglich, ~57 Tage |
| 9 | Polish (DSGVO-UI, Settings, Account, Statistik, i18n, A11y) | ⏸ offen | breite Polish-Phase |
| 10 | Production-Deploy (Mac Mini, Cloudflare-Tunnel) | ⏸ offen | braucht DNS + Tunnel-Config |
| 11 | Decommission Cards-Modul aus mana-monorepo | ⏸ offen | erst nach Phase 10 |
Legende: ✅ erledigt + verifiziert · 🚧 blockiert · ⏸ noch nicht begonnen
---
## Was läuft
### Lokal voll einsatzbereit
```bash
cd /Users/till/Documents/Code/cards
# 1. Dependencies (idempotent)
pnpm install
# 2. Postgres-Container (auf :5435, kollidiert nicht mit Mana-Plattform-:5432)
pnpm docker:up
# 3. Drizzle-Schema pushen
cd apps/api
DATABASE_URL='postgresql://cards:cards@localhost:5435/cards' \
pnpm exec drizzle-kit push --force
# 4. API starten (auf :3081)
DATABASE_URL='postgresql://cards:cards@localhost:5435/cards' \
CARDS_API_PORT=3081 \
CARDS_DSGVO_SERVICE_KEY='msk_test_dsgvo_42' \
bun run src/index.ts &
# 5. Web starten (auf :3082)
cd ../web && pnpm dev &
# 6. Browser öffnen
open http://localhost:3082
```
Login mit beliebigem User-ID-String (Dev-Stub speichert via
`sessionStorage`). Für Föderations-Endpunkte (share/receive) muss die
User-ID UUID-formatiert sein, z.B. `00000000-0000-0000-0000-00000000aaaa`.
Aufräumen: `kill %1 %2 && pnpm docker:down` (Daten in
`infrastructure/.volumes/cards-postgres`).
Vollständiger Smoke-Test-Runbook: [`docs/SMOKE_TEST.md`](docs/SMOKE_TEST.md).
### Verifizierte Endpoints
```
GET /healthz → {"status":"ok"}
GET /version → {"app":"cards","version":"…","build":"…"}
GET /.well-known/mana-app.json → Manifest
POST /api/v1/decks User-JWT CRUD
GET /api/v1/decks User-JWT
GET /api/v1/decks/:id User-JWT
PATCH/DELETE /api/v1/decks/:id User-JWT
POST /api/v1/cards User-JWT Create + Auto-Reviews
GET /api/v1/cards?deck_id=… User-JWT
GET/PATCH/DELETE /api/v1/cards/:id User-JWT
GET /api/v1/reviews/due User-JWT Hot-Path
POST /api/v1/reviews/:cardId/:subIndex/grade User-JWT FSRS-Transition
POST /api/v1/share/receive User-JWT Föderations-Inbox
POST /api/v1/tools/:name User-JWT cards.create | cards.search
GET /api/v1/search?q=… User-JWT SearchResultEnvelope
GET /api/v1/dsgvo/export?user_id=… Service-Key
POST /api/v1/dsgvo/delete Service-Key
```
---
## Pre-Flight für Phase 2 + Live-Föderation
Diese Items sind **nicht autonom machbar** — du oder ein Mensch musst
sie freischalten:
| Item | Wer | Status |
|---|---|---|
| DNS für `cardecky.mana.how` reservieren (Cloudflare) | Mensch | offen |
| GitHub-Repo `mana-ev/cards` anlegen + Remote pushen | Mensch | offen |
| Cards in `mana-auth.apps` registrieren (Service-Key + Public-Key) | Mensch oder KI gegen laufende mana-auth | offen |
| `NPM_AUTH_TOKEN` für Verdaccio in `~/.npmrc` setzen | Mensch | offen |
| Cards-Manifest bei mana-share registrieren | KI gegen laufende mana-share | offen |
Sobald `NPM_AUTH_TOKEN` da ist, kann der lokale Protocol-Mirror in
`packages/cards-domain/src/protocol/` durch Re-Exports aus
`@mana/shared-share-protocol` ersetzt werden — das ist eine 1-Liner-
Änderung in `cards-domain/src/index.ts` plus Imports.
---
## Wichtige Pointer
### Konventionen + Stack
- pnpm 9.15.x, Node 20+, Bun für apps/api
- Tabs-Indent, single-quotes, 100-col Prettier (`.prettierrc.json`)
- SvelteKit 2 + Svelte 5 (**runes-only** — kein legacy `let count = 0`)
- Hono + Bun + Drizzle für API
- Drizzle 0.38 / drizzle-kit 0.30 / zod 3 (gleicher Stand wie Mana-Plattform)
- Tailwind 4 via `@tailwindcss/vite` (oklch-Theme + Dark-Mode-Auto)
- Tests: Vitest + Hono `app.request()`, später Playwright für e2e
Volle Konventionen: [`CLAUDE.md`](CLAUDE.md)
### Wichtige Dateien
| Pfad | Zweck |
|---|---|
| [`STATUS.md`](STATUS.md) | dieses Dokument — Single Source of Truth für Status |
| [`CLAUDE.md`](CLAUDE.md) | Konventionen + Architektur-Invarianten + Stack-Decisions |
| [`README.md`](README.md) | Kurz-Anleitung, ein paar Befehle |
| [`docs/SMOKE_TEST.md`](docs/SMOKE_TEST.md) | Reproduzierbarer E2E-Lauf (curl-Sequenz) |
| [`docs/LESSONS_FROM_MANA_MONOREPO.md`](docs/LESSONS_FROM_MANA_MONOREPO.md) | 15 Architektur-Lessons aus dem Read-Day, 5 Kern-Entscheidungen |
| [`app-manifest.json`](app-manifest.json) | Source of Truth für Föderations-Vertrag (v1.0.0, beta-tier) |
| [`packages/cards-domain/src/`](packages/cards-domain/src/) | zod-Schemas SSOT + FSRS-Adapter + Protocol-Mirror |
| [`apps/api/src/`](apps/api/src/) | Hono-Routen, Drizzle-Schemas, Share-Handlers |
| [`apps/web/src/`](apps/web/src/) | SvelteKit-Routes, $lib/api, $lib/auth-Stub |
| [`infrastructure/docker-compose.yml`](infrastructure/docker-compose.yml) | Postgres-Container für lokal-dev |
### Cross-Repo-Dokumente (im Plattform-Repo `mana/`)
| Pfad | Zweck |
|---|---|
| `mana/docs/playbooks/CARDS_GREENFIELD.md` | Master-Playbook (alle Phasen, Pre-Flight, Decommission) |
| `mana/docs/FEDERATION.md` | Föderations-Architektur-Grundlagen |
| `mana/docs/SHARE_PROTOCOL.md` | Manifest- + Envelope-Schema-Spezifikation |
| `mana/docs/MANA_AUTH_FEDERATION.md` | App-Identitäts-Modell (Service-Keys, JWKS) |
| `mana/docs/SHARED_PACKAGES.md` | Versions-Disziplin Klasse A/B/C |
| `mana/docs/PORTS.md` | Port-Allokation (cards-api: **3081**, cards-web: **3082**) |
| `mana/docs/PLAN.md` | Übergreifende mana-e.V.-Roadmap inkl. Phase 6 (Cards-Greenfield) |
---
## Git-Historie
```
0328caa Phase 5: Föderations-Endpunkte — Cards ist föderierter Peer
89a7a92 Phase 4: Frontend-Core MVP — Decks, Cards, Study mit FSRS-Loop
e3b3a2b docs: SMOKE_TEST.md — verifizierter E2E-Lauf gegen lokale Postgres
5f67bd9 Phase 3 follow-up: type-check + tests grün, ts-fsrs v5 API
45a47e0 Phase 3: Domain-Modell + Decks/Cards/Reviews-CRUD
8605b1b Phase 0+1: Repo-Skelett für Cards-Greenfield
```
`git remote -v` ist leer — Repo lebt lokal, GitHub-Remote folgt mit
Pre-Flight (`mana-ev/cards`).
---
## Architektur-Subtilitäten, die nicht offensichtlich sind
### 1. Reviews bleiben PLAINTEXT
Der FSRS-Scheduler quert täglich `due <= now`. Wenn die Reviews
verschlüsselt wären, müsste man jeden Tag N Reviews entschlüsseln nur
um zu wissen welche fällig sind. Geht nicht.
→ Wenn Encryption nachgerüstet wird: nur `cards.fields` (front/back)
und `decks.{name,description}` werden encrypted, Reviews bleiben
plaintext. Pattern aus mana-monorepo bestätigt (`crypto/registry.ts`
hat `cardReviews` plaintext-allowlisted).
### 2. SubIndex-Granularität pro Card-Type
Eine `basic-reverse`-Karte hat **2** Reviews (sub_index 0 = front→back,
sub_index 1 = back→front). Cloze hat 1 Review pro Cluster-Index.
Beim Card-Insert werden alle initialen Reviews in **einer Transaktion**
mit angelegt — siehe `apps/api/src/routes/cards.ts` POST-Handler.
`subIndexCount(type)` in `@cards/domain` ist die Single Source of Truth.
### 3. Lokales Protocol-Mirror
`packages/cards-domain/src/protocol/` enthält eine **TEMPORARY**-
Kopie der Schemas aus `@mana/shared-share-protocol`. Solange Verdaccio
nicht offen ist (kein `NPM_AUTH_TOKEN`), halten wir sie hier lokal.
→ Drift-Risiko: bei jedem Update der mana-Spec MUSS diese Datei
nachgezogen werden, bis der Swap erfolgt. Marker-Kommentar oben in
jeder Mirror-Datei.
### 4. Inbox-Deck wird auto-erstellt
Eingehende Shares (über `/share/receive`) landen alle in einem
auto-erstellten "Inbox"-Deck pro User. `ensureInboxDeck(db, userId)`
prüft auf Existenz oder legt es neu an. User kann Karten später in
echte Decks umsortieren.
→ Naming-Hinweis: Wenn ein User schon ein Deck namens "Inbox" hat,
greift unser `ensureInboxDeck` darauf zu. Das ist gewollt (idempotent).
### 5. Dev-Auth via X-User-Id ist EXPLICIT temporär
`apps/api/src/middleware/auth.ts` und `apps/web/src/lib/auth/dev-stub.svelte.ts`
sind beide klar als „Phase 2 ersetzt durch echtes JWT" markiert. Beim
Swap auf mana-auth:
- API: `@mana/shared-hono` `authMiddleware()` mit JWKS-Cache
- Web: `@mana/shared-auth`-Login-Flow gegen `auth.mana.how`
- Beide aus Verdaccio (= NPM_AUTH_TOKEN-blockiert)
### 6. Cards-Modul in mana-monorepo wird nach Live-Gang **gelöscht**
Strategie-B-Konsequenz: nach `cardecky.mana.how` live + 2 Wochen Test
folgt ein Decommission-PR in mana-monorepo, der `apps/mana/.../modules/cards/`,
`packages/cards-core/`, `services/cards-server/` (Marketplace-Backend)
und alle DB-Schemas in `mana_platform.cards.*` entfernt. Keine zwei
Cards-Welten parallel.
→ Diese Entscheidung ist im Greenfield-Playbook festgehalten und im
älteren `CARDS_CUTOVER.md` (jetzt überholt) als Strategie-A-Variante
diskutiert worden.
---
## Wenn du gerade neu bist — Onboarding-Sequenz
1. **Lies dieses Dokument zu Ende** (5 Min).
2. **Lies `CLAUDE.md`** (Konventionen + Stack-Decisions, 3 Min).
3. **Lies `mana/docs/playbooks/CARDS_GREENFIELD.md`** (Master-Plan, 10 Min).
4. **Optional:** `docs/LESSONS_FROM_MANA_MONOREPO.md` für Domain-Verständnis.
5. **Verifiziere lokal:** `docs/SMOKE_TEST.md` durchspielen — wenn
alle 7 Schritte grün, ist die Umgebung in Ordnung.
6. **Memory-Check (KI):** falls du auto-memory hast, prüfe
`memory/project_phasenstand.md` für eventuell neueren Stand.
---
## Was als Nächstes ansteht (Vorschläge)
In Reihenfolge meiner Empfehlung:
1. **Phase 8 (Anki-Import)** — autonom, klar abgegrenzte Funktionalität,
~57 Tage. Brauchbar als Migrations-Hilfe für künftige User.
2. **Card-Edit-Page + Inbox-Banner im Frontend** — 12 Tage Polish.
3. **Pre-Flight aktiv abräumen** — Mana-Plattform-Stack + mana-auth
live, dann Cards als App registrieren (Phase 2).
4. **Phase 6 (Subscriptions)** — braucht laufende mana-credits.
5. **Phase 9 (Polish)** — Settings, Account, DSGVO-UI, Statistik, i18n.
Was nicht autonom geht: Phase 2 (Auth-Föderation), Phase 7 (mana-mcp-
Live), Phase 10 (Mac-Mini-Deploy) — alle hängen an Pre-Flight-Items.
---
**Wenn du dieses Dokument liest und etwas hier nicht stimmt, ist das
Dokument schuld, nicht der Code. Update es.**