User-facing Rebrand:
- LoginView Heading (war schon in v0.8.5)
- NotificationManager.title (war schon in v0.8.5)
- ShareEditorView Footer-Text: "...in der Cards-App" → "...in der Cardecky-App"
- StudyAppIntents Description: "Öffnet Cards" → "Öffnet Cardecky"
- Localizable.xcstrings: "Cards" key → "Cardecky"
- NSPhotoLibraryUsageDescription: "Cards greift..." → "Cardecky greift..."
- Log.app.info("Cards starting") → "Cardecky starting"
- MARKETING_COPY.md: alle "Cards"-Treffer in DE + EN auf Cardecky
- RELEASE_CHECKLIST: App-Name "Cards" → "Cardecky"
Build-Nummer 2 → 3 (Apple lehnt doppelte Build-Nummern ab, Code-
Hash hat sich geändert).
Code-Identifier bleiben: CardsAPI, CardsTheme, CardsNativeApp,
CardsWidgetExtension, CardsShareExtension — interne Symbol-Namen,
nicht user-facing.
Archive verifiziert: CFBundleDisplayName=Cardecky, Build=3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
153 lines
7.2 KiB
Markdown
153 lines
7.2 KiB
Markdown
# RELEASE_CHECKLIST — cards-native
|
||
|
||
Externe Schritte vor App-Store-Submission. Alles unter dieser
|
||
Sektion läuft NICHT durch das Repo — sondern durch das Apple-
|
||
Developer-Portal, App-Store-Connect, das Cards-Web-Repo (für
|
||
AASA) und über Xcode (für Build + Sign).
|
||
|
||
## Vor TestFlight (intern, kein Apple-Review)
|
||
|
||
### Apple-Developer-Konfiguration
|
||
|
||
- [x] **Team-ID gesetzt** (`QP3GLU8PH3`, mana e.V.) — `DEVELOPMENT_TEAM`
|
||
in `project.yml > settings > base`. Greift bei Archive automatisch.
|
||
- [ ] **App-ID `ev.mana.cardecky`** im Developer-Portal anlegen, falls
|
||
noch nicht da. Mit Capabilities: App Groups, Keychain Sharing,
|
||
Associated Domains.
|
||
- [ ] **App-ID `ev.mana.cardecky.share`** + **`ev.mana.cardecky.widget`** für
|
||
die Extensions analog anlegen, ebenfalls mit App Groups.
|
||
- [ ] **App-Group `group.ev.mana.cardecky`** im Portal anlegen und allen
|
||
drei App-IDs zuweisen.
|
||
- [ ] **Keychain-Access-Group**: heute `ev.mana.cardecky`. Wenn
|
||
Shared-Keychain mit `memoro-native` gewünscht (siehe
|
||
`mana/docs/MANA_SWIFT.md` Phase γ), auf
|
||
`$(AppIdentifierPrefix)ev.mana.shared` umstellen und
|
||
`AppConfig.manaAppConfig.keychainAccessGroup` setzen.
|
||
- [ ] **Provisioning Profiles** für alle drei Targets generieren
|
||
(Development + Distribution). Bei "Automatic Signing" macht
|
||
Xcode das beim ersten Build selbst, wenn das Team-ID stimmt.
|
||
|
||
### Asset-Polish
|
||
|
||
- [ ] **AppIcon ersetzen.** Heute Platzhalter aus
|
||
`scripts/make-appicon.swift` (forest-green "C"). Vor Submission
|
||
durch ein vom Designer erstelltes Icon austauschen
|
||
(`Sources/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png`).
|
||
- [ ] **Marketing-Versionsnummer** in `project.yml` setzen
|
||
(`MARKETING_VERSION` → "1.0.0").
|
||
- [ ] **Build-Nummer** monoton inkrementieren bei jedem TestFlight-
|
||
Upload (`CURRENT_PROJECT_VERSION`).
|
||
|
||
### Server-seitige Vorbedingungen
|
||
|
||
- [x] **AASA-Endpoint** auf `cardecky.mana.how/.well-known/apple-app-site-association`
|
||
— SvelteKit-Server-Route gebaut in
|
||
`cards/apps/web/src/routes/.well-known/apple-app-site-association/+server.ts`
|
||
(2026-05-13). Content-Type `application/json`, paths `/d/*` und
|
||
`/u/*`. Lokal mit `node build` + curl verifiziert.
|
||
- [x] **`PUBLIC_APPLE_TEAM_ID=QP3GLU8PH3`** in
|
||
`cards/infrastructure/docker-compose.production.yml` hinterlegt
|
||
(Commit folgt). Wird zur Runtime von `$env/dynamic/public`
|
||
aufgelöst und in den AASA-Response geschrieben.
|
||
- [x] **Production-Deploy von cards-web** durchgeführt 2026-05-13.
|
||
Probe von außen: `curl https://cardecky.mana.how/.well-known/apple-app-site-association`
|
||
liefert `application/json` mit `"appID":"QP3GLU8PH3.ev.mana.cardecky"`.
|
||
Cloudflare-Tunnel reicht den Endpoint sauber durch (kein
|
||
HTML-Captive, kein Redirect).
|
||
- [ ] **cardecky-api.mana.how** muss erreichbar bleiben — die App
|
||
ist 100% Online-write. Health-Probe verifizieren.
|
||
|
||
### Build + Archive
|
||
|
||
- [ ] `xcodegen generate`
|
||
- [ ] In Xcode: Product → Archive (Destination "Any iOS Device")
|
||
- [ ] Im Organizer: Validate App
|
||
- [ ] Distribute App → TestFlight & App Store
|
||
|
||
### TestFlight-Test-Plan
|
||
|
||
- [ ] **Endurance:** 200+ Karten lernen, Flugmodus zwischendurch.
|
||
- [ ] **Cross-Device:** Web↔Native parallel. Karte gegrade in App →
|
||
Web zeigt nach Reload identischen Review-State.
|
||
- [ ] **Widget:** ans Home-Screen pinnen, Due-Count nach App-Refresh.
|
||
- [ ] **Universal-Link:** `https://cardecky.mana.how/d/<slug>` in
|
||
Safari öffnen → App startet auf Explore-Tab + Public-Deck-Detail.
|
||
- [ ] **Share-Extension:** Text in Safari markieren → Teilen → "Als
|
||
Karte speichern" → Karte landet in der App.
|
||
- [ ] **Siri-Shortcut:** "Hey Siri, Karten lernen" → App öffnet.
|
||
- [ ] **Daily-Reminder:** Tagesgrenze überqueren, Notification kommt
|
||
zur konfigurierten Uhrzeit.
|
||
- [ ] **Login/Logout:** kompletter Auth-Roundtrip.
|
||
- [ ] **Offline-Grades:** Reviews offline machen, online gehen,
|
||
`PendingGrade`-Queue läuft leer.
|
||
|
||
## Vor App-Store-Submission (öffentliches Review)
|
||
|
||
### App-Store-Connect
|
||
|
||
- [ ] **App-Eintrag erstellen** unter https://appstoreconnect.apple.com
|
||
mit Bundle-ID `ev.mana.cardecky`.
|
||
- [ ] **App-Name** + **Subtitle** (max 30 Zeichen):
|
||
- Name: "Cardecky"
|
||
- Subtitle: "Karteikarten — Verein mana"
|
||
- [ ] **Description** (de + en, max 4000 Zeichen). Vorschlag in
|
||
[`docs/MARKETING_COPY.md`](MARKETING_COPY.md) — vor Submission
|
||
gegenlesen und Vereins-Tonalität schärfen.
|
||
- [ ] **Keywords** (max 100 Zeichen, comma-separated):
|
||
"Karteikarten,Spaced Repetition,Lernen,Vokabeln,Anki,Flashcards,FSRS,mana,Verein,Open Source"
|
||
- [ ] **Screenshots** für iPhone 16 Pro Max + iPhone SE-3 + iPad Pro.
|
||
6.7", 6.5", 5.5", iPad 12.9" — siehe Apple's Specs.
|
||
- [x] **Privacy-Policy-URL**: `https://cardecky.mana.how/privacy` (live
|
||
seit 2026-05-13, SvelteKit-Route mit Verein-Content).
|
||
- [x] **Support-URL**: `https://cardecky.mana.how/help` (live, FAQ +
|
||
Kontakt-Email kontakt@mana-ev.ch).
|
||
- [ ] **Marketing-URL** (optional) — `cardecky.mana.how`.
|
||
- [ ] **Age-Rating**: vermutlich 4+ (no objectionable content).
|
||
- [ ] **Pricing**: Free.
|
||
- [ ] **App-Privacy** (Data Type Declaration):
|
||
- Email-Adresse (für Login)
|
||
- User-Inhalt (Karten, Decks)
|
||
- Nutzungsdaten (FSRS-Reviews)
|
||
- **Nicht** für Tracking verwendet.
|
||
|
||
### Compliance / Verein-Werte
|
||
|
||
- [ ] **Lese `mana/docs/COMPLIANCE.md`** und prüfe, dass keine
|
||
Telemetrie, kein Crash-Reporter, kein SaaS-Tracker in Submission-
|
||
Build (Stripe + APNs sind die akzeptierten Ausnahmen — Cards
|
||
nutzt keines davon heute).
|
||
- [ ] **Subscriptions / In-App-Purchases**: Marketplace-Paid-Decks
|
||
sind über `mana-credits` abgewickelt, nicht über StoreKit. Im
|
||
App-Store-Connect "no In-App-Purchases" auswählen, **außer**
|
||
wir wollen vor Submission StoreKit für `mana-credits` einführen
|
||
(separate Architektur-Frage).
|
||
|
||
### Hub-App vs Standalone-App (siehe MANA_SWIFT.md)
|
||
|
||
- [x] Entschieden: separate Apps. memoro-native und cards-native sind
|
||
eigenständige App-Store-Einträge. Keine Hub-App.
|
||
|
||
## Carryover-Tasks (β-6 / β-7-Reste)
|
||
|
||
- [x] Siri-Shortcut via App Intents (`StudyCardsIntent`) — funktional,
|
||
v1: nur "App öffnen". Erweiterung "Direkt in Default-Deck-Study"
|
||
kann später kommen.
|
||
- [x] Share-Extension "Save as Card" — Pragma-Lösung: Extension
|
||
speichert `PendingShare` in App-Group, Haupt-App zeigt Banner,
|
||
User wählt Ziel-Deck und Back-Text. Kein direkter API-Call aus
|
||
der Extension (Auth-State wäre kompliziert, Pragma reicht für v1).
|
||
- [ ] **Card-Edit** (PATCH `/cards/:id`): heute deferred, ergänzen wenn
|
||
Beta-User danach fragen.
|
||
- [ ] **Anki-Import**: heute deferred, weil Web client-side parsed
|
||
und kein Server-Endpoint existiert. Native bräuchte eigenen
|
||
`.apkg`-Parser (sqlite-basiert) — eigener Sprint.
|
||
|
||
## Nach Submission
|
||
|
||
- [ ] **Monitoring**: nach Release `cardecky-api.mana.how/healthz` und
|
||
Rate-Limit-Auslastung beobachten — Native-App kann Last-Spitzen
|
||
erzeugen.
|
||
- [ ] **DSGVO-Endpoint** (`/api/v1/dsgvo/export`, `/delete`) testweise
|
||
aus Native triggerbar machen (β-7-Extension oder β-8).
|
||
- [ ] **Update-Cadence**: erstmal alle 2-4 Wochen ein Build.
|
||
Build-Nummer monoton, Marketing-Version semver.
|