Voller Lern-Flow mit Web-Parität: fällige Karten via /reviews/due laden, flip + rate (4 Buttons + Haptic), Grades via Offline-Queue ans Server-FSRS schicken. - Card/Review/DueReview DTOs mit snake_case + camelCase-deckId- Sonderfall im embedded card-Subobjekt - CardType-Enum (alle 7 Typen), Rating-Enum mit deutschen Labels - Cloze-Helper 1:1-Port aus cards-domain (extractClusterIds, subIndexCount, clusterId, renderPrompt/Answer, hint) - CardsAPI.dueReviews(deckId:) + gradeReview(cardId,subIndex,rating,reviewedAt) - PendingGrade SwiftData-Model + GradeQueue (FIFO-Drain, originaler Timestamp bleibt, bei Netzfehler in Queue, Retry beim nächsten Drain) - StudySession @Observable State-Machine - CardRenderer für basic, basic-reverse, cloze; Placeholder für image-occlusion/audio-front/typing/multiple-choice (β-3/β-4) - RatingBar mit UIImpactFeedbackGenerator (medium/heavy) - StudySessionView per NavigationLink aus DeckListView - 9 neue Tests (Cloze: 8, Review-Decoding: 3), insgesamt 17 grün Server-authoritative FSRS bleibt — kein ts-fsrs-Port. Endurance-Test auf realem Gerät steht aus (siehe PLAN.md). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
105 lines
4.6 KiB
Markdown
105 lines
4.6 KiB
Markdown
# 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
|