Invarianten #1/#2/#6 kehrten die alte „Server-authoritative FSRS / kein lokaler ts-fsrs-Port"-Entscheidung um — der Web-L-2-Cutover (2026-05-20) hat die Server-Grade-/CRUD-Endpoints retired (410), wordeck-Web rechnet FSRS client-seitig + synct über event-sync. Native zieht nach (E-4.4b, explizit mit Till entschieden). Doku darf dem Code nicht widersprechen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.3 KiB
CLAUDE.md — wordeck-native repo
Guidance für Claude Code in diesem Repository.
Wenn du gerade neu bist: lies zuerst
PLAN.mdund../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.
Umkehrung 2026-05-25 (E-4.4b, explizit mit Till entschieden): Die Invarianten #1, #2 und #6 wurden umgekehrt. Grund: der Web-L-2-Cutover (2026-05-20) hat die Server-Grade-/CRUD-Endpoints (
/reviews/.../grade,/decks,/cards) retired (410 Gone) — wordeck-Web rechnet FSRS jetzt client-seitig und synct über@mana/event-sync/sync2.mana.how. Die alte „Server-authoritative FSRS"-Invariante war damit faktisch schon gebrochen. Native zieht nach: client-seitiger FSRS-Port + event-sourced Local-First. Siehe../mana/docs/playbooks/MANA_SWIFT_EVENT_SYNC.md.
- Client-seitiger FSRS (Local-First). Grading rechnet lokal über den
Pure-Swift-FSRS-6-Port (
Sources/Core/Domain/FSRSScheduler.swift), byte-paritätisch zu ts-fsrs/@wordeck/domain(Golden-Test gegenTests/UnitTests/Fixtures/fsrs_golden.json). Kein Server-Grade-Call mehr (Endpoint ist 410). Ergebnis wird alsReviewGraded-Event emittet. - Event-sourced via
ManaEventSync. deck/card/review als Events (lokaler EventLog + Outbox + Sync gegensync2.mana.how). Offline voll nutzbar; Push gated bis Login (Anonymous-Mode + Claim). Ersetzt den alten REST-Cache (CachedDeck/PendingGrade). Marketplace + KI-Generate bleiben HTTP gegenapi.wordeck.com. - mana-auth via ManaCore.
import ManaCore,AuthClient(config: AppConfig.manaAppConfig). Eigene Auth-Implementierung ist verboten. - Pure SwiftUI. Keine externen UI-Libraries. AppKit/UIKit nur
als Bridge wenn zwingend (z.B.
PencilKitfür Image-Occlusion). - Bundle-ID
ev.mana.wordeck. Reverse-Domain mana-ev.ch. Universal-Link-Domain:wordeck.com. - Domänen-Logik client-seitig, paritätisch zum Web. FSRS + SubIndex-
Berechnung (Cloze) laufen lokal, byte-/verhaltens-paritätisch zu
@wordeck/domain(Golden-Tests). Bei Konflikt gewinnt Web (#8). Content-Hash/Marketplace-Validierung bleiben serverseitig. forest-Theme. Heute lokal inWordeckTheme.swiftnachgebaut (Werte gespiegelt ausmana/packages/themes/src/variants/forest.css). Migration auf ManaTokens-Theme-Switch ist Phase ε.- 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.ymldefiniert 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.wordeckviaSources/Core/Telemetry/Log.swift. ManaCore loggt parallel unterev.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:
- Path + Method gegen den Hono-Handler prüfen
- Response-Schema (
zod) gegenCodable-Struct mappen - snake_case via
CodingKeys, Optionale Felder explizitOptional<T> - 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 viapath: ../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.