Commit graph

151 commits

Author SHA1 Message Date
Till JS
0667e105e5 chore(deps): bump @mana/shared-schemas to 0.1.11
Some checks are pending
CI / validate (push) Waiting to run
Forward-Fix nach versehentlichem unpublish aller älteren Versionen auf
npm.mana.how (2026-05-22). 0.1.11 enthält additive Schema-Änderungen
nur im pageta-Sub-Schema; das App-eigene Sub-Schema bleibt byte-gleich.
Kein Code-Diff erforderlich, nur Lockfile-Refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:19:19 +02:00
Till JS
916c662d58 theme: Welle 2a — all.css + ThemeToggle + Store
Some checks are pending
CI / validate (push) Waiting to run
- @mana/shared-ui ^0.1.0 → ^1.1.1
- app.css: all.css statt nur variants/forest.css
- app.html: data-theme="forest" raus, FOUC-Init-Script eingefügt
- src/lib/theme.svelte.ts: createThemeStore (anon — wordeck hat noch
  keinen echten Auth, nur dev-stub)
- +layout.svelte: theme.initialize() + floating <ThemeToggle />
  (nur außerhalb focus-mode + login-page)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:51:13 +02:00
Till JS
7980c7d0f1 deps: @mana/themes ^0.1.0 → ^0.2.0 + base.css-Import
Some checks are pending
CI / validate (push) Waiting to run
Stufe-2-Konsolidierung der UI-Pakete in mana/-Repo: themes@0.2.0
schluckt shared-tailwind. base.css bringt Tailwind-Plumbing (@theme
inline) + Brand-Literals. Forest-Variant unverändert.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 05:33:40 +02:00
Till JS
d7b220566e shared-ui: @mana/shared-ui-2 → @mana/shared-ui
shared-ui-2 wurde in mana/ zu shared-ui v1.0.0 konsolidiert
(mana@6339c48). Paket-Name jetzt einheitlich; kein API-Bruch für
diese App.
2026-05-21 04:28:49 +02:00
Till JS
cba37c3c37 fix(wordeck): pre-existing test drifts + L-2 cleanup vor Deploy
Some checks are pending
CI / validate (push) Waiting to run
- tests cards→wordeck rebrand-drift: app-name in health/search/tools/dsgvo,
  envelope to.app + service-key env-var WORDECK_DSGVO_SERVICE_KEY
  (war: CARDS_*). Test-Suite jetzt 83/83 grün.
- dsgvo.ts: ENV-Name auf WORDECK_DSGVO_SERVICE_KEY (war CARDS_*) — passt
  zum Test-Setup + wordeck-Branding
- decks.ts (web): generateDeckFromImage routet URL-only-Pfad auf
  generateDeck, File-Upload-Pfad wirft klaren Fehler (Server-Route
  existiert nicht). UI-Komponenten unverändert
- migrate-db-to-events.ts: Stub als „nicht benötigt" markiert.
  Wordeck-Production hat keine User-Daten in den obsoleten Tabellen;
  Marketplace-Decks (cardecky-User) leben in eigenem pgSchema und
  sind vom Cutover nicht betroffen

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:56:42 +02:00
Till JS
375a6af86e feat(wordeck): Big-Bang-Cutover L-2 — Server-CRUD raus, alles auf event-sync
Some checks are pending
CI / validate (push) Waiting to run
L-2 von mana/docs/playbooks/LOCAL_FIRST_LOGIN_OPTIONAL.md:

apps/api:
- routes/decks.ts: CRUD-Routes gelöscht. Verbleibend nur Read-Only:
  GET /:id/marketplace-source + GET /:deckId/distractors
- routes/cards.ts: alle CRUD-Routes → 410 Gone mit Deprecation/Sunset
  Header (Sunset 2026-06-20). Sub-Pfade weren von Hono auf das *-Handler
  geleitet, die alle 410 zurückgeben
- routes/reviews.ts: alle Routes → 410 Gone, FSRS-Compute ist jetzt
  client-side via @wordeck/domain.gradeReview
- routes/decks-generate.ts: returnt nur noch LLM-Vorschlag
  ({ suggestion: { deck, cards } }), Server schreibt NICHTS mehr in
  decks/cards/reviews. Client emittet Events lokal in event-sync
- routes/dsgvo.ts: Doku-Block: nach Big-Bang sind neue User-Daten in
  sync2 mana_sync_v2.wordeck.*, nicht mehr hier. mana-admin-Fanout
  muss beide Quellen abfragen
- scripts/migrate-db-to-events.ts: Stub für DB→Event-Sync-Migration.
  Idempotent via idempotencyKey='migration:<row-id>:<event-type>'.
  Plaintext-Migration (kein User-Master-Key zur Migration-Zeit),
  --dry-run/--commit, --user-id-Filter. mintToken() noch als Stub
  (braucht Service-Key-basierten JWT-Mint in mana-auth)

apps/web:
- lib/api/decks.ts: generateDeck wrapped jetzt den Server-Vorschlag
  via lokales createDeck + createCard-Burst. UI sieht weiterhin
  { deck, cards_created } als Return-Shape

apps/api/tests:
- decks.test.ts: post-cutover-Smokes (Auth-Check + 404 für entfernte
  Routes)
- cards.test.ts: 410-Gone-Verification mit Deprecation-Header
- reviews.test.ts: 410-Gone-Verification

Type-check 0 Errors. Test-Suite: pre-existing fails (dsgvo, share,
tools — alle pre-cutover schon rot, Rebrand-Drift cards→wordeck);
meine drei Big-Bang-Tests-Files 7/7 grün.

Offene Punkte (bewusst geflaggt, nicht Big-Bang-Block):
- DSGVO-Pfad cross-source-Aggregation (sync2 + DB) ist mana-admin's
  Architektur-Job, nicht wordeck-app
- Migration-Script mintToken() braucht mana-auth-Service-Key-Pfad
  oder sync2-Service-Key-Auth-Mode (Plattform-Arbeit)
- Live-User-Migration: Skript-Stub ist ungetestet, muss vor echtem
  Run code-reviewed + 1-2 User-Dry-Runs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:51:22 +02:00
Till JS
bebd182540 feat(wordeck): L-1f Phase C — public-feed-Endpoint + DSE für lokale Speicherung
Some checks are pending
CI / validate (push) Waiting to run
apps/api:
- neue Route GET /api/v1/public/feed?cursor=<opaque>&limit=20
- Plattform-Konvention aus LOCAL_FIRST_LOGIN_OPTIONAL.md §3 D
- Shape: { items: [{ id, type:'deck', slug, title, excerpt, author,
  publishedAt, stats }], nextCursor: <opaque> | null }
- Quelle: marketplace.public_decks (is_takedown=false), sortiert
  nach createdAt desc — Aggregatoren wie hub.mana.how/timeline
  konsumieren genau diese Shape

apps/web/datenschutz:
- neue Sektion 7a „Lokale Daten + anonyme Nutzung" mit Hinweisen auf
  IndexedDB-DB-Name manasync_wordeck, anonyme Geräte-ID anon:<ulid>,
  Sign-In-Lift mit AES-GCM-256-Vault-Verschlüsselung, Browser-Reset-
  Risiko bei anonymer Nutzung
- alter sql-wasm-Hinweis raus (Wordeck nutzt jetzt event-sync, kein
  sql-wasm mehr)

Verbleibend für Live-Smoke (Till manuell):
- wordeck.com lädt → /decks ohne Login (anonymous-Mode)
- Deck anlegen → IndexedDB manasync_wordeck zeigt Event
- Login → Re-Tagging-Sweep + Push zu sync2.mana.how
- /api/v1/public/feed Smoke (oder über hub.mana.how)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:40:49 +02:00
Till JS
e0605b2f2e feat(landing): Marketing-Astro auf wordeck.com LIVE
Some checks are pending
CI / validate (push) Waiting to run
Astro-Landing als neuer Apex-Container (:3202), gebaut mit
@mana/marketing-kit. Probe-Cutover der Welle-1-Charge (niedrigstes
Compliance-Risiko, höchste Ship-Reife). Anki-Migration als
Akquise-Anker; /anki-import als dedicated Long-Tail-Page mit
3-Schritt-Anleitung + FAQ + JSON-LD FAQPage (Sitemap-Priorität 0.95).

- apps/landing/ — index, anki-import, ueber, mitwirken
  + robots/llms/sitemap-Endpoints
- infrastructure/macmini/docker-compose.landing.yml — Port 3202
- .gitignore += .astro

Cutover-Playbook: mana/docs/playbooks/LANDING_CUTOVER.md
Domain-Status:
  wordeck.com          → :3202  (Marketing, NEU)
  www.wordeck.com      → :3202  (Marketing, NEU)
  app.wordeck.com      → :5181  (Web-App, NEU als Subdomain)
  api.wordeck.com      → :3191  (API, unverändert)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:38:41 +02:00
Till JS
823560900c feat(web): event-sync migration L-1f Phase B — anonymous-mode + lokal-first CRUD
Some checks are pending
CI / validate (push) Waiting to run
L-1f Phase B von mana/docs/playbooks/LOCAL_FIRST_LOGIN_OPTIONAL.md:

apps/web:
- neue Foundation: lib/sync.svelte.ts mit @mana/event-sync v0.5.0,
  Vault-Crypto via createMasterKeyProviderFromVault, anonymous-Mode
  aktiv (getToken returnt null bis Login)
- lib/api/event-adapters.ts: konvertiert WordeckDeckState/CardState/
  ReviewState (camelCase, event-sourced) → Deck/Card/Review
  (snake_case, @wordeck/domain), stable aggregate-id-Helpers
- lib/api/event-builder.ts: baut EventEnvelope mit aktuellem
  attributedToUserId (real-user-id wenn signed-in, anon:<ulid> sonst)
- lib/api/decks.ts: list/get/create/update/delete/archive auf event-sync.
  Marketplace-Source, duplicate, AI-generate bleiben HTTP (cross-user
  bzw. Tier-gated, Server-AI-Calls)
- lib/api/cards.ts: list/get/create/update/delete auf event-sync,
  Review-Init-Events beim CardCreate (basic-reverse → 2 Reviews),
  content_hash client-side via @wordeck/domain
- lib/api/reviews.ts: listDueReviews via aggregateList, gradeReview
  rechnet FSRS client-side via @wordeck/domain.gradeReview, emittet
  ReviewGraded mit prevSnapshotJson für undo
- routes/+page.svelte: kein redirect-to-/login mehr — direkt /decks
  (anonymous-Mode trägt's)
- routes/auth/callback: ruft onSignedIn(realUserId) für anonyme→real
  Re-Tagging der Outbox + EventLog

shared-schemas/wordeck:
- CardType-Korrektur: 'type-in' → 'typing' (matched @wordeck/domain
  CardType-Schema). Schema-Hash neu: da67d23cf100…, re-published auf
  sync2.mana.how + @mana/shared-schemas@0.1.10

Verbleibend für L-1f Phase C (nächste Session):
- Wordeck-API server-seitige Routes auf Read-Only-Projektion umstellen
  (heute noch Read+Write, wir lassen es da bis wir sicher sind dass
  event-sync stabil läuft)
- /api/v1/public/feed Endpoint (oder Marketplace-Alias)
- DSE-Update (lokale Speicherung, anonyme Nutzung erwähnen)
- Live-Smoke auf wordeck.com

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 21:37:34 +02:00
Till JS
2ee706bab1 fix(manifest): base_url auf api.wordeck.com — wordeck.com ist Web, hat kein /healthz
Some checks are pending
CI / validate (push) Waiting to run
Vor dem Rebrand zeigte base_url auf cardecky.mana.how (war API+Web im
gleichen Container). Mit dem Switch wurde cardecky.mana.how zur 301-
Redirect-Stub, wordeck.com läuft als reines SvelteKit-Web — kein
/healthz, kein /api/v1/*. Damit liefen alle Manifest-Endpoints (health,
search, share/receive, tools, dsgvo) ins Leere.

Korrekt ist https://api.wordeck.com (Container kreisel… nein,
cards-api auf :3191, ingress in managarten cloudflared-config).
mana-share-Health-Cron sah dadurch wordeck als failed=1 — nach
Re-Registrierung mit korrektem base_url ist OK erwartet beim
nächsten Cron-Tick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:54:44 +02:00
Till JS
428b3d8b68 chore: gitignore .npmrc — Verdaccio-Token soll nie in git 2026-05-20 16:53:00 +02:00
Till JS
332e27df14 fix(api): 0004-Migration referenziert wordeck-Schema (war: cards)
Some checks are pending
CI / validate (push) Waiting to run
Die Text-Only-Cutoff-Migration aus dem Rebrand-Lift schrieb gegen
\"cards\".\"cards\" — historischer Pre-Rebrand-Schema-Name. Auf prod
heißt das Schema seit Phase 0 `wordeck`. Drizzle-Migrator crashte
mit `relation \"cards.cards\" does not exist`.

Alle 6 cards.X-References auf wordeck.X umgeschrieben. Migration
bleibt idempotent (IF EXISTS / DO-BLOCK), Re-Run harmlos.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:07:22 +02:00
Till JS
03485ec780 fix(api): 0004_wordeck_text_only + 0005_wordeck_license_rename ins Journal
Some checks are pending
CI / validate (push) Waiting to run
SQL-Files lagen seit dem Rebrand-Lift im Repo, fehlten aber in
meta/_journal.json — drizzle-migrator iteriert nur Journal-Entries
und hat die zwei ignoriert. Resultat: Wordeck-Rebrand-Constraints
(text-only CHECK, neue License-Strings) waren auf prod nicht angewandt.

Beide Migrations sind idempotent (IF EXISTS / IF NOT EXISTS), beim
nächsten Container-Boot greift der migrate-Hook und führt sie aus.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:05:13 +02:00
Till JS
9a735d0a2b fix(api): vi.fn() in lib-url-fetch.test typt zu typeof fetch
Some checks are pending
CI / validate (push) Waiting to run
5 tsc-Errors „Property 'preconnect' is missing in type Mock". Bun's
`typeof fetch` deklariert eine `preconnect(url, options)`-Methode,
vitests `vi.fn()`-Mock hat die nicht. Cast über `unknown` umgeht den
strikten Type-Check, ohne den Mock künstlich aufzublähen.

- makeFetch() bekommt `typeof globalThis.fetch` als Return-Type
- direkter inline-vi.fn().mockRejectedValue() cast'd am Use-Site
- 6/6 Tests grün

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:07:14 +02:00
Till JS
90816de934 feat(api): Auto-Apply von Drizzle-Migrations beim Boot
Some checks are pending
CI / validate (push) Waiting to run
Folge-Adoption nach Pageta (mana/docs/playbooks/MIGRATIONS_BOOTSTRAP.md).
Versionierte Migrations lagen schon im Repo (src/db/migrations/), aber
ohne Auto-Apply-Hook würde ein Volume-Reset die DB schema-leer lassen
und Container-Restart liefe dann auf 500er gegen fehlende Tabellen.

- src/db/migrate.ts (runMigrations-Helper mit onnotice-Suppress)
- src/index.ts top-level-await Hook hinter _RUN_MIGRATIONS
- infrastructure/docker-compose.production.yml: _RUN_MIGRATIONS='true'

Idempotent über drizzle.__drizzle_migrations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:30:06 +02:00
Till JS
56de993fc3 fix(web): prerender /offline für Workbox-Precache
Some checks are pending
CI / validate (push) Waiting to run
Workbox wirft `non-precached-url: /offline` beim SW-Register, weil
`createPWAConfig()` aus @mana/shared-pwa `navigateFallback: '/offline'`
setzt, SvelteKit aber nur prerendertes HTML in den Precache aufnimmt
(`**/*.html`-Glob → `prerendered/offline.html`).

`+page.ts` mit `export const prerender = true;` landet die statische
Offline-Page im Precache. Sweep über alle 10 shared-pwa-Konsumenten —
selber Bug latent überall identisch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:11:58 +02:00
Till JS
2b35168d38 fix(ui): Marketplace-Stack + Mehr-laden-Button + Header-Logo
Some checks are pending
CI / validate (push) Waiting to run
- MarketplaceDeckStack: cover-desc auf 6 Zeilen geclampt
  (vorher unbegrenzt, lange Beschreibungen überlagerten den Titel
  visuell und wurden hart vom overflow:hidden abgeschnitten).
- Explore: "Mehr laden"-Button von full-width-Border auf
  zentriertes Pill mit Primary-Fill, mit "X von Y"-Counter
  drüber. Vorher kaum sichtbar.
- Header: "C"-Logo (Cards-Rebrand-Rest) auf "W" gesetzt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:44:40 +02:00
Till JS
cb5d23ec03 chore(web): bump @mana/shared-pwa zu 0.1.0-alpha.5
Some checks are pending
CI / validate (push) Waiting to run
Neuer PWA-Install-Banner mit App-Icon, Titel + Erklärungstext und
Icons in den Buttons.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:28:35 +02:00
Till JS
fa5da8e937 fix(api): API_BASE liest PUBLIC_WORDECK_API_URL statt PUBLIC_CARDS_API_URL
Some checks are pending
CI / validate (push) Waiting to run
Rebrand-Rest aus dem Cards-Cutover: client.ts las noch den alten
PUBLIC_CARDS_API_URL, die Production-Compose exportiert aber
PUBLIC_WORDECK_API_URL. Folge: das Web-Bundle fiel auf den
Dev-Default localhost:3081 zurück und alle API-Calls liefen ins
Leere (Deck-Liste, Marketplace).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:25:56 +02:00
Till JS
65091e3a12 fix(auth): app-Slug 'cards' → 'wordeck' im Login-Redirect
Some checks are pending
CI / validate (push) Waiting to run
wordeck-web schickte bisher `?app=cards` ans zentrale Auth-Portal —
nach Login wurde wordeck.com nicht zurückgereicht, weil cards'
Allowlist nur cardecky.mana.how kennt. Mit dem neuen Wordeck-App-
Eintrag in mana@e9e78c0 funktioniert der Redirect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:14:14 +02:00
Till JS
9c1ee67f69 feat(web): OfflineFallback aus @mana/shared-pwa adoptiert
Some checks are pending
CI / validate (push) Waiting to run
~25 LOC eigene Offline-Page → 5 LOC shared-Component-Use. Pattern
für alle 10 mana-Apps konsistent (Nutriphi-Pilot, dann Welle).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 15:03:20 +02:00
Till JS
1bd1d5dcbf feat(layout): Datenschutz-Link im Footer
Some checks are pending
CI / validate (push) Waiting to run
User müssen die DSE finden, sonst nutzen die 10 Erst-Entwürfe nichts.
Pro App ein <footer> mit /datenschutz-Link (Nutriphi hatte das schon
als Vorbild).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:44:20 +02:00
Till JS
19ceda8627 docs(datenschutz): §7 wahrheitsgemäß — mana-share speichert vollen Payload
Some checks are pending
CI / validate (push) Waiting to run
N3-Audit durch mana-architect 2026-05-19: mana-share.envelopes speichert
payload_jsonb + user_note + source_link (Retention 730 Tage,
DSGVO-Anonymisierung on-demand). „kein Inhalt" wäre Falschangabe
nach Art. 13/14 DSGVO.

§7 (Konten-Föderation) ehrlich angepasst auf: „der geteilte Inhalt
selbst inkl. optional User-Notiz und Quell-Link, Speicherdauer bis
730 Tage mit Anonymisierung danach".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:29:09 +02:00
Till JS
7a0448c156 docs(datenschutz): Erst-Entwurf nach Vorlage V2
Some checks are pending
CI / validate (push) Waiting to run
Spaced-Repetition-spezifisch + Marketplace: decks/cards/reviews/
studySessions/tags/imports privat (lit. b), Marketplace-Veröffent-
lichung als Opt-in (lit. a, Widerruf möglich). Text-only-Architektur
explizit (kein Bild/Audio nach Cards→Wordeck-Rebrand). Public-Tier
also kein Beta-Hinweis. Doppel-Domain wordeck.com + cards.mana.how
mit SSO-Hinweis.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 12:35:58 +02:00
Till JS
55bf722761 feat(web): Auth-Session über @mana/shared-auth-sso
Some checks are pending
CI / validate (push) Waiting to run
devUser ist jetzt Wrapper um die shared SsoSession. App-spezifisch
bleiben stubId + patchProfile() (lokales Profil-Update). 201 LOC → 123 LOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:31:02 +02:00
Till JS
633f051f2d feat(web): PWA-Setup über @mana/shared-pwa (Adoption #9)
Some checks are pending
CI / validate (push) Waiting to run
createOfflineFirstPWAConfig — schließt sql-wasm.wasm aus dem Precache
(Wordeck nutzt sql.js für lokales Spaced-Repetition). themeBridge('forest')
#117e39 passend zum data-theme='forest'. 2 Shortcuts (Decks + Entdecken).
OfflineBanner/UpdatePrompt/InstallPrompt unter skip-link. Icons aus
wordeck-native AppIcon-1024.

Build grün.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:44:38 +02:00
Till JS
b13c9dd914 fix(marketplace): credits-client camelCase + grant() + referenceId
Some checks are pending
CI / validate (push) Waiting to run
Validierung gegen mana-credits internalReserveSchema /
internalGrantSchema:

- snake_case → camelCase (userId, appId, reservationId, referenceId)
  Vorher hätte jeder reserve-Call 400 geworfen — fiel nicht auf, weil
  Paid-Decks dormant sind.
- grant()-Methode neu: für Author-Payouts beim Paid-Deck-Live-Schalten.
  Braucht referenceId (Pflicht, max 128 chars) + reason (max 64).
- appId 'wordeck' statt 'cards' (Brand-Konsistenz mit ev.mana.wordeck-
  Rebrand 2026-05-17).
- commit() akzeptiert optionalen description-Parameter.
- Response-Type: reservationId/grantId statt snake_case.

Bereitet den Live-Bezahl-Flow vor (immer noch dormant). Synchron mit
Comicello-Fix vom 2026-05-19.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:11:05 +02:00
Till JS
070cb44de8 feat(aura): onboarding.first_use (+25) hook in JWT-Branch
Some checks are pending
CI / validate (push) Waiting to run
Cross-App-Hook nach Pageta-Pattern. context.app='wordeck' im Payload.
Bewusst NICHT im dev-stub-Branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 12:52:29 +02:00
Till JS
1743fe6453 docs(status): Title cards → Wordeck
Some checks are pending
CI / validate (push) Waiting to run
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 23:25:41 +02:00
Till JS
2473ccd65d fix(dockerfiles): packages/cards-domain → wordeck-domain
Some checks are pending
CI / validate (push) Waiting to run
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 22:40:31 +02:00
Till JS
372832d266 refactor(big-bang): cards → wordeck im gesamten Code-Layer
Some checks are pending
CI / validate (push) Waiting to run
Phase 2 des cards→wordeck Big-Bang-Rebrand:

- 4 package.json: @cards/* → @wordeck/*
- packages/cards-domain/ → packages/wordeck-domain/
- 41+12 Files: from '@cards/domain' → '@wordeck/domain'
- pgSchema('cards') → pgSchema('wordeck') (Drizzle-Schema)
- 17 Files: process.env.CARDS_* → process.env.WORDECK_*
- docker-compose Service-Names: cards-* → wordeck-*
- docker-compose Volume: /Volumes/ManaData/cards → wordeck
- env-vars in compose: CARDS_DB_PASSWORD/_API_VERSION/_DSGVO_SERVICE_KEY etc. → WORDECK_*
- Log-Prefixes + Error-Strings + manifest-id 'cards' → 'wordeck'
- CORS-Origin cardecky.mana.how → wordeck.com
- .env.production.example umbenannt + S3-Key entfernt (kein MinIO mehr)

Type-Check 0 Errors in api+domain+web, 51/51 Domain-Tests grün.

DB-Rename + Container/Volume-Rename auf mana-server folgen in nächstem
Commit nach Verzeichnis-Rename.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 22:39:42 +02:00
Till JS
c77100e85a chore: stale Cardecky-Refs entfernt + apps/landing/ gelöscht
Some checks are pending
CI / validate (push) Waiting to run
- apps/landing/ entfernt (Cardecky-Marketing-Astro-Site, war nie
  deployed — der nginx-Block in landings.conf zeigte auf einen
  Pfad ohne Inhalt)
- Stale Doc-Kommentare in api+web: Cardecky → Wordeck wo passend
- fsrs.ts subIndexCount: image-occlusion + audio-front Cases raus
  (CardType-Enum hat sie nicht mehr — der throw wäre toter Code)
- fork.ts: image-occlusion-Sonderfall in subIndexCountFor weg
- cards-domain tests: schemas-Test prüft jetzt Wordeck-Typen + dass
  image-occlusion/audio-front ABGELEHNT werden
- cards-domain tests: image-occlusion-throw-Test entfernt
- api tests/cards.test.ts: 3 image-occlusion-Cases zu 1 negative
  Tested (422 expected, weil Schema sie verbietet)

51 Tests grün (cards-domain).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:58:52 +02:00
Till JS
9b37243b1d docs: STATUS auf Wordeck-LIVE-Stand
Some checks are pending
CI / validate (push) Waiting to run
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:27:12 +02:00
Till JS
17bf6f4d66 fix(migration): 0004 droppt auch cards.media_refs (separate Tabelle, nicht nur Spalte)
Some checks are pending
CI / validate (push) Waiting to run
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:26:27 +02:00
Till JS
e3c84a9249 feat(text-only): Wordeck-Cutoff für Image-Occlusion + Audio + MinIO
Some checks are pending
CI / validate (push) Waiting to run
Ω-1: Text-Only-Architektur ist scharfgestellt.

Code-Cleanup:
- 4 Components gelöscht: ImageOcclusionEditor, ImageOcclusionView,
  AudioFrontView, AudioUploadField
- 3 API-Module gelöscht: routes/media.ts, services/storage.ts,
  db/schema/media.ts (mediaRefs + mediaFiles), routes/decks-from-image.ts
- packages/cards-domain: image-occlusion.ts + Tests entfernt,
  CardTypeSchema reduziert auf basic/basic-reverse/cloze/typing/multiple-choice
- 3 Web-Routes (study/[deckId], cards/new, cards/[id]/edit) bereinigt:
  Image-Occlusion- und Audio-Front-Code-Pfade raus
- anki/import.ts text-only: kein Media-Upload mehr, img/sound werden
  ersatzlos gestrippt
- 21 weitere Files bereinigt: dto, health, me, dsgvo, tools, cards,
  decks, share-handlers, marketplace/decks, marketplace/fork,
  marketplace/pull-requests, AnkiImport.svelte

DB-Migrationen (noch nicht gerannt, idempotent):
- 0004_wordeck_text_only.sql: DELETE image-occlusion/audio (0 betroffene
  Rows), media_files-Tabelle DROP, media_refs-Spalte DROP, CHECK
  cards.type IN (basic, basic-reverse, cloze, type-in, multiple-choice)
- 0005_wordeck_license_rename.sql: Cardecky-Personal-Use-1.0 →
  Wordeck-Personal-Use-1.0, Cardecky-Pro-Only-1.0 → Wordeck-Pro-Only-1.0,
  Default + CHECK + Backfill

Infrastruktur:
- docker-compose.production.yml: cards-minio-Service raus, MinIO-Envs
  aus cards-api raus, CARDS_PUBLIC_URL + PUBLIC_CARDS_API_URL auf
  wordeck.com / api.wordeck.com
- App-Manifest schon vorher auf wordeck umgestellt

Type-Check grün (api, domain, web — alle 3 Sub-Pakete).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:23:30 +02:00
Till JS
1228eb4692 fix(web): app.html default-title Cards → Wordeck
Some checks are pending
CI / validate (push) Waiting to run
Vergessener Branding-Stelle aus Bulk-Rename. Der app.html-Title
greift bei Seiten ohne expliziten <svelte:head><title>.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:49:15 +02:00
Till JS
39fe22a018 feat: Wordeck-Web-Branding + Manifest-Cutover
Some checks are pending
CI / validate (push) Waiting to run
Cards-zu-Wordeck-Umbennung im Web-Layer komplett:

- app-manifest.json: id, name, homepage, icon, base_url, deep_link_scheme,
  link_patterns alle auf wordeck. tools[].name auch (cards.create →
  wordeck.create — bei mana-mcp wird das beim re-upsert konsumiert).
- 5 i18n-Files (de/en/fr/es/it): App-Beschreibung von Cardecky-zu-Wordeck-
  Wording, USP "text-first" wo es passt.
- 11 Routes mit Page-<title>: Cardecky → Wordeck.
- CSP connect-src ergänzt um api.wordeck.com (cardecky-api bleibt während
  Übergang).
- AASA exposed jetzt BEIDE Bundle-IDs (ev.mana.cardecky alt + ev.mana.wordeck
  neu) — die alte Native bleibt während der Ω-3 Bauphase funktional.
- UI-Slug-Vorschau (PublishDeckModal, +page, me/published): wordeck.com.

DNS für wordeck.com + api.wordeck.com + www.wordeck.com sind als
Cloudflare-Tunnel-CNAMEs angelegt; cloudflared-Ingress auf mana-server
patched + reloaded. wordeck.com antwortet HTTP 200 mit Cards-Container
(Branding-Update hier macht das jetzt zu Wordeck).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:46:10 +02:00
Till JS
22927fbe59 feat: Wordeck-Vorarbeiten — Datenschutz-Seite + Text-Only-Migration
Some checks are pending
CI / validate (push) Waiting to run
Privacy/+page.svelte: Cards → Wordeck, MinIO-Erwähnung entfernt
(text-only, kein Object-Storage), Bilder/Audio explizit als
"speichern wir NICHT" markiert, Bundle ev.mana.wordeck.

0004_wordeck_text_only.sql: Migration für CardType-Cutoff
(image-occlusion/audio raus, CHECK-Constraint, media_files-DROP).
Vor-Audit gegen prod hat 0 betroffene Karten gezeigt — die Migration
ist defensiv und idempotent, kann ohne Daten-Verlust gefahren werden.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:36:20 +02:00
Till JS
29351f881d docs(content-plan): Author-Slug von cardecky zu wordeck migriert
Some checks are pending
CI / validate (push) Waiting to run
Big-Bang Author-Slug-Migration vollzogen am 2026-05-17:
- /u/wordeck/<slug> → 200 (alle 43 Decks)
- /u/cardecky/<slug> → 404 (URL-Bruch akzeptiert)
- Login-Email cardecky@mana.how bleibt (technische Identität)
- owner_user_id der Decks unverändert (Join läuft über User-ID)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:32:59 +02:00
Till JS
4c0eb0a7b1 docs: Cards-Rebrand zu Wordeck angekündigt
Some checks are pending
CI / validate (push) Waiting to run
Brand-Wechsel zu Wordeck (wordeck.com) ist beschlossen (2026-05-17).
Wordeck wird text-only — image-occlusion und audio fallen weg, neuer
iOS-Bundle ev.mana.wordeck, Pre-Cutover-Export für betroffene User.

- STATUS.md: Banner am Anfang mit Verweis auf das Playbook
- CLAUDE.md: neue Architektur-Invariante 0 (Text-only)
- CONTENT_PLAN.md: Owner-Slug cardecky bleibt, Brand-Wechsel-Notice

Vollständiger Plan: mana/docs/playbooks/WORDECK_REBRAND.md (eigener
Commit im mana-Repo).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 19:54:47 +02:00
Till JS
f3445a8f9d docs(content-plan): Phase-1-Seed komplett — 20/20 Tier-A live + 5 Tier-B-Bonus
Some checks are pending
CI / validate (push) Waiting to run
Tracking-Update nach der Cardecky-Content-Welle vom 2026-05-17. Alle
Phase-1-Tier-A-Decks aus §8 (Naturwissenschaften, Sprache, Mathe,
Geografie/Geschichte) sind jetzt im Marketplace . Dazu 5 neue
Tier-B-Bonus-Decks (B-16..B-20): Schweizer Kantone, Helvetismen,
Informatik Sek 1, Italienisch A2 (534), Latein-Grundwortschatz (199).

Marketplace-Stand: 43 Decks · 5572 Karten · 100 % kategorisiert
(language/science/math/history/technology). Audit-Trail pro Deck
liegt außerhalb des Repos in ~/Documents/cards-drafts/ (laut
Cardecky-Skill-Konvention).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 19:42:04 +02:00
Till JS
ac05afa93e devlog: 6 Tage geschrieben (Greenfield → Hardening + Cardecky-Native-Vorbereitung)
Some checks failed
CI / validate (push) Has been cancelled
Tag 1: Phase 0–10c Marathon, Live-Cut auf cardecky.mana.how.
Tag 2: Marketplace-Restore (Phase 12 R0–R5 + G1–G4).
Tag 3: Karten-Typ-Vollausbau (Periodensystem, audio, typing,
multiple-choice, Vision-LLM-Deck-Generation).
Tag 4: Mobile-Nav + 5 Sprachen + CSV/PDF + Astro-Landing.
Tag 5: Security-Hardening (fail-secure, CSP, DSGVO-Audit,
rate-limit) + Leech-Detection + AASA.
Tag 6: Recovery + Undo + FSRS-Slider + Streak + Stats-Charts +
Blog + Marketplace-Report + Privacy/Help.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 22:23:29 +02:00
Till JS
ff00c7d961 feat(marketplace): Deck-Report + Author-Block + me/decks-Endpoints
Some checks failed
CI / validate (push) Has been cancelled
Cardecky-Marketplace bekommt die App-Store-Guideline-5.1.1(v)-
Pflicht-Komponenten für User-Generated-Content: User können einzelne
Decks melden und Authors blockieren. Plus `GET /me/decks` für den
Native-Re-Publish-Flow.

Schema (Migration 0003)
- Neue Tabelle `marketplace.author_blocks (blocker_user_id,
  blocked_user_id, created_at)` mit Unique-Index auf dem Tupel
- `deckReports` lag schon im Schema, jetzt erstmals durch Routes
  erreichbar

Routes
- POST /api/v1/marketplace/decks/:slug/report — auth, 10/min Rate-
  Limit, Kategorie-Enum (spam, copyright, nsfw, misinformation, hate,
  other), optional `body` ≤ 1000 Zeichen. Idempotent pro (deck,
  reporter, category): doppeltes Melden liefert `already_reported:
  true` ohne Fehler. Owner darf eigenes Deck nicht melden.
- POST /api/v1/marketplace/authors/:slug/block — idempotent
  (onConflictDoNothing). Self-Block geht 422.
- DELETE /api/v1/marketplace/authors/:slug/block
- GET /api/v1/marketplace/me/blocks — eigene Block-Liste mit
  display_name + blocked_at
- GET /api/v1/marketplace/me/decks — eigene Marketplace-Decks mit
  latest_version (semver, card_count, published_at). Native nutzt das
  für die „Neue Version"-Auswahl im Publish-Flow

Listing-Filter
- explore.ts: `browseImpl` nimmt `signedInUserId?` und filtert
  blockierte Author-Decks per `NOT EXISTS`. Wirkt auf /explore +
  /decks (Browse mit Filtern)
- decks.ts: `GET /:slug` returnt 404 wenn der Viewer den Author
  blockiert hat — bewusst 404 statt 403, UGC-Block soll ohne Hinweis
  auf den Block wirken

Mount: zwei neue Router auf /api/v1/marketplace (moderation) und
/api/v1/marketplace/me. 104/104 Vitest-Tests grün.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 02:04:54 +02:00
Till JS
eb39faddb3 feat(web): /auth/reset + /auth/verify als Fallback-Pages
Some checks are pending
CI / validate (push) Waiting to run
Wenn der Reset-Link aus der Email auf einem Gerät ohne installierte
Cardecky-iOS-App geöffnet wird (Desktop, Android, iOS-ohne-App),
fängt Apple den Universal-Link nicht ab — der Browser landet auf
cardecky.mana.how/auth/reset. Heute = 404.

Diese minimalen Brücken redirecten den Token an die jeweilige
auth.mana.how-Surface, damit der Reset/Verify-Flow trotzdem durchläuft:

  cardecky.mana.how/auth/reset?token=X
    → auth.mana.how/reset-password?token=X (Web-Reset-Formular)

  cardecky.mana.how/auth/verify?token=X
    → auth.mana.how/api/auth/verify-email?token=X (Better-Auth-Endpoint)

iOS mit installierter App: Universal-Link greift, Browser-Page wird
nie gerendert.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 21:18:44 +02:00
Till JS
8c7c8c9c98 feat(aasa): /auth/* in Universal-Link-Paths
Reset- und Verify-Mails aus mana-auth zeigen jetzt direkt auf
cardecky.mana.how/auth/reset?token=… — damit der iOS-Universal-Link
greift, muss /auth/* in der AASA-Paths-Liste sein.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 21:16:58 +02:00
Till JS
4d905bb4cd fix(api): 0002_decks_archived_at — schließt Schema-Drift
Some checks are pending
CI / validate (push) Waiting to run
Production-DB hatte cards.decks.archived_at nicht, obwohl 0000_baseline
die Spalte im CREATE TABLE hat. Ursache: Schema-Datei wurde nach
initialer DB-Provisionierung um archived_at erweitert, ohne separate
ADD-COLUMN-Migration zu generieren. Resultat: cards-native
DeckListView triggert GET /api/v1/decks → isNull(decks.archivedAt) →
PostgresError → HTTP 500.

Fix:
- 0002_decks_archived_at.sql mit ALTER TABLE IF NOT EXISTS (idempotent)
- _journal.json updaten
- Auf Production manuell schon angewandt 2026-05-13 — diese Migration
  ist nur für fresh Setups + Migration-State-Konsistenz

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 15:32:25 +02:00
Till JS
c6488c0b83 feat(web): /privacy + /help Stubs für App-Store-Submission
Some checks are pending
CI / validate (push) Waiting to run
Apple verlangt für jede App-Store-Submission verlinkte Privacy-Policy
und Support-Page. Beide jetzt als SvelteKit-Routes mit Verein-Content.

/privacy:
- Was wir speichern (Account/Inhalte/Reviews/Server-Logs)
- Was wir NICHT machen (kein Ad-Tracking, kein SaaS-Crashreporter)
- Welche Dienste (Cloudflare-Tunnel, Eigenhosting)
- DSGVO-Rechte (Export, Löschung)
- Native-App-Spezifika (SwiftData-Cache, Keychain)

/help:
- Kontakt kontakt@mana-ev.ch
- FAQ (FSRS, Anki-Import, Offline, Marketplace, Mitmachen)
- Bug-Report-Anleitung

Beide nutzen die 12-Token-CSS-Vars (--color-foreground etc.) für
Theme-Konsistenz.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:10:45 +02:00
Till JS
abf493aeec feat(cards): recovery mode, undo, FSRS slider, streak header, stats charts, blog
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>
2026-05-13 13:37:03 +02:00
Till JS
21ec535173 fix(web): AASA bundleId ev.mana.cards → ev.mana.cardecky
Some checks are pending
CI / validate (push) Waiting to run
App-ID im Apple-Developer-Portal heißt ev.mana.cardecky (analog
zur Brand cardecky.mana.how). AASA-appID nachgezogen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:26:43 +02:00
Till JS
e68d53bfbb feat(infra): PUBLIC_APPLE_TEAM_ID für AASA-Endpoint
Some checks are pending
CI / validate (push) Waiting to run
mana e.V. Apple-Developer-Team-ID QP3GLU8PH3 ins cards-web-Service-
Environment in docker-compose.production.yml. Wird zur Runtime von
$env/dynamic/public aufgelöst und in
/.well-known/apple-app-site-association eingesetzt — Apple matched
das mit dem applinks:cardecky.mana.how-Entitlement in cards-native
(Bundle ev.mana.cards).

Aktivierung: docker compose -f docker-compose.production.yml up -d cards-web
auf mana-server. Verify nach Deploy:
  curl https://cardecky.mana.how/.well-known/apple-app-site-association
  → "appID":"QP3GLU8PH3.ev.mana.cards" statt XXXXXXXXXX.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:17:27 +02:00