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

14 KiB
Raw Blame History

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 (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

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.

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

Wichtige Dateien

Pfad Zweck
STATUS.md dieses Dokument — Single Source of Truth für Status
CLAUDE.md Konventionen + Architektur-Invarianten + Stack-Decisions
README.md Kurz-Anleitung, ein paar Befehle
docs/SMOKE_TEST.md Reproduzierbarer E2E-Lauf (curl-Sequenz)
docs/LESSONS_FROM_MANA_MONOREPO.md 15 Architektur-Lessons aus dem Read-Day, 5 Kern-Entscheidungen
app-manifest.json Source of Truth für Föderations-Vertrag (v1.0.0, beta-tier)
packages/cards-domain/src/ zod-Schemas SSOT + FSRS-Adapter + Protocol-Mirror
apps/api/src/ Hono-Routen, Drizzle-Schemas, Share-Handlers
apps/web/src/ SvelteKit-Routes, $lib/api, $lib/auth-Stub
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.