zitare-native/PLAN.md
Till JS 1d770123f5 η-0: De-Hybrid — WKWebView raus, native Tabs mit Platzhaltern
Lift von Hybrid (WKWebView für Lesen/Erkunden) auf fully-native ist
beschlossen. Diese Phase entfernt die WebShell-Infrastruktur; das volle
native Read-Surface folgt in η-2..η-5 nach docs/NATIVE_LIFT_PLAN.md.

- ManaWebShell-Dep raus aus project.yml
- Sources/Core/WebShell/CookieBridge.swift gelöscht
- RootView auf vier native Tabs (Lesen + Erkunden = Platzhalter,
  Submit + Konto unverändert nativ)
- DocComments in DeepLinkRouter / AppConfig / Account / Settings von
  WebView-Verweisen befreit
- CLAUDE.md Invarianten von Hybrid auf η umgestellt (13 Invarianten,
  pure SwiftUI + Offline-first + SafariView-Ausnahme für Legal)
- PLAN.md auf η-0 + Phasenübersicht η-0..η-10
- AppConfigTests.test_keychainService_matchesSharedGroup auf
  ManaSharedKeychainGroup aktualisiert (war drift seit Cross-App-SSO)

Verifikation:
- xcodebuild iOS-Simulator iPhone 16e: BUILD SUCCEEDED
- nm ZitareNative | grep WKWebView: 0 Referenzen
- otool -L: kein WebKit-Framework-Link
- 20/20 Tests grün

Cross-Repo-Follow-up (η-1 Blocker):
- zitare/apps/zitare/ muss index-full.json + 7 Stammdaten-JSONs liefern
- zitare/apps/api/ Volltext-Search-Endpoint bestätigen/ergänzen

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:32:05 +02:00

118 lines
5.3 KiB
Markdown

# Plan — zitare-native (η = fully native)
**Stand: 2026-05-22 — Phase η-0 in Arbeit.** Hybrid-Strategie ist
revidiert. Lese-Surfaces werden nativ. Vollständige Phasen-Begründung
+ Erfolgs-Kriterien in [`docs/NATIVE_LIFT_PLAN.md`](docs/NATIVE_LIFT_PLAN.md).
> **SOT:** der NATIVE_LIFT_PLAN. Dieses File ist nur die App-lokale
> Status-Spur.
## Archiv: Phasen ζ-0 bis ζ-2 (Hybrid, abgeschlossen)
Code aus diesen Phasen lebt teils weiter, teils ist er entfernt:
-**ζ-0 Setup** — Repo-Skelett, `project.yml`, iOS-Simulator-Build,
ManaCore-Login + Healthz-Probe live (2026-05-14).
-**ζ-1 WebShellView + Cookie-Bridge** — gebaut, dann in η-0 (heute)
wieder gelöscht. `CookieBridge.swift` weg, `ManaWebShell`-Dep raus
aus `project.yml`.
- 🚧 **ζ-2 Snapshot-Sync + DailyQuoteWidget (Code-Done)** — Widget-Code
+ SwiftData-Stub-Modelle existieren, Endpoint im Web-Repo (Snapshot
v1 `index-min.json`) + Apple-Dev-Portal-App-Group fehlen für E2E.
Wird in η-1 auf Snapshot v2 erweitert.
## Aktuell
**η-0 — De-Hybrid (2026-05-22, abgeschlossen)**
- [x] `Sources/Core/WebShell/CookieBridge.swift` gelöscht +
WebShell-Verzeichnis entfernt.
- [x] `ManaWebShell`-Dep aus `project.yml` raus.
- [x] `RootView.swift` auf vier native Tabs umgestellt; Lesen +
Erkunden zeigen Platzhalter-Views (η-2/η-4-Hinweis).
- [x] DocComments in `DeepLinkRouter.swift`, `AppConfig.swift`,
`AccountView.swift`, `SettingsView.swift` von WebView-Verweisen
befreit.
- [x] `CLAUDE.md` Invarianten ersetzt (Hybrid → η).
- [x] `xcodegen generate` + iOS-Simulator-Build grün (iPhone 16e, Xcode
26.2 SDK).
- [x] `nm ZitareNative` zeigt 0 WKWebView-Referenzen; `otool -L`
kein WebKit-Framework-Link. Binary ist WebView-frei.
- [x] Tests grün: 20/20 (AppConfigTests + DeepLinkRouterTests +
SnapshotSyncTests + SmokeUITests). Pre-existing Keychain-Service-
Test auf `ManaSharedKeychainGroup` aktualisiert (war out-of-sync
seit Cross-App-SSO-Konsolidierung).
- [x] Greenfield-Playbook `mana/docs/playbooks/ZITARE_NATIVE_GREENFIELD.md`
als überholt markiert (Banner + status-Header).
## Phasen-Übersicht (η)
| Phase | Ziel | Erfolg | Status |
|---|---|---|---|
| η-0 | De-Hybrid | Build grün, kein WKWebView im Binary | ✅ |
| η-1 | Snapshot v2 + volles SwiftData-Schema | Cold-Start lädt vollen Korpus, ETag spart Bytes | ⏳ (Web-Repo-Blocker) |
| η-2 | Read-Core (Heute, Quote, Author) | Flugmodus + UL aus Mail-App zeigt Quote nativ | ⏳ |
| η-3 | Read-Browse (Source/Theme/Place/Role/Epoch/Lang) | Alle Deep-Link-Pattern aus app-manifest.json nativ | ⏳ |
| η-4 | Explore + Filter | „Roman + DE + lang" Filter live ohne Server | ⏳ |
| η-5 | Search (lokal + Server-Fallback) | Offline-Treffer + Online-Ergänzung | ⏳ |
| η-6 | Account nativ | Sign-In/Out + Submissions-Liste nativ | ⏳ |
| η-7 | Legal via SafariView | Impressum/Datenschutz/Lizenz als SFSafariViewController | ⏳ |
| η-8 | Submit + ShareExt + Spotlight an Snapshot v2 | Spotlight findet via Volltext | ⏳ |
| η-9 | Polish (iPad / Accessibility / macOS) | Solo-Nutzung ohne Browser-Tab eine Woche | ⏳ |
| η-10 | TestFlight | Approved | ⏳ |
## Externe Blocker (nicht von Native-Code lösbar)
- [ ] **Apple-Dev-Portal: App-Group `group.ev.mana.zitare`**
registrieren — sonst kein macOS-Build und kein Widget auf realem
Gerät. Selbe Aktion wie für cards/memoro/moodlit/herbatrium nötig.
- [ ] **Cloudflare:** DNS-CNAME für `zitare.com` (Apex) auf
`1435166a-0e3f-4222-8de6-744f32cea5c9.cfargotunnel.com`
proxied. Plus Cleanup des versehentlichen
`zitare.com.mana.how`-CNAME. Anleitung in
[`docs/CLOUDFLARE_TODO.md`](docs/CLOUDFLARE_TODO.md).
## Web-Vorbedingungen (Aufgabe an `../zitare/`)
η-1-Blocker — ohne diese Endpoints kein Offline-Lesen:
- [ ] `https://zitare.com/index-full.json` mit allen Quote-Feldern
inkl. Volltext.
- [ ] Stammdaten-Collections: `authors.json`, `sources.json`,
`themes.json`, `places.json`, `epochs.json`, `roles.json`,
`languages.json` auf `zitare.com/`.
- [ ] ETag-Header für jeden dieser Endpoints (Cache-Control: 1h).
η-5-Voraussetzung:
- [ ] `GET /api/v1/quotes?q=<query>` Volltext-Search bestätigt /
ergänzt in `zitare/apps/api/`.
η-6-Voraussetzung:
- [ ] `GET /api/v1/me/submissions` (eigene Einreichungen) bestätigt /
ergänzt.
Restliche Web-Vorbedingungen (orthogonal):
- [ ] AASA auf `https://zitare.com/.well-known/apple-app-site-association`
mit `appID: QP3GLU8PH3.ev.mana.zitare`.
- [ ] `zitare.com` Cloudflare-Zone-Onboarding (steht in
`zitare/STATUS.md` als offen).
## Verifikations-Lücken
η-0: keine offenen. Pre-existing 4 swiftlint-strict-Violations in
`ZitareNativeApp.swift` + `SubmitQuoteView.swift` bleiben — sind aus
ζ-3 (Submit-Phase) und nicht η-0-Scope.
## Quirks
- `swiftformat` läuft aggressiver als die letzte ζ-Phase: entfernt
`Sendable`-Konformanz aus `DropRecord`/`QuoteDraft`/`SubmittedQuote`
und `self.`-Prefix in `OS_log_t.info(...)`-`@autoclosure`-Calls.
Beides führt zu Strict-Concurrency-Errors. In η-0 wurden die
Kollateral-Edits zurückgerollt; `swiftformat` muss vor η-1 mit
expliziter Exclude-Liste oder einer .swiftformat-Regel-Anpassung
gezähmt werden, sonst zerstört der nächste Format-Lauf wieder
Submit-Code.