cards-native/CLAUDE.md
Till JS 4dfb32ba25 chore: Rebrand auf ev.mana.cardecky
Apple-Developer-Portal-App-ID lautet ev.mana.cardecky (analog zur
Domain cardecky.mana.how). Alle Bundle-IDs, App-Group, Keychain-
Group, OSLog-Subsysteme, URL-Schemes, Widget-Kind, App-Intent-Phrases,
Marketing-Texte und Doku nachgezogen.

Bundle-IDs neu:
- Main: ev.mana.cardecky
- Widget: ev.mana.cardecky.widget
- Share: ev.mana.cardecky.share
- Tests: ev.mana.cardecky.tests / .uitests

App-Group: group.ev.mana.cardecky
Keychain-Access-Group: $(AppIdentifierPrefix)ev.mana.cardecky
OSLog-Subsystem: ev.mana.cardecky

AASA gleichzeitig in cards-Repo angepasst (Commit 21ec535) und
auf mana-server redeployed — Probe liefert appID
"QP3GLU8PH3.ev.mana.cardecky".

Plus: ShareExtension/Resources/Info.plist + entitlements werden
jetzt analog zu Widget-Resources gitignored (sind XcodeGen-generated).

35 Unit-Tests + 1 UI-Test grün, alle drei Targets bauen.

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

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.cardecky │ 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.cardecky`.** 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.cardecky` 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.cardecky)
│ │ └── 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.