Repo-Skelett für cards-native, native SwiftUI-Universal-App für Cardecky (mana e.V.). Web-Parität zu cardecky.mana.how. - project.yml mit Bundle ev.mana.cards, ManaSwiftCore-Dep via path - AppConfig: auth.mana.how + cardecky-api.mana.how, Keychain ev.mana.cards - CardsTheme: forest-Werte aus mana/packages/themes/.../forest.css - LoginView (Email/PW gegen mana-auth via ManaCore.AuthClient) - DashboardView als β-1-Placeholder mit cardecky-api-Reachability-Probe - Log unter Subsystem ev.mana.cards - 3 AppConfig-Tests - iOS-Simulator-Build grün Phasen-Plan: mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
183 lines
7.3 KiB
Markdown
183 lines
7.3 KiB
Markdown
# CLAUDE.md — cards-native repo
|
|
|
|
Guidance für Claude Code in diesem Repository.
|
|
|
|
> **Wenn du gerade neu bist:** lies zuerst [`PLAN.md`](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 **Cardecky**, die Spaced-Repetition-Karten-App des Vereins
|
|
**mana e.V.** Web-Parität zu `cardecky.mana.how`, plus native iOS-
|
|
Affordances (Widgets, Notifications, Universal-Links, Pencil).
|
|
|
|
```
|
|
HTTPS/JWT ┌──────────────────┐
|
|
cards-api ◄───────────── │ cards-native │ SwiftUI
|
|
cardecky-api.mana.how │ (this repo) │ SwiftData (Cache)
|
|
│ ev.mana.cards │ WidgetKit (β-6)
|
|
└──────────────────┘
|
|
```
|
|
|
|
## Status
|
|
|
|
**Phase β-0 — Setup (2026-05-12).** Repo-Skelett, ManaCore + ManaTokens
|
|
als Package-Dependency, Login + Cardecky-API-Reachability-Probe.
|
|
Phasen β-1 bis β-7 in `../mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md`.
|
|
|
|
## Leitprinzip: Web-Parität
|
|
|
|
Die Web-App auf `cardecky.mana.how` 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.cards`.** Reverse-Domain mana-ev.ch.
|
|
Universal-Link-Domain: `cardecky.mana.how`.
|
|
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 `CardsTheme.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.cards` 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`
|
|
|
|
## Cardecky-API-Wire-Format
|
|
|
|
Wire-Format gegen `https://cardecky-api.mana.how/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
|
|
|
|
```
|
|
cards-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/ CardsNativeApp (@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/ CardsAPI (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.cards)
|
|
│ │ └── Theme/ CardsTheme (forest-Werte)
|
|
│ ├── Widgets/ (WidgetKit-Extension — ab β-6)
|
|
│ ├── ShareExtension/ (Save-as-Card — ab β-6)
|
|
│ └── Resources/
|
|
│ ├── Assets.xcassets
|
|
│ ├── Localizable.xcstrings
|
|
│ ├── Info.plist (generiert, gitignored)
|
|
│ └── CardsNative.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:**
|
|
```bash
|
|
xcodegen generate
|
|
open CardsNative.xcodeproj
|
|
```
|
|
|
|
**Vor jedem Commit:**
|
|
```bash
|
|
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.
|