User-Feedback umgesetzt:
- Tap auf Deck-Tile öffnet jetzt direkt den Study-Mode für dieses
Deck (statt Deck-Detail). DeckRoute-Enum mit .study/.detail-Cases
+ programmatic NavigationPath.
- Edit-Icon (Pencil) unten rechts auf der Tile in Muted-Circle-Badge;
Tap führt in den Deck-Detail-View (Browse Cards + Bearbeiten).
- Kategorie-Icon oben rechts jetzt in primary-Farbe (war muted) +
größer (.title2 statt .title3) — visuell prominenter.
- Inbox-Banner ist jetzt als Button → Study-Mode mit dem ersten
Inbox-Deck.
ExploreView/PublicDeckCard:
- Selbes Tile-Layout wie DeckStackTile (5:7 Aspect-Ratio, CardSurface,
Kategorie-Icon oben rechts, Footer mit Counts + Owner).
- Featured-Star-Badge oben links statt rechts (damit Kategorie-Icon
konsistent rechts bleibt).
- Star-Count als ausgefüllter Stern in warning-Farbe.
- Owner-Name unter den Counts, mit verified-Seal wenn vorhanden.
Build 10 → 11. 43 Tests grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bei lokalen Xcode-Run-Builds wird beim Start automatisch eingeloggt
wenn der Keychain leer ist. Spart das manuelle Login bei jedem
Re-Install via Xcode.
- Sources/Core/Auth/DebugCredentials.swift — #if DEBUG-gewrappte
Founder-Credentials (tills95@gmail.com / Aa-123456789)
- Sources/Core/Auth/AuthClient+EnsureSignedIn.swift — Extension
ensureSignedIn() prüft .signedOut → signIn() in DEBUG
- RootView.task ruft auth.ensureSignedIn() — Release-Builds No-Op
(Release/TestFlight/App-Store bleiben unverändert, User muss
manuell einloggen)
Pattern 1:1 von memoro-native (gleiches File-Layout +
Klassennamen).
Build 9 → 10.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
UI-Refactor angelehnt an cards/apps/web. Drei Killer-Patterns
übernommen:
1. CardSurface (Sources/Core/Theme/CardSurface.swift)
- Drei Sizes md/lg/hero mit identischem Border-Radius 14pt,
1pt Border, layered Shadows je nach Elevation
- Aspect-Ratio 5:7 für md/hero, 12:16.8 für lg
- Optional Color-Accent-Stripe links (6pt, deck.color)
2. DeckStackTile (Sources/Features/Decks/DeckStackTile.swift)
- Spielkarten-Stack-Visual: 3 gestaffelt-rotierte
Hintergrund-Layer hinter der CardSurface
- Layer-Offsets + Tilts deterministisch aus Deck-ID gehasht
(gleiches Deck = gleiche Asymmetrie)
- Inhalt: Category-Icon oben rechts, Titel + Description
zentriert, Counts unten als Pill für dueCount
3. RatingBar mit Good-Emphasis (Features/Study/RatingBar.swift)
- "Good" als full primary background (hero action)
- again/hard/easy mit subtle border-tint + opacity-08-Background
- Keyboard-Shortcut im Button-Label als kbd-Style-Pill
DeckListView komplett umgebaut:
- Horizontale ScrollView mit scrollTransition + viewAligned-Snap
- Zwei Sektionen: "Eigene Decks" und "Abonniert"
- Inbox-Banner als highlight (primary opacity 0.08 mit border)
- Pending-Share-Banner mit warning-Tint
- Section-Headers mit Icon + Title + Count
StudySessionView.cardSurface nutzt jetzt CardSurface(.hero, .raised).
Build 6 → 7. Drei native Targets bauen, 35 Tests grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root-Cause des "0 Karten in jedem Deck" + "Server-Fehler (404)"-
Bug: ManaCore.AuthenticatedTransport.request(path:) hat
URL.appending(path:) verwendet, das `?` in Query-Strings als Pfad-
Component encoded → `?deck_id=X` → `%3Fdeck_id=X` → Server-Route
matched nicht → 404.
Betroffene Endpoints (alle hatten still failed):
- /api/v1/cards?deck_id=X → cardCount immer 0
- /api/v1/reviews/due?deck_id=X → dueCount immer 0, "Karten lernen"
immer disabled
- /api/v1/marketplace/decks?q=...&sort=... → Browse-Filter wirkungslos
- /api/v1/decks?forked_from_marketplace=true → Inbox-Filter wirkungslos
memoro-native nicht betroffen weil dort keine Query-Endpoints.
Fix in ManaCore v1.0.1 (Commit 74aee8d): String-basierte URL-
Konstruktion. CardsAPI bleibt unverändert.
Build 5 → 6, in Simulator verifiziert mit live-API-Auth-Roundtrip.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bisher zeigte DeckDetailView nur 4 Action-Buttons (Lernen,
Hinzufügen, Bearbeiten, Löschen) — Karten waren nur via Study-Loop
sichtbar. User-Feedback: "ich sehe keine Karten im Deck".
Geändert:
- CardsAPI.listCards(deckId:) → [Card] (war nur cardCount via /total)
- CardListResponse: nimmt cards-Array zusätzlich zu total
- DeckDetailView: ScrollView statt VStack, neue Sektion "Karten"
unter den Action-Buttons mit CardPreviewRow pro Karte
- CardPreviewRow: Type-Icon + Front-Preview (basic/cloze/audio/
image-occlusion adaptiv) + Type-Label
- task(id:) + refreshable triggern loadCards()
- Nach CardEditor-Save reloaded die Liste
Build 4 → 5.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Beim Öffnen eines Marketplace-Decks crashed JSON-Decoder mit
typeMismatch (Expected String, found Bool) auf
owner.pseudonym.
Ursache: Server-Schema (cards/apps/api/src/db/schema/marketplace/
authors.ts) hat pseudonym als `boolean NOT NULL DEFAULT false` —
ein Flag, dass der Autor pseudonym auftritt (Anzeigename verbergen).
Native hatte das fälschlich als String? (Anzeige-Pseudonym) interpretiert.
Fix:
- PublicDeckOwner.pseudonym: String? → Bool
- decoder.decodeIfPresent(String.self) → decode(Bool.self) ?? false
- Test-Fixture: "pseudonym": null → "pseudonym": false
Build 3 → 4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apple lehnte Build 0.1.0(1) ab mit ITMS-90129: "The bundle uses a
bundle name or display name that is already taken." Im App-Store
gibt es schon Apps mit dem DisplayName "Cards" (u.a. Apples eigene
Grußkarten-App war so benannt). App-Store-Connect-App heißt sowieso
"Cardecky" — Brand-Konsistenz: DisplayName durchgehend "Cardecky".
Geändert:
- project.yml Main-App: CFBundleDisplayName Cards → Cardecky,
CFBundleVersion 1 → 2 (Apple lehnt doppelte Build-Nummern ab)
- project.yml Widget: CFBundleDisplayName Cards Widget → Cardecky Widget,
INFOPLIST_KEY_CFBundleDisplayName analog
- project.yml Share-Extension: CFBundleVersion 1 → 2
- LoginView Heading: "Cards" → "Cardecky"
- NotificationManager.content.title: "Cards" → "Cardecky"
- UITest: erwartet "Cardecky" statt "Cards"
Archive verifiziert: CFBundleDisplayName=Cardecky, CFBundleVersion=2,
ARCHIVE SUCCEEDED. Nach erneutem Upload via Xcode Organizer sollte
TestFlight den Build akzeptieren.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- CFBundleShortVersionString 0.1.0 + CFBundleVersion 1 in beiden
Extensions (Widget + Share), damit sie mit dem Main-Bundle matchen
(Apple-Validation-Warning bei Embedded-Binary)
- UISupportedInterfaceOrientations (iPhone Portrait/Landscape +
iPad alle vier), behebt Validation-Warning
- AppIcon mac-Slot auf size 1024x1024 (Asset-Catalog akzeptiert)
- xcodeVersion: 16.0 im XcodeGen-Manifest gegen "Update to
recommended settings"-Hint
- ShareViewController: DispatchQueue.main.async für State-Updates
aus NSItemProvider-Callbacks (Swift-6-Concurrency-Sauberkeit)
- PendingShareStore.append: guard url != nil statt unused-let
Archive verifiziert via xcodebuild archive -allowProvisioningUpdates:
ARCHIVE SUCCEEDED, alle drei Provisioning Profiles (cardecky,
cardecky.widget, cardecky.share) automatisch geholt + signiert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apple-Developer-Team-ID des Vereins ist gesetzt. Greift bei Xcode-
Archive automatisch — Provisioning-Profile holt Xcode beim ersten
Sign-Versuch selbst, wenn die App-IDs (ev.mana.cards,
ev.mana.cards.widget, ev.mana.cards.share) im Developer-Portal
existieren.
RELEASE_CHECKLIST aktualisiert: Team-ID + AASA-Compose-Eintrag als
done markiert, Production-Deploy-Schritt für cards-web hinzu.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Feature-komplett für TestFlight. App-Icon-Platzhalter, Siri-Shortcut,
Share-Extension, Release-Checklist mit allen externen Apple-Schritten.
- scripts/make-appicon.swift: CoreGraphics-basierter Generator für
1024×1024 forest-green PNG mit "C"-Letter und Karten-Stack-Schatten
- Asset-Catalog auf Single-Size-AppIcon-Pattern umgestellt
- StudyCardsIntent + CardsAppShortcuts (App Intents): Siri-
Shortcut "Karten lernen mit Cards" / "Mit Cards lernen"
- CardsShareExtension Target: ShareViewController (UIKit-Bootstrap +
SwiftUI-Hosting), ShareEditorView mit Text-Edit
- PendingShare + PendingShareStore shared in App-Group
group.ev.mana.cards
- DeckListView zeigt PendingShare-Banner; Tap navigiert zu
PendingShareConsumeView mit Deck-Picker + Front/Back-Felder, Submit
→ POST /cards, danach store.remove
- Info.plist: NSPhotoLibraryUsageDescription für Image-Occlusion-
Picker, NSUserActivityTypes für Universal-Links
- docs/RELEASE_CHECKLIST.md mit externen Schritten: Apple-Developer-
Portal, App-IDs, App-Group, AASA, Xcode-Archive, TestFlight-Plan,
App-Store-Connect-Felder, Compliance-Verifikation
- UI-Test robuster (akzeptiert Login oder Decks/Entdecken als
Launch-Erfolg, unabhängig vom Simulator-Keychain-State)
- 35 Tests + 1 UI-Test grün, alle drei Targets bauen
App-Store-Submission selbst ist externe Aktion und passiert nicht
durch dieses Repo — Schritte in docs/RELEASE_CHECKLIST.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drei Sub-Pakete: Keyboard-Shortcuts, Daily-Reminder-Notifications,
WidgetKit-Extension mit App-Group-Daten-Sharing. Siri-Shortcuts
und Share-Extension auf β-7 verschoben — niedrige Priorität, die
drei großen Brocken decken 90% des Native-Polish ab.
Keyboard-Shortcuts:
- Hidden Buttons in StudySessionView mit .keyboardShortcut
- Space = flip, 1/2/3/4 = again/hard/good/easy
- iPad-Magic-Keyboard + macOS-tauglich
Daily-Reminders:
- NotificationManager @Observable mit UNUserNotificationCenter
- Authorization-State + Permission-Request-Flow
- UNCalendarNotificationTrigger täglich zur konfigurierten Zeit
- SettingsView in AccountView mit Toggle + DatePicker
- UserDefaults-Persistierung von Hour/Minute/Enabled
WidgetKit-Extension:
- WidgetSnapshot Codable mit topDecks (Top-3 by dueCount) + totalDueCount
- WidgetSnapshotStore schreibt in group.ev.mana.cards-Container
- DeckListStore.refresh schreibt Snapshot + WidgetCenter.reloadAllTimelines
- CardsWidgetExtension-Target im project.yml (app-extension)
- CardsWidgetBundle + CardsDueWidget mit 5 Familien (small/medium/
accessoryCircular/accessoryInline/accessoryRectangular)
- DueProvider TimelineProvider mit 30-min-Refresh
- DueWidgetView Family-Switch
- WidgetSnapshot.swift shared in beiden Targets via XcodeGen sources
- App-Group im Haupt- und Widget-Entitlement
35 Tests grün (keine neuen Tests in β-6 — WidgetKit + Notifications
sind System-API-Integrationen, Tests wären überwiegend Mocks).
Build inkl. Widget-Extension grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Voller Marketplace-Flow mit TabBar und Universal-Link-Handler.
Drei Live-Decks (Geografie, English A2, Periodensystem) sind
browse-, abonnier- und lernbar.
- PublicDeckEntry/PublicDeck/PublicDeckVersion/PublicDeckOwner/
PublicDeckDetail Codable mit snake_case
- ExploreResponse, BrowseResponse, SubscribeResponse
- MarketplaceSort-Enum (recent/popular/trending)
- CardsAPI.explore/browseMarketplace/publicDeck/subscribe/unsubscribe
- MarketplaceStore @Observable mit Explore + Browse States
- ExploreView: Featured + Trending Horizontal-Carousels, Browse-Link
- BrowseView: Searchable + Sort-Picker + List
- PublicDeckView: Header/Metadata/Subscribe — Subscribe löst Auto-Fork
serverseitig aus, Response liefert private_deck_id, NavigationLink
zum eigenen Deck
- PublicDeckCard + BrowseRow mit forest-Theme
- RootView: TabBar (Decks/Entdecken/Account) statt Single-View
- Universal-Link-Handler: onOpenURL + onContinueUserActivity für
https://cardecky.mana.how/d/<slug> und cards://d/<slug>
- associated-domains: applinks:cardecky.mana.how im entitlement
- 5 neue Marketplace-Decoding-Tests (35 Total grün)
Universal-Links funktionieren erst nach AASA-Setup auf
cardecky.mana.how/.well-known/apple-app-site-association
(Web-Aufgabe, heute 404).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deck-Liste mit Web-Parität: alle eigenen Decks aus cardecky-api,
Card-/Due-Counts pro Deck (Web-Pattern: separate Calls), Pull-to-
Refresh, Offline-Read via SwiftData, Inbox-Banner für Marketplace-
Forks.
- Deck-Codable-DTO mit snake_case-CodingKeys (DeckCategory,
DeckVisibility, FsrsSettings)
- ISO8601-Date-Decoder mit Fractional-Seconds-Toleranz
- CardsAPI.listDecks() + cardCount() + dueCount()
- CachedDeck SwiftData-Model mit lastFetchedAt
- DeckListStore (API + Cache, paralleles Counts-Fetching via TaskGroup)
- DeckListView mit forest-Theme, deck.color-Streifen, Inbox-Banner
- AccountView mit Sign-out
- DashboardView durch DeckListView ersetzt
- 6 Unit-Tests + 1 UI-Test grün
Phasen-Plan: mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Repo-Skelett für cards-native, native SwiftUI-Universal-App
für Cardecky (mana e.V.). Web-Parität zu cardecky.mana.how.
- project.yml mit Bundle ev.mana.cards, ManaSwiftCore-Dep via path
- AppConfig: auth.mana.how + cardecky-api.mana.how, Keychain ev.mana.cards
- CardsTheme: forest-Werte aus mana/packages/themes/.../forest.css
- LoginView (Email/PW gegen mana-auth via ManaCore.AuthClient)
- DashboardView als β-1-Placeholder mit cardecky-api-Reachability-Probe
- Log unter Subsystem ev.mana.cards
- 3 AppConfig-Tests
- iOS-Simulator-Build grün
Phasen-Plan: mana/docs/playbooks/CARDS_NATIVE_GREENFIELD.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>