v0.4.0 — Phase β-3 Editor

Voller Editor-Flow für Decks und 5 Card-Types (basic, basic-reverse,
cloze, typing, multiple-choice). image-occlusion + audio-front kommen
mit β-4 (Media). Anki-Import bleibt vorerst aus (Web parsed client-
side, gibt keinen Server-Import-Endpoint zu rufen).

- DeckCreateBody/UpdateBody, CardCreateBody/UpdateBody Encodable
  mit snake_case-CodingKeys, nil-Felder werden weggelassen
- CardFieldsBuilder mit Type-spezifischen Pflicht-Feld-Konstruktoren
- CardsAPI: createDeck/updateDeck/deleteDeck +
  createCard/updateCard/deleteCard
- DeckEditorView (Create + Edit in einer View): Color-Picker mit
  8-Preset-Palette, Category-Picker (11 Kats, deutsche Labels),
  Visibility-Segmented-Control
- CardEditorView mit Type-Picker und dynamischen Feldern je Typ.
  Cloze-Sektion zeigt Live-Cluster-Count und Hint-Syntax-Hinweis.
  image-occlusion/audio-front zeigen β-4-Placeholder
- DeckDetailView mit Action-Buttons (Lernen, Karte hinzufügen,
  Bearbeiten, Löschen mit Confirmation)
- DeckListView: "+"-Button im Toolbar (Leading) für Create-Sheet
- 7 neue Encoding-Tests (24 Unit-Tests + 1 UI-Test grün)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-05-13 00:24:43 +02:00
parent 3b861af3fb
commit cf1160b270
9 changed files with 930 additions and 19 deletions

65
PLAN.md
View file

@ -1,10 +1,9 @@
# 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.
**Stand: 2026-05-13 — Phasen β-0 + β-1 + β-2 + β-3 abgeschlossen.**
Login, Deck-Liste mit Cache, Study-Loop mit Offline-Grade-Queue,
voller Editor-Flow (Deck Create/Edit/Delete + Card Create für 5
Types). 24 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.
@ -28,6 +27,24 @@ mit Flugmodus zwischendurch) steht aus — Aufgabe für Till.
- `LoginView` (Email/PW gegen mana-auth)
- 3 Unit-Tests (AppConfig)
✅ **β-3 — Editor (2026-05-13, Tag `v0.4.0`)**
- `DeckCreateBody`, `DeckUpdateBody`, `CardCreateBody`, `CardUpdateBody`
Encodable-Structs (snake_case via `CodingKeys`, nil-Felder werden
weggelassen)
- `CardFieldsBuilder` mit Type-spezifischen Pflicht-Feld-Konstruktoren
- `CardsAPI`: createDeck/updateDeck/deleteDeck + createCard/updateCard/deleteCard
- `DeckEditorView` für Create + Edit in einer View (mode-switch),
Color-Picker mit 8-Preset-Palette aus forest-Theme, Category-Picker
(11 Kategorien mit deutschen Labels), Visibility-Segmented-Control
- `CardEditorView` mit Type-Picker (basic, basic-reverse, cloze,
typing, multiple-choice) und dynamischen Feldern je Typ. Cloze-View
zeigt Live-Cluster-Count und Hint-Syntax-Hinweis. image-occlusion
und audio-front zeigen β-4-Placeholder
- `DeckDetailView` mit 4 Action-Buttons (Lernen, Karte hinzufügen,
Bearbeiten, Löschen), Confirmation-Dialog für Delete
- DeckListView: "+"-Button im Toolbar (Leading), Sheet für Create
- 7 zusätzliche Encoding-Tests (24 Unit-Tests total)
✅ **β-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
@ -68,25 +85,41 @@ mit Flugmodus zwischendurch) steht aus — Aufgabe für Till.
| β-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) |
| β-3 | ✅ 2026-05-13 | Editor: Deck-CRUD + Card-Create (5 Types); Anki-Import auf β-3-ext verschoben |
| β-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)
## Nächste Schritte für β-4 (Media + Advanced Card-Types)
Aus Greenfield-Plan-Sektion "Phase β-3 — Card-/Deck-Editor":
Aus Greenfield-Plan-Sektion "Phase β-4":
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`
1. Media-Upload via `POST /api/v1/media` (Multipart, 25 MiB max,
MinIO-Backend), PHPickerViewController für Foto-Auswahl
2. `audio-front`-Cards: AVAudioPlayer für Wiedergabe (Pattern aus
memoro-native)
3. `image-occlusion`-Renderer: SVG-Mask-Overlay über AsyncImage,
Tap auf Mask → Reveal
4. iPad-PencilKit-Editor für Image-Occlusion-Masks
5. `MediaCache` im FileManager (Caches/cards-media/<id>, LRU 200 MB)
6. `CardEditorView` um image-occlusion + audio-front erweitern
**Erfolgskriterium:** Karte in Native erstellt, in Web sichtbar;
Karte in Web erstellt, in Native sichtbar (Pull-to-Refresh).
**Erfolgskriterium:** Karten mit Bildern und Audio aus Web-erstellten
Decks funktionieren in Native. Image-Occlusion in beide Richtungen
(Native↔Web) sichtbar.
## Verschoben auf β-3-Extension oder später
- **Anki-Import** (`.apkg`-Parser): Web parsed client-side und ruft
`POST /cards` pro Karte. Native bräuchte eigenen Swift-Parser für
Anki-Pakete (Plist/sqlite/.apkg) — eigener Brocken, nicht
blockierend für andere Phasen.
- **Card-Edit** (PATCH /cards/:id): Card-Create reicht für Web-Parität
in v1, Edit kann später nachgereicht werden.
- **Distractor-Vorschau** für Multiple-Choice-Editor: Server liefert
Distractors zur Lernzeit (`/decks/:deckId/distractors`), Editor
zeigt sie nicht — Web macht das auch nicht.
## Pflicht-Tests für β-2 (vor β-3-Start)