cards/docs/FEATURE_IDEAS.md
Till JS e1ddbf34b3
Some checks are pending
CI / validate (push) Waiting to run
security(cards): fail-secure dev-stub, headers, rate-limit, dsgvo audit
Behebt live verifiziertes Auth-Bypass auf cardecky-api.mana.how
(X-User-Id → founder-Tier) und zieht im selben Patch das fehlende
Operations-/Compliance-Fundament nach.

* Auth-Middleware fail-secure: opt-in via CARDS_AUTH_DEV_STUB="true"
  (war opt-out, Default true). Compose-Default flipped auf "false",
  NODE_ENV="production" für cards-api ergänzt, env-Template
  dokumentiert. vitest.config.ts + tests/setup.ts aktivieren den
  Stub gezielt für Test-Suiten.
* Security-Headers: Hono secureHeaders() in apps/api,
  SvelteKit hooks.server.ts mit X-Frame/X-Content-Type/Referrer/
  HSTS in apps/web. CSP bewusst ausgelassen — eigener Sprint.
* CORS-localhost-Whitelist nur außerhalb Prod.
* Rate-Limiting (in-memory sliding window, dependency-frei) auf
  share.receive 60/min/IP, media.upload 30/min/user,
  decks.generate + decks.from-image 10/min/user, dsgvo.* 10/min/IP.
* Health-Endpoint mit echter DB- und MinIO-Probe; /healthz bleibt
  Liveness, /healthz/details ist Readiness mit 503 bei Failure.
* DSGVO-Honesty: storage_ok + storage_error im Response (statt
  schluckend console.warn), Account-UI zeigt Fehler-Toast.
* Audit-Log: strukturierte JSON-Zeile (kind: "audit") auf stdout
  für /dsgvo/export, /dsgvo/delete, /me/export, /me/delete.
* Bug-Fix: duplizierte case "multiple-choice"-Clause in fsrs.ts.

Verifiziert: apps/api 17 Files / 104 Tests grün, apps/web check
0 errors. Deploy auf Mac Mini steht noch aus.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:56:03 +02:00

18 KiB

Feature Ideas

Stand: 2026-05-12. Korrektur-Pass nach Code-Review gegen den aktuellen Cardecky-Stand. Items, die zwischen Erst-Erstellung (2026-05-11) und heute bereits implementiert wurden, sind unten in „Seit letzter Liste gebaut" geführt, damit der Diff nachvollziehbar bleibt, und aus den Themen-Sektionen entfernt.


🔴 Akute Sicherheitslücke — Live verifiziert 2026-05-12

Dev-Stub-Auth-Bypass ist auf Production aktiv. curl -H "X-User-Id: <beliebig>" https://cardecky-api.mana.how/api/v1/decks liefert 200 OK (ohne Header: 401), und Dev-Stub-User bekommen founder-Tier (auth.ts:90).

Repo-Patch — gebaut 2026-05-12, noch nicht deployed

  1. apps/api/src/middleware/auth.ts:39 auf opt-in geflippt: ALLOW_DEV_STUB = process.env.CARDS_AUTH_DEV_STUB === 'true'. Vergessene env-var ⇒ Bypass AUS.
  2. infrastructure/docker-compose.production.yml: Default flipped auf :-false, plus NODE_ENV: production für cards-api ergänzt (fehlte zuvor — nur cards-web hatte es).
  3. infrastructure/.env.production.example: CARDS_AUTH_DEV_STUB=false als Pflichtzeile mit Kommentar.
  4. apps/api/vitest.config.ts + apps/api/tests/setup.ts angelegt, damit die Test-Suiten (5 Files mit X-User-Id-Auth) den Stub automatisch aktivieren. Verifikation: pnpm test → 16 Files, 100 Tests grün.

Verbleibend bei dir (Mac Mini + Deploy)

  1. git pull / Rebase auf der Prod-Box, dann docker compose -f infrastructure/docker-compose.production.yml \ up -d --build cards-api.
  2. Verifizieren mit curl -i -H "X-User-Id: probe" https://cardecky-api.mana.how/api/v1/decks → erwartet 401 (vorher 200).
  3. Optional: .env.production auf dem Mac Mini um die explizite CARDS_AUTH_DEV_STUB=false-Zeile ergänzen (jetzt nur noch Doku-Konsistenz — der Compose-Default ist schon fail-secure).
  4. Forensik: cards.decks.user_id und cards.cards.user_id gegen mana_auth.users joinen — IDs ohne Match wären Indizien für ausgenutzten Bypass.

Seit letzter Liste gebaut (Stand-Korrektur)

Diese Punkte standen in der 2026-05-11-Fassung noch als Ideen, sind aber im Code längst gelandet:

  • audio-front / typing / multiple-choice — komplette Renderer + Editor-Forms + Integration im Study-Flow (AudioFrontView.svelte, TypingView.svelte, MultipleChoiceView.svelte, Edit-Routen unter cards/[id]/edit/+page.svelte).
  • Keyboard Shortcuts im Study-Mode1/2/3/4 = Rating, Space/Enter = Reveal bzw. good (routes/study/[deckId]/+page.svelte:170-180).
  • Daily Streaks (Backend + Anzeige)me.ts:106-156 berechnet streak_days, Stats-Dashboard zeigt es an. Streak-Freeze, Streak im Header und Streak-Push fehlen noch (siehe Gamification unten).
  • CSV-Import + CSV-Exportlib/csv/{parse,import,export}.ts + CsvImport.svelte.
  • Quizlet-Importlib/quizlet/parse.ts + QuizletImport.svelte.
  • Marketplace-Smart-Merge-Pull-UIupdateAvailable-Banner und pullUpdate(deckId) im Deck-Edit (routes/decks/[id]/edit/+page.svelte:39,113,275).
  • Lizenz-Feld auf Marketplace-Decksmarketplace/decks.ts:73 hat license mit Default Cardecky-Personal-Use-1.0; Constraint bindet Preis an Lizenz-Typ.

Lern-Erlebnis

Scheduler-Verbesserungen

  • FSRS-Parameter pro User optimierents-fsrs liefert computeParameters() aus Review-History; Schema (decks.fsrs_settings) und Per-Deck-Override sind vorbereitet, aber kein Endpoint und kein UI. Größter messbarer Retention-Gewinn pro Aufwand.
  • Leech-Detectionreviews.lapses zählt bereits; Auto-Markierung + UI-Vorschlag „aufteilen / suspendieren" für Karten oberhalb eines Schwellwerts.
  • Undo letzte Bewertung — wichtiger UX-Reflex; aktuell muss man das Review händisch zurückbauen.
  • Card Burial / Suspension — Karten temporär deaktivieren ohne Löschen; häufig angefragtes Anki-Feature.
  • Geschwister-Burial — Cloze-Cluster und basic-reverse-Seiten nicht am selben Tag wiederholen.
  • Custom Study Sessions — gefilterte Sitzungen: nur neue Karten, nur Fehler der letzten Woche, nach Tag filtern. Tag-Filter im reviews-Endpoint fehlt aktuell ganz.
  • Session-Mix-Algorithmus — heute wird due ≤ now linear abgearbeitet; Optionen „Neue Karten zuerst", „durchmischt", „nur Fehler" als saubere Filter im Queue-Loader.
  • Subdeck-Unterstützung — hierarchische Deck-Struktur (z. B. Vokabeln → Nomen / Verben).
  • Cloze-Hint-Anzeige{{c1::answer::hint}} wird aktuell beim Rendern fallen gelassen; Hint-Anzeige steht in STATUS.md als verbleibender Phase-9-Punkt.

Kartentypen, Schema vorhanden / vorbereitet

  • Bild-Front / Bild-Back — als generischer Type mit media_ref in fields. MinIO-Storage + media_files-Pfad ist seit Sprint 9k da, also rein UI-Frage.
  • Speech-In (Audio-Antwort vom User) — Whisper via mana-stt ist im Plattform-Stack vorhanden; Schema müsste expected + Audio- Vergleichs-Strategie definieren.

Gamification & Motivation

  • Streak-Freeze-Token — ein Streak-Schutztag pro Woche, optional durch Credits kaufbar.
  • Streak im Header — heute nur im Stats-Dashboard sichtbar; Header-Glyph mit Zahl wäre Mikro-Aufwand, sichtbare Wirkung.
  • XP + Badges — Meilensteine (erstes Deck, 100 Karten, 30-Tage- Streak).
  • Tages-Ziele — „Heute: 20 Karten" mit Progress-Bar im Dashboard.
  • Push/Email-Reminders — „Du hast heute noch 15 fällige Karten" via mana-notify. Aktuell wird mana-notify von Cards noch nicht benutzt (siehe marketplace/pull-requests.ts:41 — „Notify-Calls ausgelassen — eigene Welle").
  • Estimated Mastery Date — „Dieses Deck beherrschst du voraussichtlich in 3 Wochen" (aus FSRS-Stability ableitbar).

KI-Features

  • Auto-Cloze-Generator — Text markieren → {{c1::...}} automatisch einfügen.
  • Card-Split-Vorschlag — KI erkennt informationsreiche Karten und schlägt Aufteilung vor.
  • Erklär-Modus — Nach falscher Antwort: KI erklärt den Zusammenhang (opt-in).
  • Auto-Tagging — Karten beim Erstellen / Importieren semantisch taggen.
  • Duplicate Detection — semantische Ähnlichkeit über Decks hinweg erkennen.
  • Card Quality Score — Hinweis „Diese Karte hat zu viel Text" + Verbesserungsvorschlag.

Analytics & Insights

  • Vergessenskurven-Visualisierung — pro Deck und Tag, aus FSRS-State ableitbar.
  • Retention-Rate — aufgeschlüsselt nach Kategorie und Sprache.
  • Lernzeit-Tracking — Minuten pro Session, Wochentrend.
  • Karten-Schwierigkeits-Heatmap — welche Karten kosten die meiste Review-Zeit.
  • Wöchentliche Zusammenfassung — In-App oder per Email via mana-notify.
  • Algorithmus-Transparenz pro Karte — kleines „Wieso wurde ich befragt?"-Tooltip mit Stability/Difficulty/letztem Rating. Macht FSRS sichtbar (Mission-Wert „Souveränität").

Import / Export

  • PDF-Export — druckbare Karteikarten (A6-Format, vorder-/rückseitig). Print-Route existiert schon (decks/[id]/print/), aber als HTML-Print, nicht generiert-PDF.
  • .apkg-Export — Round-Trip mit dem Anki-Parser (Parser ist schon da). Stärkste „du kannst jederzeit weggehen"-Geste, Mission-Argument.
  • Web Clipper (Browser-Extension) — markierter Text → sofort neue Karte; eigenes Projekt, eigener Scope.
  • SuperMemo XML — für Power-User aus dem SM-Ecosystem.
  • FSRS-State-Export — Lernstand als JSON exportieren für Backup und Migration (über DSGVO-Export hinaus, in interop-tauglichem Format).

Zusammenarbeit & Community

  • Study Spaces — gemeinsame Decks für Schulklassen und Lerngruppen (braucht Gruppen-Konzept in mana-auth, das noch nicht existiert; decks.visibility = 'space' ist im Schema vorgesehen, aber ohne Spaces-Backend wirkungslos).
  • Deck-Ratings & Kommentare — Qualitätssicherung im Marketplace durch Community. marketplace/discussions.ts-Schema existiert, UI-Anbindung müsste geprüft werden.
  • Study Challenges — mit Freunden auf demselben Deck messen.
  • Kreator-Analytics — für Marketplace-Publisher: Views, Forks, Abonnenten-Retention.
  • Collaborative Decks — Team-Editing mit Rollen (Maintainer / Contributor).

Marketplace (eigener Themenblock)

Marketplace-Schema + Pull-Update-UI sind da, aber drumherum klafft einiges:

  • Pull-Request-UI — Backend (marketplace/pull-requests.ts) und API-Client (lib/api/marketplace.ts) existieren; eine Surface, wo ein Fork-Maintainer Änderungen an das Original vorschlagen kann, fehlt im Web.
  • Versions-Diff zwischen Fork und Upstream — Voraussetzung, damit Smart-Merge-Pull nicht „trust me"-Klick ist.
  • Moderations-Queue-Surfacemarketplace/moderation.ts im Schema vorhanden; Report-Funktion auf Decks/Karten im UI fehlt.
  • Lizenz-Auswahl bei Publishdecks.license hat Default Cardecky-Personal-Use-1.0; Standard-Lizenzen (CC-BY-SA, CC-0, CC-BY-NC) als Optionen im Publish-Flow.
  • Lizenz-Anzeige beim Studieren geforkter Decks — wer das Deck veröffentlicht hat, welche Lizenz greift; transparent unten in der Study-View.

UX / Plattform

  • PWA Offline-Read-Only als Zwischenschritt zur vollen PWA: Service-Worker cached die letzte Queue, Bewertungen werden gepuffert. Bricht die Server-authoritative-Invariante nicht (Puffer ist transient).
  • Dark Mode / Theme-Switcherdata-theme="forest" ist in app.html fest verdrahtet; In-App-Auswahl fehlt. Bei der laufenden 12-Token-Theming-Strategie ohnehin geplant.
  • Bulk-Operationen — mehrere Karten auswählen, verschieben, taggen, löschen.
  • Dynamic Decks / Smart Playlists — automatisch gefiltert: z. B. „alle Karten mit Tag 'Grammatik' aus 3 Decks".
  • Card History — Lernverlauf pro Karte: wann wie bewertet.

A11y (konkret aufs UI bezogen)

  • prefers-reduced-motion respektieren in DeckFan.svelte und DeckStack.svelte (animationslastige Komponenten).
  • Screen-Reader-Live-Region im Study-View für das Reveal-Event („Antwort eingeblendet").
  • Touch-Targets ≥ 44 px für die Rating-Buttons; Mobile-Review ist der Haupt-Use-Case und Code zeigt keine explizite Min-Höhe.
  • Fokus-Reihenfolge nach Reveal — Cursor sollte auf den Rating- Buttons landen, nicht am Body-Anfang.
  • Tastatur-Hilfe-Overlay im Study-Mode (?-Taste): zeigt die bestehenden Shortcuts an. Heute sind sie undokumentiert in der UI.

Security (eigener Block, weil Live-App)

  • Dev-Stub-Default ist opt-out, nicht opt-in — siehe akute Sicherheitslücke oben. Fix-Anweisung dort, dieser Eintrag bleibt als Erinnerung, dass die Middleware-Logik in auth.ts:39 auf opt-in geflippt gehört (=== 'true' statt !== 'false').
  • JWT in localStoragedev-stub.svelte.ts:13 speichert das Access-Token unter cards.auth.accessToken. Anfällig für XSS- Token-Diebstahl. Mitigation: DOMPurify sanitisiert Markdown (gut), aber HttpOnly-Cookie wäre der robustere Ansatz, sobald der SSO- Cookie-Pfad ohnehin schon da ist.
  • SVG-Upload erlaubtmedia.ts:13 whitelistet image/- Prefix; image/svg+xml ist im Extension-Map (media.ts:28). SVG kann eingebettetes JavaScript enthalten. Wenn SVG-Medien per <img> gerendert werden, ist es harmlos; bei <object>/<iframe> oder direkter Einbettung gibt es ein XSS-Loch. Mindestens Content-Security-Policy img-src strikt halten, oder SVG-Upload separat sanitisieren (svgo + Script-Strip).
  • Security-Headers — gebaut 2026-05-12, noch nicht deployed.
    • API: secureHeaders() aus Hono vor cors() eingehängt (apps/api/src/index.ts:3,30).
    • Web: apps/web/src/hooks.server.ts neu, setzt X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, plus HSTS (180 Tage, includeSubDomains) wenn NODE_ENV=production.
    • CSP bewusst ausgespart — eine richtige Content-Security- Policy braucht Browser-Test (inline-styles, Theme-Assets, Markdown-Renderer). Eigener Sprint. SVG-Upload-Risiko (oben) bleibt bis dahin ungemildert.
  • CORS lässt localhost in Prod durch — gebaut 2026-05-12, noch nicht deployed. Live-Probe hatte Access-Control-Allow-Origin: http://localhost:9999 gezeigt. Patch: localhost-Regex in apps/api/src/index.ts per NODE_ENV === 'production'-Check disabled.
  • DSGVO-Delete-Honesty — gebaut 2026-05-12, noch nicht deployed. Sowohl /api/v1/dsgvo/delete (Service-Key) als auch /api/v1/me/delete (Self-Service) liefern jetzt storage_ok: true|false
    • optional storage_error im Response. Frontend zeigt im Account-Delete-Flow eine Fehler-Toast wenn storage_ok=false.
  • Service-Key-Rotation — ein statisches CARDS_DSGVO_SERVICE_KEY in env, kein Revoke. Phase F-1 ist in service-key.ts:11 geplant (Verifikation gegen mana-auth.apps.app_service_keys). Bis dahin: Rotation-Playbook in docs/playbooks/ festschreiben.

Operations & Resilienz

Bisher gar nicht in dieser Liste behandelt, aber Cards ist live:

  • Rate-Limiting — gebaut 2026-05-12, noch nicht deployed. In-Memory Sliding-Window-Middleware in apps/api/src/middleware/rate-limit.ts, dependency-frei. Aktive Limits: share.receive 60/min/IP, media.upload 30/min/user, decks.generate 10/min/user, decks.from-image 10/min/user, dsgvo.* 10/min/IP. Verifiziert in tests/rate-limit.test.ts (4 Tests). Bei Multi-Container-Setup später auf Redis oder Cloudflare-Rate-Limit umsteigen.
  • Audit-Log für DSGVO-Aktionen — gebaut 2026-05-12, noch nicht deployed. apps/api/src/lib/audit.ts schreibt strukturierte JSON-Zeilen auf stdout (kind: 'audit'). Aktiv auf /dsgvo/export, /dsgvo/delete, /me/export, /me/delete. Persistierung in eine audit_log-Tabelle ist additiv möglich, ohne Aufrufer anzupassen.
  • Health-Endpoint inkl. DB+MinIO-Probe — gebaut 2026-05-12, noch nicht deployed. /healthz bleibt simpel (Liveness), neu ist /healthz/details mit echtem SELECT 1 und MinIO-bucketExists- Probe, Status 200 bei beidem grün, sonst 503 mit Latency+Error je Probe.
  • Strukturiertes Logging + Request-IDs end-to-end — vermutlich via @mana/shared-hono vorhanden, aber im Frontend-Fehler-Toast bisher keine sichtbare Correlation-ID.
  • Backup-Strategie für cards-DB + MinIO-Bucket — hängt am globalen Backup-Cron-TODO, ist aber jetzt mit Prod-Daten dringend.
  • content_hash-Backfill-Skript — Pre-Sprint-9j-Karten haben content_hash = NULL, Re-Import-Dedupe ist auf diese Karten blind (siehe STATUS.md Subtilität #10).

Mission-Fit (Vereins-Werte aufs Produkt anwenden)

  • Anti-Lock-In als Feature, nicht als Disclaimer.apkg- Export plus FSRS-State-Export plus eine sichtbare „Daten mitnehmen"-Surface in account/. Heute ist es als DSGVO-Export versteckt.
  • Telemetrie-Audit dokumentieren — verifiziert: 0 Trackerapps/web/src/ enthält weder PostHog noch Plausible/Matomo/Umami, kein gtag, keine track()-Aufrufe. Das ist ein hartes Mission-Argument, das man heute kostenlos hergibt. Vorschlag: kleine Surface in account/ oder im Footer („Cards trackt dich nicht — Code-Beweis"), die auf den git grep-Befund im Repo verlinkt.
  • Tier-frei-Modus erhalten — Schema und Plumbing für mana-credits sind da (credits-client.ts, requireTier), aber MVP ist tier-frei. Bei jeder neuen Feature-Idee bewusst markieren, ob sie tier-pflichtig wird oder nicht; default frei.

DevX & Code-Hygiene

  • Playwright-E2E in CISTATUS.md spricht von „lokalem E2E-Smoke"; ein playwright.config.ts existiert im Repo nicht. Bei Live-App mit Marketplace-Forks die schmerzhafteste Regressions-Quelle.
  • Drizzle-Migrationen versionierendrizzle.config.ts zeigt auf out: './src/db/migrations', der Ordner existiert aber nicht (nur db:push). Mit Prod-Daten ein Risiko; Wechsel auf drizzle-kit generate + versionierte Migrationen.
  • Storybook / Histoire für lib/components/ — 20+ Svelte- Komponenten ohne isolierte Vorschau; Lost-Pixel-Theming-Strategie würde davon doppelt profitieren.
  • CLAUDE.md ↔ Realität synchen — CLAUDE.md erwähnt deploy.yml neben ci.yml, im .github/workflows/-Ordner liegt aber nur ci.yml. Entweder Workflow nachziehen oder Doku korrigieren.

Offene Punkte

  • Was nach diesem Hardening-Sprint übrig bleibt:
    1. CSP setzen — eigener Mini-Sprint mit Browser-Test, weil SVG-XSS-Risiko erst mit CSP wirklich gemildert ist.
    2. Drizzle-Migrationen versionieren — bevor das erste Prod- Schema-Diff weh tut. Heute läuft alles via db:push.
    3. FSRS-Parameter-Optimierung pro User — größter messbarer Lern-Effekt, Schema schon vorbereitet.
    4. Service-Key-Rotation-Playbook in docs/playbooks/ anlegen, bis die mana-auth.app_service_keys-Anbindung (Phase F-1) fertig ist.
    5. JWT-Storage von localStorage → HttpOnly-Cookie — XSS-Token-Diebstahl-Härtung. Größerer Umbau weil der SSO-Callback-Flow das mitziehen muss.
  • PWA-Offline-Read-Only ist der Architektur-Trade-off mit dem größten Risiko: der saubere server-authoritative Pfad würde um einen Sync-Puffer erweitert. Lieber spät als verfrüht.
  • Study Spaces bleibt blockiert durch fehlendes Gruppen-Konzept in mana-auth; Schema-Slot visibility = 'space' ist vorbereitet, aber ohne Backend wirkungslos.
  • Marketplace-Reifegrad transparent in STATUS.md führen — aktuell taucht „Marketplace" in STATUS.md nur in der „Strategie- B-Ausnahme"-Notiz auf; ob Marketplace im UI freigeschaltet ist oder hinter einer Feature-Flag steckt, ist von außen nicht ablesbar.
  • Notify-Anbindung ist offenmana-notify wird von Cards noch nicht aufgerufen; sobald Streak/Weekly/PR-Notifies reinkommen sollen, ist das ein eigener Sprint.