# Plan — cards-native (SwiftUI Universal) **Stand: 2026-05-13 — Phasen β-0 + β-1 + β-2 abgeschlossen.** Repo auf Forgejo, Login funktioniert, Deck-Liste mit Cache + Pull-to-Refresh, voller Study-Loop mit Flip/Rating/Haptic + Offline-Queue für Grades (PendingGrade SwiftData). Cloze client- rendered (1:1-Port aus cards-domain). 17 Unit-Tests + 1 UI-Test grün. Pflicht-Check für β-2: Endurance-Test auf realem Gerät (200+ Karten mit Flugmodus zwischendurch) steht aus — Aufgabe für Till. > **SOT:** `../mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md`. > Dieses File ist die App-lokale Status-Spur, das Greenfield-Doc > hat die ganze Architektur-Begründung. ## Aktueller Stand ✅ **β-0 — Setup (2026-05-12, Tag `v0.1.0`)** - Repo-Skelett unter `git.mana.how/till/cards-native` - `project.yml` mit Bundle-ID `ev.mana.cards`, ManaSwiftCore via `path: ../mana-swift-core` - `AppConfig` als `ManaAppConfig`-Provider: - Auth: `https://auth.mana.how` - API: `https://cardecky-api.mana.how` - Keychain-Service: `ev.mana.cards` - `CardsTheme.swift` mit forest-Werten (lokal nachgebaut aus `mana/packages/themes/src/variants/forest.css`) - `LoginView` (Email/PW gegen mana-auth) - 3 Unit-Tests (AppConfig) ✅ **β-2 — Study-Loop (2026-05-13, Tag `v0.3.0`)** - `Card`, `Review`, `DueReview` Codable-DTOs, `CardType`-Enum (alle 7 Typen) - `Rating`-Enum: `again | hard | good | easy` mit deutschen Labels - `Cloze`-Helpers (extractClusterIds, subIndexCount, clusterId, renderPrompt, renderAnswer, hint) — 1:1-Port aus `cards/packages/cards-domain/src/cloze.ts` - `CardsAPI.dueReviews(deckId:)`, `CardsAPI.gradeReview(...)` mit ISO8601-Encoder - `PendingGrade` SwiftData-Model + `GradeQueue` für Offline-Submit (FIFO-Drain, originaler reviewedAt-Timestamp bleibt erhalten) - `StudySession` als @Observable State-Machine (loading/studying/finished/failed) - `CardRenderer`: basic, basic-reverse (sub-index-abhängig), cloze client-rendered. image-occlusion/audio-front/typing/multiple-choice zeigen Placeholder (β-3/β-4) - `RatingBar` mit Haptic-Feedback (medium für again/hard/good, heavy für easy, soft beim Flip) - `StudySessionView` vollbild aus DeckListView per NavigationLink - 9 zusätzliche Tests (Cloze 8x, Review/DueReview-Decoding 3x) ✅ **β-1 — Decks lesen (2026-05-13, Tag `v0.2.0`)** - `Deck`-Codable-DTO mit snake_case-CodingKeys, plus `DeckCategory`, `DeckVisibility`, `FsrsSettings` - ISO8601-Date-Decoder mit Fractional-Seconds-Toleranz - `CardsAPI.listDecks()`, `cardCount(deckId:)`, `dueCount(deckId:)` - `CachedDeck` als SwiftData-Model mit `lastFetchedAt` (Offline-Read) - `DeckListStore` orchestriert API + Cache, paralleles Counts-Fetching via TaskGroup - `DeckListView` mit Pull-to-Refresh, Card/Due-Counts, deck.color-Streifen, Inbox-Banner für Marketplace-Forks - `AccountView` mit Sign-out-Button - iOS-Simulator-Build + Tests grün (6 Unit-Tests, 1 UI-Test) ## Phasen (Detail in Greenfield-Plan) | Phase | Status | Inhalt | |---|---|---| | β-0 | ✅ 2026-05-12 | Setup, Login, API-Probe | | β-1 | ✅ 2026-05-13 | Decks lesen, SwiftData-Cache, Pull-to-Refresh | | β-2 | ✅ 2026-05-13 | Study-Loop, Offline-Grade-Queue (Endurance-Test offen) | | β-3 | — | Card-/Deck-Editor (basic, cloze, typing, multiple-choice) | | β-4 | — | Media, image-occlusion (PencilKit), audio-front | | β-5 | — | Marketplace, Universal-Links | | β-6 | — | Native-Polish (Widgets, Notifications, Share-Extension) | | β-7 | — | App-Store-Submission | ## Nächste Schritte für β-3 (Editor) Aus Greenfield-Plan-Sektion "Phase β-3 — Card-/Deck-Editor": 1. `DeckCreateView`: Form für Name, Description, Color (Picker), Category-Picker, Visibility, FSRS-Settings (Sheet) 2. `CardEditorView` per Type (basic, cloze, typing, multiple-choice): Two-Text-Fields oder Cloze-Syntax-Highlighting 3. POST/PATCH/DELETE `/api/v1/cards` und `/api/v1/decks` 4. Anki-Import als Datei-Picker → `/api/v1/decks/import` **Erfolgskriterium:** Karte in Native erstellt, in Web sichtbar; Karte in Web erstellt, in Native sichtbar (Pull-to-Refresh). ## Pflicht-Tests für β-2 (vor β-3-Start) - [ ] Endurance-Test auf realem Gerät: 200+ Karten lernen, Flugmodus zwischendurch — alle Grades landen am Server nach Reconnect. - [ ] Cross-Check mit Web: Karte gegrade in Native → Web zeigt identischen Review-State nach Reload. ## Cross-Refs - `../mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md` — Greenfield-Plan SOT - `../mana/docs/MANA_SWIFT.md` — Plattform-SOT - `../cards/CLAUDE.md` — Cards-Repo - `../cards/STATUS.md` — Web-Phasenstand (Referenz) - `../mana-swift-core/CLAUDE.md` — ManaCore-Konventionen - `CLAUDE.md` — Repo-Konventionen