R0 (Doku): - Archiv unter docs/marketplace/archive/ aus managarten-Tag cards-decommission-base: MARKETPLACE_PLAN (654 Z., Vollvision mit mana-credits-Flow, Anti-Patterns), COMPETITORS, GUIDELINES, cards-server_CLAUDE. - docs/playbooks/MARKETPLACE_RESTORE.md mit Schema-Naming-Entscheidung (eigenes marketplace-pgSchema), Wellen R0-R6, Cardecky-Skill- Integration, Lizenz-Modell. - CLAUDE.md Invariante 2: Strategie-B gilt nur für Study-/FSRS-/Sync- Schicht; Marketplace-Restore ist explizite Ausnahme. - STATUS.md: Phase 12 R0+R1 durch. R1 (Schema): - 16 Tabellen + 5 Enums im neuen marketplace-pgSchema (authors, decks, deck_versions, deck_cards, tag_definitions, deck_tags, deck_stars, deck_subscriptions, deck_forks, deck_pull_requests, card_discussions, deck_reports, ai_moderation_log, deck_purchases, author_payouts, author_follows). - drizzle.config.ts: schemaFilter ['cards', 'marketplace']. - Greenfield cards-pgSchema unangetastet. - DB-CHECK decks_price_requires_license verifiziert (paid Deck mit CC-BY wirft sauber ab). - type-check + 56 API-Tests grün, drizzle-kit push idempotent. Decks dormant (kein Code-Pfad ruft die Tabellen). R2 (Backend α/β: Author-Profile + Publish + AI-Mod) als nächstes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15 KiB
Marketplace-Restore — Playbook
Status: Plan, R0+R1 in Arbeit. Stand 2026-05-09. Vorgänger: das alte
services/cards-server/ausmanagarten/(mana- monorepo) wurde am 2026-05-08 zusammen mitapps/cards/dekommissioniert, weil beides eine Kopplung war — siehe Decommission-Commitsbc158cb0b(cards-server),9cd871749(apps/cards),dd1bab09d(cards-core). Rollback-Tag:cards-decommission-baseim managarten-Repo.Dieser Plan dokumentiert den Restore des Marketplace-Backends in die Standalone-Cards-App, additiv zur bestehenden Greenfield-API.
TL;DR
- Strategie-B-Klarstellung: „Kein Code aus mana-monorepo" galt der
Study-/FSRS-/Sync-Schicht (Dexie raus, server-authoritative). Marketplace
war nie davon betroffen — er wurde nur mit-rausgerissen, weil er an
apps/cardsgekoppelt war. - Restore vs. Neubau: Restore. ~13.000 Zeilen reifer Code, 8 Phasen in Produktion gelaufen, Plan-Doku in Goldstandard-Qualität (654 Zeilen), bekannte Limitierungen sauber dokumentiert. Neubau wäre 4–6 Wochen, Restore ~14 Tage.
- Schema-Naming-Entscheidung: Eigenes
marketplace-pgSchema in derselbencards-DB. Begründung: saubere Read/Write-Trennung, Backup-Granularität (pg_dump --schema=marketplace), RLS-Policies pro Schema möglich, keine Kollisionen mit den existierendencards.{decks,cards,reviews,…}-Tabellen. - Service-Topologie: Single-Service. Marketplace-Routen kommen unter
/api/v1/marketplace/*in den bestehendencards/apps/api. Kein zweiter Hono-Prozess, kein zweiter Container. YAGNI bei deinem Volumen. - Frontend: alte Routes 1:1 nach
cards/apps/web/src/routes/—/explore,/d/[slug],/u/[slug],/me/{published,subscribed,forks,purchases},/admin/reports. Imports auf Verdaccio-Pakete umstellen, Theming- Bridge-Aliase greifen automatisch. - Restore-Reihenfolge: R0 (Doku) → R1 (Schema) → R2 (Auth + Routes α/β) → R3 (γ + δ) → R4 (ε) → R5 (Frontend) → R6 (Smoke + erste Cardecky-Decks publishen).
- Was nicht im ersten Wurf: Paid Decks (ζ.1) und Moderation-UI (η.1). Schema-Tabellen kommen mit, aber Code-Pfade bleiben dormant bis nach erstem Live-Test.
Was die alte Implementation konnte (Phase α–η.1)
Inhalt der archivierten Dokumente — Original-Wahrheit unter
cards/docs/marketplace/archive/:
| Datei | Was drin |
|---|---|
MARKETPLACE_PLAN_2026-05-07.md |
654-Zeilen-Vollvision: Datenmodell, mana-credits-Flow, Cold-Start-Strategie, Anti-Patterns, Phasen-Status |
COMPETITORS_2026-05.md |
353-Zeilen-Konkurrenz-Analyse: Quizlet, AnkiHub, Brainscape, AnkiPro, AnkiApp, RemNote, Mnemosyne |
GUIDELINES.md |
367 Zeilen Community-Guidelines + Lizenz-Modell (SPDX + Cardecky-Personal-Use-1.0 + Cardecky-Pro-Only-1.0) |
cards-server_CLAUDE.md |
110 Zeilen Tech-Stack-Doku des Original-Service |
Phasen-Status zum Zeitpunkt der Decommission (2026-05-08):
| Phase | Status | Was lief produktiv |
|---|---|---|
| α — Skelett | ✅ live | 17-Tabellen-Schema, JWT-Auth, Container, Tunnel cardecky-api.mana.how |
| β — Author-Workflow | ✅ live | Profil-Claim, Publish, Lizenz-Picker (SPDX), Preis-Eingabe, AI-Mod-First-Pass |
| γ — Discovery | ✅ live | /explore, Stars, Follows, Author-Profile, Trending, Search (ILIKE) |
| δ — Subscribe + Smart-Merge | ✅ live | Pull, Diff-View „+N · ~N · −N", FSRS-State erhalten über Karten-Hash-Diff |
| ε — PRs + Discussions | ✅ live | „✏️ Verbessern" auf jeder Karte, Author-Merge, Inline-Threads, Notify-Mails |
| ζ.1 — Paid Decks | ✅ live | 4-Schritt-Reserve→Purchase→Commit→Grant, 80/20-Split (90/10 für verified_mana) |
| η.1 — Moderation | ✅ live | Reports, Admin-Inbox, Takedown-Workflow (kaskadiert auf PRs), Author-Ban |
Bekannte Limitierungen (siehe MARKETPLACE_PLAN_2026-05-07.md §13a):
PR-Merge-stale-blind, Reconciler-Lücke bei Paid-Pipeline, Mention-System
fehlt, Discussion-Threading 1-Level, kein Refund-Self-Service. Alles
dokumentiert, nichts unbekannt.
Architektur-Anpassungen für den Restore
1. DB-Topologie: eigenes marketplace-pgSchema
Alt (in mana_platform-DB, geteilt mit allen mana-Services):
mana_platform.cards.{authors, decks, deck_versions, …} — 17 Tabellen
Neu (in standalone cards-DB des Standalone-Repos):
cards.cards.{decks, cards, reviews, media_files, tags, imports} — Greenfield, bleibt
cards.marketplace.{authors, decks, deck_versions, deck_cards, …} — Restore, neu
Begründung für ein eigenes pgSchema statt Tabellen-Prefix
(published_decks, published_deck_versions, …):
- Sauberer Read-Path. Public-Endpoints sehen nur das
marketplace- Schema. Greenfield-Code (private Decks/Karten/Reviews) sieht ausschließlichcards. Kein Risiko, dass einSELECT * FROM decksversehentlich beide Welten mischt. - Backup-Granularität.
pg_dump --schema=marketplaceexportiert nur den Marketplace-Stand für Compliance/Recovery. Privater Lern- Stand der User bleibt unangetastet. - RLS-Policies pro Schema — falls wir je Row-Level-Security einführen für public-decks-take-down-Workflows, ist das pro Schema konfigurierbar.
- Drizzle-kit-Push-Disziplin.
schemaFilter: ['cards', 'marketplace']hält beide Pushes sauber. Schema-Drift fängt sich auf Schema-Ebene.
Drizzle-Variablennamen halten den public-Prefix aus dem alten Code:
publicDecks, publicDeckVersions, publicDeckCards. So bleibt das
intent klar, und Imports kollidieren nicht mit cards.decks aus dem
Greenfield.
2. Auth-Modell: identisch, kein Refactor
Alter cards-server: JWKS-Cache gegen mana-auth. Greenfield-cards-api:
JWKS-Cache gegen mana-auth. Identisch. Service-Key-Auth (X-Service-Key)
für Mana-Webhooks ebenfalls 1:1 übernommen.
Optional-Auth-Middleware für Public-Endpoints (/explore, /d/:slug)
muss aus dem alten Code mitkommen — der erlaubt anonymen Read und
gibt zugleich personalisierte Daten (z.B. „Bist du Subscriber?")
wenn ein Bearer mit-übermittelt ist.
3. Service-Topologie: Single-Service
Alle Marketplace-Routen unter /api/v1/marketplace/* in
cards/apps/api/src/routes/marketplace/:
cards/apps/api/src/routes/marketplace/
├── authors.ts
├── decks.ts (publish, list, version reads)
├── engagement.ts (stars, subscribe, fork)
├── discussions.ts (card-discussions threads)
├── pull-requests.ts
├── moderation.ts (reports + admin)
├── purchases.ts (paid decks — dormant in R3, aktiv ab späterer Welle)
└── explore.ts (discovery + search)
Hauptserver-Mount in cards/apps/api/src/index.ts:
app.route('/api/v1/marketplace/authors', authorsRouter())
app.route('/api/v1/marketplace/decks', decksRouter())
// …
Vorteile: ein Prozess, ein Container, ein Tunnel-Endpoint
(cardecky-api.mana.how), eine JWT-Validierung, eine Drizzle-DB-Connection.
4. Frontend: additive Routes, gleicher Stack
cards/apps/web/ ist SvelteKit + Svelte 5 (runes-only). Alter
apps/cards/apps/web/ war es auch. Routen werden 1:1 übernommen,
mit drei Anpassungen:
- Imports:
@mana/shared-*kommt heute aus Verdaccio (npm.mana.how).pnpm add @mana/shared-ui@^0.1.1 @mana/shared-share-protocol …. - Theming: alte Components nutzten alte Token. Greenfield-Bridge-
Aliase in
app.cssmappen die meisten alten Token aufs 12er-Mana- Vokabular. Test im Browser, ggf. Anpassungen. - Auth-Hook:
dev-stub.svelte.tsbleibt für Phase-2-Lücke. Sobald echte mana-auth-Login-Flow ausgerollt ist (sieheSTATUS.md), weicht der Stub für@mana/shared-auth.
5. Hash-Implementierung: bestehende @cards/domain benutzen
Alter cards-server/src/lib/hash.ts: eigenständige SHA-256-Implementierung.
Greenfield: cardContentHash in @cards/domain (Web-Crypto, deterministisch).
Beim Restore: lib/hash.ts nicht mit-übernehmen, sondern
Marketplace-Code auf cardContentHash aus @cards/domain umbiegen.
Eine Hash-Definition für die ganze App.
6. mana-Service-Calls: identische Pattern
Alter cards-server rief mana-credits, mana-llm, mana-media, mana-notify
über MANA_*_URL-env-Vars. Greenfield-cards-api macht das genauso.
Code 1:1 übernehmen.
Wellen-Plan
| Welle | Zustand | Was passiert | Blocker |
|---|---|---|---|
| R0 | 🟡 in Arbeit | Doku-Restore: Archive aus cards-decommission-base + dieser Plan + Strategie-B-Klarstellung | — |
| R1 | ⏸ pending | Schema-Restore: 7 Schema-Files in cards/apps/api/src/db/schema/marketplace/, drizzle-kit push grün gegen lokale cards-DB |
R0 |
| R2 | ⏸ pending | Backend Phase α + β: Author-Profile + Publish + AI-Mod-Stub | R1 |
| R3 | ⏸ pending | Backend Phase γ + δ: Discovery + Subscribe + Smart-Merge | R2 |
| R4 | ⏸ pending | Backend Phase ε: Pull-Requests + Card-Discussions | R3 |
| R5 | ⏸ pending | Frontend-Routes: /explore, /d/[slug], /u/[slug], /me/{published,subscribed,forks} |
R4 |
| R6 | ⏸ pending | E2E-Smoke: erstes Cardecky-Deck publishen, von Till's Account subscriben, Smart-Merge testen | R5 |
Aufwand-Schätzung gesamt: ~14 Tage Real-Arbeit.
Bewusst aus dem ersten Restore-Wurf rausgelassen:
- ζ.1 Paid Decks — Schema-Tabellen kommen in R1 mit, aber Routes/UI bleiben dormant. Re-Aktivierung als eigene Welle nach Live-Validation. Begründung: mana-credits-Integration ist heikel (4-step-Pipeline mit reservation-commit-grant), Author-Erlöse sind ein Verein-Compliance- Thema (Steuern, AGB, Refund-Policy), und solange Cardecky synthetic Decks publisht, gibt's keinen Need.
- η.1 Moderation-UI — Schema-Tabellen + API-Endpoints kommen mit,
Admin-Frontend (
/admin/reports) wird ausgelassen bis erste echte User da sind. Take-Down via SQL für die ersten Wochen. - θ Deep AI (Auto-Tags, Embeddings, TTS) — bleibt explizit später- Phase, war im Original-Plan auch nicht für den ersten Wurf vorgesehen.
Cardecky-Skill-Integration
Der /cards-deck-Skill (siehe ~/.claude/skills/cards-deck/SKILL.md)
produziert Decks unter dem Cardecky-Plattform-User. Beim Marketplace-
Restore wird Cardecky automatisch zum Marketplace-Author:
- Bei R2 wird ein Init-Skript einen
marketplace.authors-Row für Cardecky-User-ID anlegen (slug='cardecky',display_name='Cardecky',pseudonym=false,verified_mana=true— der Verein vergibt das Badge an seinen eigenen KI-Author). - Skill-Stufe 5 (Publish) wird erweitert um einen optionalen Schritt:
nach Anlegen des privaten Decks kann der Skill ein
POST /api/v1/marketplace/decks/:id/publishmitsemver=1.0.0und einem auto-generierten Changelog hinterher schicken — dann ist das Deck sofort im/exploresichtbar. - Default bleibt aber „nur privat anlegen", weil:
- das Validate-Stage (Stufe 4) eine menschliche Sichtung verdient, bevor 30 Karten öffentlich werden;
- Reviewer-Stops nach Stufe 3 sind zwingend.
Der Skill braucht keine Architektur-Änderung — er addiert nur einen optionalen 6. Schritt.
Lizenz-Modell (aus dem Original übernommen)
Aus MARKETPLACE_PLAN_2026-05-07.md §3 + GUIDELINES.md:
| SPDX-ID | Erlaubt | Wann |
|---|---|---|
CC0-1.0 |
alles, kein Attribution-Pflicht | für Public-Domain-fähige Karten |
CC-BY-4.0 |
alles, mit Attribution | meist gewählt für Wissens-Decks |
CC-BY-SA-4.0 |
alles, ShareAlike + Attribution | für Wikipedia-derivierte Decks |
Cardecky-Personal-Use-1.0 |
nur persönlicher Lern-Use, kein Re-Publish | Default für kostenlose Decks |
Cardecky-Pro-Only-1.0 |
nur via Kauf, kein Re-Publish, kein Fork | Pflicht für paid Decks (DB-CHECK enforced) |
Der DB-CHECK auf decks.price_credits = 0 OR license = 'Cardecky-Pro-Only-1.0'
ist im Schema beibehalten — Code-Bug kann nicht stillschweigend ein
Paid-Deck mit CC-Lizenz publishen.
Cold-Start-Strategie (aus dem Original)
Kommt im ersten Restore-Wurf nicht aktiv zum Tragen, aber der Original- Plan §9 hat drei Hebel definiert, die bei Re-Launch greifen:
- Verein-Seed-Decks — 50 hochwertige Cardecky-published Decks
(Sprachen, Geschichte, Allgemeinwissen, Programmierung). Der
/cards-deck-Skill ist genau das Werkzeug dafür. - Anki-Top-100-Import-Service — populäre CC-BY-Anki-Decks mit
Original-Author-Attribution importieren, Original-Author bekommt
verified_mana-Badge bei Registrierung. - Influencer-Outreach — 10–20 Anki-Power-Authoren (AnKing & Konsorten) gezielt ansprechen, sehr Author-freundlicher Cut.
Hebel 2 + 3 sind Wachstumsmaßnahmen, nicht Phase-1. Hebel 1 ist sofort umsetzbar mit dem bestehenden Skill.
Anti-Patterns aus dem Original-Plan §13 (gelten weiter)
- Kein 1-5-Sterne-Rating-System. Stars (Bookmark) ja, Bewertungen nein.
- Kein Reddit-Style-Voting auf Karten/PRs/Discussions. Hacker-News-Effekt.
- Kein „Karten der Woche" allein-algorithmisch. Editorial + Trending- Liste, aber niemals reiner Algo-Feed.
- Kein Anki-Bashing im Marketing. Bridge nicht Burning.
- Keine Pflicht-Klarnamen. Pseudonyme bleiben gleichberechtigt.
- Kein Marketplace-Cut über 30 %. Standard 80/20, verified 90/10.
Offene Punkte
- PR-Merge-stale-blind aus dem Original. Bekannte Limitierung: wenn
Author zwischen PR-Open und Merge selbst eine Karte ändert, deren
previousContentHashder PR matched, gewinnt stumm der PR. Im ersten Restore-Wurf so übernehmen wie war; späterer Fix via optimistic locking aufbaseVersionIdder PR-Row mit Reject bei Mismatch. - Reconciler-Cron für Paid-Pipeline-Inkonsistenzen. Original §13a
beschreibt das Loch: bei Commit-/Grant-Failure nach Schritt 2 bleibt
eine Purchase-Row mit
creditsTransaction = null. Beim Restore initial nicht aktiv (Paid-Decks dormant), aber sobald Phase ζ reaktiviert wird, ist Reconciler ein muss-haben. cards-decommission-base-Tag im managarten-Repo. Falls jemand managarten löscht oder das Tag nochmal entfernt, geht der Restore- Pfad verloren. Empfehlung: Schema-Files + ausgewählte Code-Snippets einmal nachcards/docs/marketplace/archive/kopieren (Doks sind schon drin, Code-Files folgen optional bei R1+R2).- Schema-Migrations-Pfad bei späterer Drizzle-Version. Greenfield-
Cards plant Migration auf Drizzle 0.45/zod-4 mit der Plattform mit
(
mana/docs/MIGRATION_DRIZZLE_ZOD.md). Marketplace-Schema kommt mit Drizzle 0.38 — sollte mit upgradeen, idealerweise atomar. - Karten-Hash-Konsistenz zwischen Greenfield und Marketplace.
Greenfield-
@cards/domaincardContentHashist die SoT. Marketplace-deck_cards.content_hashmuss mit demselben Algorithmus berechnet werden — sonst funktioniert Smart-Merge nicht. Beim R2-Port-Pass testen, dasscardContentHash({type,fields})aus@cards/domainbyte-identisch ist mit dem altencards-server/src/lib/hash.ts. Wenn nicht: alten Code anpassen, nicht@cards/domainbrechen.