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>
7.3 KiB
CLAUDE.md — cards-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 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.
- Server-authoritative FSRS. Grading-Calls gehen immer an
POST /api/v1/reviews/:cardId/:subIndex/grade. Kein lokaler ts-fsrs-Port. - 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.
- 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.cardecky. Reverse-Domain mana-ev.ch. Universal-Link-Domain:cardecky.mana.how. - 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.
forest-Theme. Heute lokal inCardsTheme.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.cardeckyviaSources/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
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:
- 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
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 viapath: ../mana-swift-core)
Workflow:
xcodegen generate
open CardsNative.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.