Some checks are pending
CI / validate (push) Waiting to run
Study-View:
- Graceful Backlog Recovery: Banner bei >30 fälligen Karten, Recovery-Queue
sortiert nach Stability aufsteigend (25er-Batch, ?recovery=true)
- Undo letzte Bewertung: 5s-Toast mit RAF-Fortschrittsbalken, Ctrl/Cmd+Z,
prevSnapshot-Spalte in reviews (Migration 0001, Prod deployed)
- FSRS-Tooltip nach Reveal: State / Stability / Difficulty als Popover
Deck-Edit:
- Neuer Abschnitt „Lern-Algorithmus" mit request_retention-Slider (50–99 %)
Header:
- Streak-Pill (🔥 N) + fällige-Karten-Pill via GET /api/v1/me/summary
Stats-Page:
- Difficulty-Distribution (5 Buckets, Farb-Bars)
- Deck-Fortschritt (Mastery % = stability>21, max 6 Decks)
API:
- GET /me/summary: streak_days + due_now (leichtgewichtiger Header-Endpoint)
- GET /reviews/due: ?recovery=true → stability-sort, Limit 25
- POST /reviews/:cardId/:subIndex/undo: prevSnapshot-Restore, 409 wenn leer
- /me/stats: difficulty_distribution + deck_mastery
Landing:
- 5 Blog-Artikel (Quizlet-Paywall, FSRS, Datenschutz, Anki, Lernkarten-Tipps)
- BlogTeaser-Komponente auf Startseite, Footer-Spalte „Artikel"
i18n: 11 neue Schlüssel in DE/EN/FR/IT/ES
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
427 lines
19 KiB
Markdown
427 lines
19 KiB
Markdown
# 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-Mode** — `1/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-Export** — `lib/csv/{parse,import,export}.ts` +
|
||
`CsvImport.svelte`.
|
||
- **Quizlet-Import** — `lib/quizlet/parse.ts` + `QuizletImport.svelte`.
|
||
- **Marketplace-Smart-Merge-Pull-UI** — `updateAvailable`-Banner und
|
||
`pullUpdate(deckId)` im Deck-Edit
|
||
(`routes/decks/[id]/edit/+page.svelte:39,113,275`).
|
||
- **Lizenz-Feld auf Marketplace-Decks** — `marketplace/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 optimieren** — `ts-fsrs@5.3.2` hat
|
||
**kein** `computeParameters()` aus Review-History (das erfordert den
|
||
Python `fsrs-optimizer`). Der praktisch nutzbare Hebel ist
|
||
`request_retention` (0.5–0.99): höherer Wert → mehr Wiederholungen,
|
||
besser für prüfungsrelevantes Lernen; niedrigerer Wert → lockerer,
|
||
gut für Allgemeinwissen. Schema (`decks.fsrs_settings`) und
|
||
Per-Deck-PATCH-Endpoint sind da; **Retention-Slider im Deck-Edit
|
||
gebaut 2026-05-13.** w-Gewichte-Optimierung (Offline-Python-Skript
|
||
→ JSON-Upload) bleibt offen.
|
||
- **Leech-Detection — gebaut 2026-05-12.** `me/stats` liefert
|
||
`leech_cards` (Threshold 4 Lapses, Limit 20, sortiert nach
|
||
Lapses desc, mit Front-Snippet + Deck-Name). Stats-Page hat eine
|
||
rote Leech-Sektion mit Link in den Card-Editor. i18n in DE/EN/
|
||
FR/IT/ES. Suspension/Aufteilen-Vorschläge sind nächste Welle.
|
||
- **Undo letzte Bewertung — gebaut 2026-05-13.** `prevSnapshot`-
|
||
Spalte in `reviews`, API `POST /:cardId/:subIndex/undo`, 5-s-Toast
|
||
mit Fortschrittsbalken im Study-View, Ctrl/Cmd+Z-Shortcut.
|
||
- **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 — bereits implementiert.** `renderClozePrompt`
|
||
in `packages/cards-domain/src/cloze.ts` rendert `{{c1::answer::hint}}`
|
||
bereits als `[hint]`. `STATUS.md`-Eintrag ist veraltet.
|
||
|
||
### 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 — gebaut 2026-05-13.** `GET /api/v1/me/summary`
|
||
liefert `streak_days` + `due_now`; Header zeigt Flammen-Pill und
|
||
fällige-Karten-Pill via `onMount`.
|
||
- **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 / Graceful Backlog Recovery —
|
||
gebaut 2026-05-13.** Stats-Page zeigt Difficulty-Distribution
|
||
(5 Buckets, Farb-Bars) + Deck-Fortschritt (Mastery %, Stability>21).
|
||
Study-View zeigt Recovery-Banner wenn total>30 fällige Karten,
|
||
startet Queue nach Stability sortiert (25er-Batch).
|
||
- **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 — gebaut 2026-05-13.**
|
||
FSRS-Tooltip im Study-View: ⓘ-Button nach Reveal öffnet Popover
|
||
mit State, 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-Surface** — `marketplace/moderation.ts` im
|
||
Schema vorhanden; Report-Funktion auf Decks/Karten im UI fehlt.
|
||
- **Lizenz-Auswahl bei Publish** — `decks.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-Switcher** — `data-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 `localStorage`** — `dev-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 erlaubt** — `media.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 läuft Report-Only seit 2026-05-12.** `hooks.server.ts`
|
||
setzt `Content-Security-Policy-Report-Only` mit restriktiver
|
||
Policy (default-src 'self', script-src 'self', img-src
|
||
'self' data: blob:, connect-src whitelist auf
|
||
cardecky-api/auth.mana.how/share/mcp). Violations laufen in
|
||
die Browser-DevTools-Console. Nach 1-2 Tagen Live-Beobachtung
|
||
via `CARDS_CSP_ENFORCE=true` auf Enforce flippen. SVG-Upload-
|
||
Risiko ist dann gemildert (script-src verbietet inline-JS in
|
||
SVG-Inlinen).
|
||
- **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-Playbook — gebaut 2026-05-12.**
|
||
`docs/playbooks/SERVICE_KEY_ROTATION.md` mit 5-Schritt-Rotation,
|
||
Tabus, Phase-F-1-Übergang. Bis die mana-auth-managed Variante
|
||
fertig ist, ist das die SoT.
|
||
|
||
---
|
||
|
||
## 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 Tracker** —
|
||
`apps/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 CI** — `STATUS.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 versionieren — Repo-Setup gebaut 2026-05-12,
|
||
Prod-Bootstrap offen.** `0000_baseline.sql` (355 Zeilen, 25 Tabellen
|
||
+ 5 Enums) festgefrostet. `apps/api/scripts/bootstrap-drizzle-tracking.ts`
|
||
+ `pnpm drizzle:bootstrap-tracking` markiert die Baseline auf der
|
||
Live-DB als „bereits angewandt", ohne SQL re-auszuführen. Lokal
|
||
verifiziert: idempotent + `drizzle:migrate` erkennt die Migration
|
||
danach als bekannt. Playbook in
|
||
`docs/playbooks/DRIZZLE_MIGRATIONS_BOOTSTRAP.md`. Nächster Schritt
|
||
beim User: einmalig auf der Prod-Box ausführen, danach ist `push
|
||
--force` Tabu.
|
||
- **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 offen** — `mana-notify` wird von Cards
|
||
noch nicht aufgerufen; sobald Streak/Weekly/PR-Notifies
|
||
reinkommen sollen, ist das ein eigener Sprint.
|