cards/STATUS.md
Till 2bed28212d 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>
2026-05-08 17:18:16 +02:00

328 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.**