wordeck-native/CLAUDE.md
Till JS 542082772a refactor(big-bang): cards-native → wordeck-native
Code + Identity-Rename zur Vorbereitung auf Apple-Dev-Portal-Aktion
(Bundle ev.mana.wordeck, App-Group group.ev.mana.wordeck, AASA
applinks:wordeck.com). Build bleibt funktional, aber gegen die
neue text-only-API können image-occlusion-Creates 422 zurückgeben —
das wird mit der Wordeck-Native v1.0-Welle (parallele Apple-Aktion)
sauber gemacht.

Umbenennung:
- 41 Files: cardecky/Cardecky → wordeck/Wordeck (Display, Strings,
  Kommentare)
- 57 Files: CardsNative → WordeckNative, CardsAPI → WordeckAPI,
  CardsTheme → WordeckTheme, CardsBrand → WordeckBrand, CardsWidget →
  WordeckWidget, CardsDueWidget → WordeckDueWidget
- Bundle-ID ev.mana.cardecky → ev.mana.wordeck (project.yml,
  Info.plist, entitlements, Keychain-Service, App-Group)
- AASA applinks:cardecky.mana.how → applinks:wordeck.com
- API-Base cardecky-api.mana.how → api.wordeck.com
- 10 Files renamed (App-Entry, API-Extensions, Theme, Widget,
  Entitlements, Tests)
- xcodeproj regenerated via xcodegen → WordeckNative.xcodeproj
- MaskRegionsTests.swift gelöscht (image-occlusion entfällt mit
  Wordeck text-only)

Forgejo-Repo git.mana.how/till/cards-native → wordeck-native umbenannt
(Auto-Redirect aktiv). Lokales Verzeichnis Code/cards-native/ bleibt
vorerst — wird beim nächsten Apple-Setup mit Bundle-Test umbenannt.

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

7.3 KiB

CLAUDE.md — wordeck-native repo

Guidance für Claude Code in diesem Repository.

Wenn du gerade neu bist: lies zuerst PLAN.md und ../mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md (übergeordneter Greenfield-Plan). Dieses CLAUDE.md ist die Konventions- und Cross-Repo-Referenz.

Was dieses Repo ist

Cards Native — native SwiftUI-Universal-App (iOS / iPadOS / macOS) für Wordeck, die Spaced-Repetition-Karten-App des Vereins mana e.V. Web-Parität zu wordeck.com, plus native iOS- Affordances (Widgets, Notifications, Universal-Links, Pencil).

                  HTTPS/JWT      ┌──────────────────┐
   cards-api     ◄─────────────  │ wordeck-native     │  SwiftUI
   api.wordeck.com         │ (this repo)      │  SwiftData (Cache)
                                 │ ev.mana.wordeck    │  WidgetKit (β-6)
                                 └──────────────────┘

Status

Phase β-0 — Setup (2026-05-12). Repo-Skelett, ManaCore + ManaTokens als Package-Dependency, Login + Wordeck-API-Reachability-Probe. Phasen β-1 bis β-7 in ../mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md.

Leitprinzip: Web-Parität

Die Web-App auf wordeck.com ist Funktions-Referenz. Bei Konflikt zwischen Native und Web → Web gewinnt. Native ist Re-Implementation, kein neues Produkt.

Datenmodell, FSRS-Verhalten, Marketplace-Slugs, Sharing-URLs: identisch zu Web.

Architektonische Invarianten

Beschlossen. Nicht ohne explizite Diskussion antasten.

  1. Server-authoritative FSRS. Grading-Calls gehen immer an POST /api/v1/reviews/:cardId/:subIndex/grade. Kein lokaler ts-fsrs-Port.
  2. Offline-Read, Online-Write. Decks + Due-Cards via SwiftData gecacht (offline sichtbar). Grades werden bei Offline in einer lokalen Queue persistiert und beim Reconnect der Reihe nach abgesendet.
  3. mana-auth via ManaCore. import ManaCore, AuthClient(config: AppConfig.manaAppConfig). Eigene Auth-Implementierung ist verboten.
  4. Pure SwiftUI. Keine externen UI-Libraries. AppKit/UIKit nur als Bridge wenn zwingend (z.B. PencilKit für Image-Occlusion).
  5. Bundle-ID ev.mana.wordeck. Reverse-Domain mana-ev.ch. Universal-Link-Domain: wordeck.com.
  6. Cards-Domain-Logik bleibt am Server. SubIndex-Berechnung für Cloze, Image-Occlusion-Mask-Validation, Content-Hash — alles Server. Native zeigt nur, was vom Server kommt.
  7. forest-Theme. Heute lokal in WordeckTheme.swift nachgebaut (Werte gespiegelt aus mana/packages/themes/src/variants/forest.css). Migration auf ManaTokens-Theme-Switch ist Phase ε.
  8. Web gewinnt bei Konflikt. Eleganteres Native-Verhalten geht zuerst in die Web-App, dann nach hier.

Konventionen

  • Swift 6.0, Strict Concurrency komplett
  • iOS 18 / iPadOS 18 / macOS 15 Minimum
  • SwiftUI als einziges UI-Framework
  • XcodeGen als SOT: project.yml definiert Targets, Info.plist, Entitlements. .xcodeproj, generierte Info.plist und Entitlements sind nicht im Git
  • SwiftFormat mit .swiftformat (4-space, 120-col, sorted imports)
  • SwiftLint mit .swiftlint.yml
  • Logging: App-Subsystem ev.mana.wordeck via Sources/Core/Telemetry/Log.swift. ManaCore loggt parallel unter ev.mana.core
  • Persistenz: SwiftData für Deck/Card-Cache (ab β-1), JWT im Keychain (über ManaCore)
  • Lokalisierung: DE primary, EN fallback via Localizable.xcstrings

Wordeck-API-Wire-Format

Wire-Format gegen https://api.wordeck.com/api/v1/*. Quelle der Wahrheit: ../cards/apps/api/src/routes/*.ts. Bei neuem DTO verifizieren:

  1. Path + Method gegen den Hono-Handler prüfen
  2. Response-Schema (zod) gegen Codable-Struct mappen
  3. snake_case via CodingKeys, Optionale Felder explizit Optional<T>
  4. Test-Fixture aus echtem Server-Response in Tests/UnitTests/

Repo-Layout

wordeck-native/
├── project.yml                  XcodeGen-Manifest (SOT)
├── PLAN.md                      Phase-Tracking (gekürzt aus Greenfield-Plan)
├── CLAUDE.md                    dieses File
├── README.md
├── .swiftformat, .swiftlint.yml
├── Sources/
│   ├── App/                     WordeckNativeApp (@main), RootView
│   ├── Features/
│   │   ├── Account/             LoginView, AccountView (ab β-1)
│   │   ├── Decks/               DashboardView (Placeholder), DeckList (β-1)
│   │   ├── Study/               (β-2)
│   │   ├── Editor/              (β-3)
│   │   ├── Marketplace/         (β-5)
│   │   ├── Stats/               (β-1)
│   │   └── Imports/             (β-3)
│   ├── Core/
│   │   ├── Auth/                AppConfig (ManaAppConfig-Provider)
│   │   ├── API/                 WordeckAPI (AuthenticatedTransport-Wrapper)
│   │   ├── Domain/              (Card-Type-Enums, Rating-Enum — ab β-2)
│   │   ├── Storage/             (SwiftData-Models — ab β-1)
│   │   ├── Sync/                (ReviewQueue, MediaCache — ab β-2/β-4)
│   │   ├── Telemetry/           OSLog (Subsystem ev.mana.wordeck)
│   │   └── Theme/               WordeckTheme (forest-Werte)
│   ├── Widgets/                 (WidgetKit-Extension — ab β-6)
│   ├── ShareExtension/          (Save-as-Card — ab β-6)
│   └── Resources/
│       ├── Assets.xcassets
│       ├── Localizable.xcstrings
│       ├── Info.plist           (generiert, gitignored)
│       └── WordeckNative.entitlements  (generiert, gitignored)
├── Tests/
│   ├── UnitTests/
│   └── UITests/
└── docs/

Wichtige Cross-Repo-Doks

  • ../mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md — vollständiger Phasen-Plan und Architektur-Entscheidungen
  • ../mana/docs/MANA_SWIFT.md — native-Plattform-SOT
  • ../mana/docs/MANA_AUTH_FEDERATION.md — Auth-Protokoll, das ManaCore implementiert
  • ../mana/docs/COMPLIANCE.md — Telemetrie/Auth/Bezahl-Regeln, gilt auch nativ
  • ../cards/CLAUDE.md — Cards-Repo, Web + API
  • ../cards/STATUS.md — Web-Phasenstand (Funktions-Referenz)
  • ../mana-swift-core/CLAUDE.md — geteilter Code, Konventionen

Lokal entwickeln

Pre-Requisites:

  • Xcode 16+
  • brew install xcodegen swiftformat swiftlint
  • ../mana-swift-core/ muss als Schwester-Verzeichnis existieren (Package-Dependency via path: ../mana-swift-core)

Workflow:

xcodegen generate
open WordeckNative.xcodeproj

Vor jedem Commit:

swiftformat Sources Tests
swiftlint --strict

Phasen-Disziplin

Jede Phase aus dem Greenfield-Plan hat ein verifizierbares Erfolgskriterium. Nicht in die nächste Phase reinarbeiten, bevor die vorherige abgeschlossen ist:

  • β-0: leerer Build + Login + API-Reachability-Probe (JETZT)
  • β-1: Decks-Liste mit SwiftData-Cache
  • β-2: Study-Loop + Offline-Grade-Queue + Endurance-Test auf realem Gerät
  • β-3: Card-/Deck-Editor (basic, cloze, typing, multiple-choice)
  • β-4: Media + image-occlusion + audio-front
  • β-5: Marketplace + Universal-Links
  • β-6: Native-Polish (Widgets, Notifications, Share-Extension)
  • β-7: App-Store-Submission

Bei Phasen-Wechsel: PLAN.md aktualisieren + Greenfield-Plan abhaken.