From 22e06ef80321252b4a1008a8bbc15a610785077f Mon Sep 17 00:00:00 2001 From: Till JS Date: Sun, 5 Apr 2026 17:15:36 +0200 Subject: [PATCH] feat(manacore/web): add PWA support with offline UX, update prompt, and icons - Generate PWA icons (192x192, 512x512, apple-touch-icon) from favicon - Add Apple PWA meta tags, theme-color, and viewport-fit=cover to app.html - Upgrade caching preset to 'full' (adds font + CDN caching) - Add manifest shortcuts for Dashboard, Todo, Calendar, Chat - Switch registerType to 'prompt' for user-controlled updates - Add OfflineIndicator component (offline banner + sync status badge) - Add PwaUpdatePrompt component (detects waiting SW, skip-waiting on confirm) - Add networkStore for online/offline + sync status tracking - Wire sync manager status into networkStore for pending change counts - Update offline page text to reflect local-first architecture - Add mobile/desktop app strategy doc and Tauri v2 implementation plan Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/manacore/apps/web/src/app.html | 7 +- .../lib/components/OfflineIndicator.svelte | 180 +++++ .../src/lib/components/PwaUpdatePrompt.svelte | 161 +++++ .../apps/web/src/lib/stores/network.svelte.ts | 58 ++ .../apps/web/src/routes/(app)/+layout.svelte | 12 + .../apps/web/src/routes/+layout.svelte | 9 + .../apps/web/src/routes/offline/+page.svelte | 4 +- .../apps/web/static/apple-touch-icon.png | Bin 0 -> 4667 bytes apps/manacore/apps/web/static/pwa-192x192.png | Bin 0 -> 4978 bytes apps/manacore/apps/web/static/pwa-512x512.png | Bin 0 -> 15586 bytes apps/manacore/apps/web/vite.config.ts | 18 + docs/MOBILE_DESKTOP_APP_STRATEGY.md | 279 ++++++++ docs/PLAN_TAURI_V2.md | 627 ++++++++++++++++++ 13 files changed, 1352 insertions(+), 3 deletions(-) create mode 100644 apps/manacore/apps/web/src/lib/components/OfflineIndicator.svelte create mode 100644 apps/manacore/apps/web/src/lib/components/PwaUpdatePrompt.svelte create mode 100644 apps/manacore/apps/web/src/lib/stores/network.svelte.ts create mode 100644 apps/manacore/apps/web/static/apple-touch-icon.png create mode 100644 apps/manacore/apps/web/static/pwa-192x192.png create mode 100644 apps/manacore/apps/web/static/pwa-512x512.png create mode 100644 docs/MOBILE_DESKTOP_APP_STRATEGY.md create mode 100644 docs/PLAN_TAURI_V2.md diff --git a/apps/manacore/apps/web/src/app.html b/apps/manacore/apps/web/src/app.html index 77a5ff52c..28f42a234 100644 --- a/apps/manacore/apps/web/src/app.html +++ b/apps/manacore/apps/web/src/app.html @@ -3,7 +3,12 @@ - + + + + + + %sveltekit.head% diff --git a/apps/manacore/apps/web/src/lib/components/OfflineIndicator.svelte b/apps/manacore/apps/web/src/lib/components/OfflineIndicator.svelte new file mode 100644 index 000000000..8b894a712 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/components/OfflineIndicator.svelte @@ -0,0 +1,180 @@ + + +{#if showBanner} +
+
+ + + +
+ {$_('pwa.offline', { default: 'Offline — Änderungen werden lokal gespeichert' })} + +
+{/if} + +{#if showSyncBadge} +
+ + + {networkStore.pendingCount} + {$_('pwa.pendingChanges', { default: 'Änderungen warten auf Sync' })} + +
+{/if} + +{#if showSyncing} +
+ + {$_('pwa.syncing', { default: 'Synchronisiere...' })} +
+{/if} + + diff --git a/apps/manacore/apps/web/src/lib/components/PwaUpdatePrompt.svelte b/apps/manacore/apps/web/src/lib/components/PwaUpdatePrompt.svelte new file mode 100644 index 000000000..8139ec041 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/components/PwaUpdatePrompt.svelte @@ -0,0 +1,161 @@ + + +{#if showPrompt} + +{/if} + + diff --git a/apps/manacore/apps/web/src/lib/stores/network.svelte.ts b/apps/manacore/apps/web/src/lib/stores/network.svelte.ts new file mode 100644 index 000000000..e67b9b593 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/stores/network.svelte.ts @@ -0,0 +1,58 @@ +/** + * Network status store — tracks online/offline state and pending sync changes. + * + * Integrates with the unified sync manager to show sync status + * and pending change counts in the UI. + */ + +import type { SyncStatus } from '$lib/data/sync'; + +let isOnline = $state(typeof navigator !== 'undefined' ? navigator.onLine : true); +let syncStatus = $state('idle'); +let pendingCount = $state(0); + +let cleanups: (() => void)[] = []; + +function initialize() { + if (typeof window === 'undefined') return; + + const handleOnline = () => (isOnline = true); + const handleOffline = () => (isOnline = false); + + window.addEventListener('online', handleOnline); + window.addEventListener('offline', handleOffline); + + cleanups.push(() => { + window.removeEventListener('online', handleOnline); + window.removeEventListener('offline', handleOffline); + }); +} + +function destroy() { + for (const fn of cleanups) fn(); + cleanups = []; +} + +function setSyncStatus(status: SyncStatus) { + syncStatus = status; +} + +function setPendingCount(count: number) { + pendingCount = count; +} + +export const networkStore = { + get isOnline() { + return isOnline; + }, + get syncStatus() { + return syncStatus; + }, + get pendingCount() { + return pendingCount; + }, + initialize, + destroy, + setSyncStatus, + setPendingCount, +}; diff --git a/apps/manacore/apps/web/src/routes/(app)/+layout.svelte b/apps/manacore/apps/web/src/routes/(app)/+layout.svelte index e23217153..2eb8bbd2d 100644 --- a/apps/manacore/apps/web/src/routes/(app)/+layout.svelte +++ b/apps/manacore/apps/web/src/routes/(app)/+layout.svelte @@ -34,6 +34,8 @@ import { linkLocalStore, linkMutations } from '@manacore/shared-links'; import { manacoreStore } from '$lib/data/local-store'; import { createUnifiedSync } from '$lib/data/sync'; + import { networkStore } from '$lib/stores/network.svelte'; + import { db } from '$lib/data/database'; import { dashboardStore } from '$lib/stores/dashboard.svelte'; import { THEME_DEFINITIONS, @@ -306,6 +308,16 @@ trackReturnVisit(); const getToken = () => authStore.getValidToken(); unifiedSync = createUnifiedSync(SYNC_SERVER_URL, getToken); + unifiedSync.onStatusChange(async (s) => { + networkStore.setSyncStatus(s); + // Update pending count when sync status changes + try { + const count = await db.table('_pendingChanges').count(); + networkStore.setPendingCount(count); + } catch { + // DB not ready yet + } + }); unifiedSync.startAll(); userSettings.load().catch(() => {}); diff --git a/apps/manacore/apps/web/src/routes/+layout.svelte b/apps/manacore/apps/web/src/routes/+layout.svelte index 90c03a089..9ccb53d1e 100644 --- a/apps/manacore/apps/web/src/routes/+layout.svelte +++ b/apps/manacore/apps/web/src/routes/+layout.svelte @@ -3,8 +3,11 @@ import { onMount } from 'svelte'; import { theme } from '$lib/stores/theme'; import { authStore } from '$lib/stores/auth.svelte'; + import { networkStore } from '$lib/stores/network.svelte'; import { loadAutomations } from '$lib/triggers'; import SuggestionToast from '$lib/components/SuggestionToast.svelte'; + import OfflineIndicator from '$lib/components/OfflineIndicator.svelte'; + import PwaUpdatePrompt from '$lib/components/PwaUpdatePrompt.svelte'; let { children } = $props(); @@ -12,6 +15,9 @@ // Initialize theme const cleanupTheme = theme.initialize(); + // Initialize network status tracking + networkStore.initialize(); + // Initialize auth await authStore.initialize(); @@ -20,9 +26,12 @@ return () => { cleanupTheme(); + networkStore.destroy(); }; }); {@render children()} + + diff --git a/apps/manacore/apps/web/src/routes/offline/+page.svelte b/apps/manacore/apps/web/src/routes/offline/+page.svelte index 645202281..21f09f9e5 100644 --- a/apps/manacore/apps/web/src/routes/offline/+page.svelte +++ b/apps/manacore/apps/web/src/routes/offline/+page.svelte @@ -4,6 +4,6 @@ diff --git a/apps/manacore/apps/web/static/apple-touch-icon.png b/apps/manacore/apps/web/static/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..910b29b26c7037ae9ce88c156e24f6be4157f643 GIT binary patch literal 4667 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 literal 0 HcmV?d00001 diff --git a/apps/manacore/apps/web/static/pwa-192x192.png b/apps/manacore/apps/web/static/pwa-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..ccd9fc2c2728d108d97bb012b36a017904d27f04 GIT binary patch literal 4978 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 literal 0 HcmV?d00001 diff --git a/apps/manacore/apps/web/static/pwa-512x512.png b/apps/manacore/apps/web/static/pwa-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..5aaee085f4fcdeba84234abeee7bf2eed72f960a GIT binary patch literal 15586 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 Analyse der Optionen, die bestehende ManaCore SvelteKit-App als native Mobile- und Desktop-App auszuliefern. +> +> Stand: April 2026 + +## Ausgangslage + +Die ManaCore Unified App ist eine SvelteKit 2 + Svelte 5 Anwendung mit: + +- **27+ Module** in einer einzigen App (`apps/manacore/apps/web`) +- **Local-first Architektur** mit Dexie.js / IndexedDB (120+ Collections) +- **Tailwind CSS** für Styling +- **Hintergrund-Sync** via mana-sync (Go, WebSocket) +- Bestehende **Expo/React Native Mobile-Apps** im Monorepo (einzelne Module) + +Ziel: Die gesamte unified App auf iOS, Android, macOS, Windows und Linux bringen — idealerweise mit maximaler Code-Wiederverwendung. + +--- + +## Optionen + +### 1. Tauri v2 + +**Funktionsweise:** Nutzt die native WebView des Betriebssystems (WebKit auf macOS/iOS, WebView2 auf Windows, WebKitGTK auf Linux, Android WebView). Backend in Rust. Kein gebündelter Browser. + +**Plattformen:** iOS, Android, macOS, Windows, Linux — alles mit einer Codebase. + +| Aspekt | Bewertung | +|--------|-----------| +| SvelteKit-Wiederverwendung | Sehr gut — SPA via `adapter-static`, Svelte ist First-Class-Citizen | +| IndexedDB/Dexie.js | Funktioniert, aber iOS-WebKit-Limit ~500 MB | +| Native APIs | Gut — Dateisystem, Notifications, Clipboard, Biometrics, Updater u.v.m. Eigene Plugins in Rust/Swift/Kotlin | +| Bundle-Grösse | 2–10 MB (kein Chromium gebündelt) | +| App Store Distribution | Alle Stores unterstützt | +| Performance | Sehr gut auf Desktop. Auf Mobile abhängig von System-WebView-Qualität | +| Community | ~85k GitHub Stars, aktive Entwicklung | + +**Vorteile:** + +- Einziges Framework das alle 5 Plattformen mit einer Codebase abdeckt +- Winzige Bundles im Vergleich zu Electron +- Svelte/SvelteKit offiziell unterstützt +- Gute Plugin-Architektur + +**Nachteile:** + +- Mobile-Support erst seit Oktober 2024 stabil — für eine komplexe App mit 27+ Modulen ein Risiko +- WebView-Inkonsistenzen zwischen Plattformen (besonders ältere Android-Geräte) +- Rust-Toolchain für eigene Plugins nötig +- Plugin-Ökosystem kleiner als Capacitor oder Electron + +--- + +### 2. Capacitor (Ionic) + +**Funktionsweise:** Wrapping-Framework, das eine Web-App in einer nativen WebView-Shell ausführt. Entwickelt von Ionic (Nachfolger von Cordova). Bridge zu nativen APIs. + +**Plattformen:** iOS und Android (Kernfokus). Desktop nur via Electron-Plugin. + +| Aspekt | Bewertung | +|--------|-----------| +| SvelteKit-Wiederverwendung | Gut — SPA via `adapter-static`, offizielle Anleitungen verfügbar | +| IndexedDB/Dexie.js | Funktioniert, selbes iOS-WebKit-Limit wie Tauri | +| Native APIs | Sehr umfangreich — grösstes Plugin-Ökosystem aller WebView-Frameworks (Camera, Filesystem, Push, Haptics, Contacts, etc.) | +| Bundle-Grösse | 15–30 MB | +| App Store Distribution | Exzellent — explizit dafür gebaut, tausende Apps in den Stores | +| Performance | Gut für die meisten Anwendungsfälle | +| Community | Sehr gross, Version 6, produktionsbewährt (Burger King, Sworkit) | + +**Vorteile:** + +- Grösstes Plugin-Ökosystem für Mobile +- Sehr ausgereift und produktionsbewährt +- Einfache Integration (`npx cap sync`) +- Niedriger Wartungsaufwand + +**Nachteile:** + +- Kein nativer Desktop-Support — braucht zusätzlich Electron oder Tauri +- Für "alle Plattformen" sind zwei Frameworks nötig +- Selbe iOS-IndexedDB-Einschränkungen + +--- + +### 3. Electron + +**Funktionsweise:** Bündelt eine vollständige Chromium-Instanz + Node.js mit der Web-App. Die App läuft in ihrem eigenen Chrome-Browser. + +**Plattformen:** macOS, Windows, Linux. Kein Mobile-Support. + +| Aspekt | Bewertung | +|--------|-----------| +| SvelteKit-Wiederverwendung | Gut — SPA oder SSR mit Node-Adapter möglich | +| IndexedDB/Dexie.js | Exzellent — eigenes Chromium, keine Limits, konsistentes Verhalten | +| Native APIs | Sehr umfangreich — Dateisystem, Tray, Menüs, Dialoge, Shortcuts, Autostart, Protocol Handler u.v.m. Volles npm-Ökosystem | +| Bundle-Grösse | 80–200+ MB (Chromium + Node.js gebündelt) | +| App Store Distribution | Möglich (VS Code, Slack, Discord im Mac App Store) | +| Performance | Gut für UI, hoher RAM-Verbrauch (100–300 MB Baseline) | +| Community | Industriestandard seit 2013, riesige Community | + +**Vorteile:** + +- Beste IndexedDB-Unterstützung (eigenes Chromium, keine Plattform-Abhängigkeit) +- Ausgereiftestes Desktop-Framework +- Riesiges Ökosystem +- Node.js-Zugriff für Server-seitige Operationen + +**Nachteile:** + +- Kein Mobile-Support +- Sehr grosse Bundles (80–200 MB) +- Hoher RAM-Verbrauch +- Regelmässige Chromium-Sicherheitsupdates nötig + +--- + +### 4. PWA (Progressive Web App) + +**Funktionsweise:** Die bestehende Web-App wird mit Service Worker und Web App Manifest erweitert. Kein nativer Wrapper — läuft direkt im Browser. + +**Plattformen:** Alle (via Browser installierbar). iOS eingeschränkt. + +| Aspekt | Bewertung | +|--------|-----------| +| SvelteKit-Wiederverwendung | Perfekt — 100%, keine Anpassungen nötig | +| IndexedDB/Dexie.js | Funktioniert, aber **kritisch auf iOS: Safari löscht IndexedDB-Daten nach 7 Tagen Inaktivität** | +| Native APIs | Begrenzt — Notifications, Geolocation, Camera, Share API, Clipboard. Kein echtes Dateisystem (iOS), eingeschränkter Hintergrund-Sync | +| Bundle-Grösse | 0 MB zusätzlich | +| App Store Distribution | Schwierig — Apple lehnt reine WebView-Apps zunehmend ab. Google Play via TWA möglich | +| Performance | Identisch zur Web-Version | +| Community | Web-Standard, aber Apple treibt PWA-Support nicht voran | + +**Vorteile:** + +- Zero Aufwand — Service Worker + Manifest hinzufügen +- Sofort installierbar auf allen Plattformen +- Kein App-Store-Review nötig +- Updates sofort verfügbar + +**Nachteile:** + +- **Für local-first auf iOS nicht verlässlich** (7-Tage-IndexedDB-Löschung) +- Begrenzte native APIs +- Apple akzeptiert reine WebView-Apps kaum noch im App Store +- Keine echte "App-Erfahrung" auf iOS + +--- + +### 5. React Native / Expo + +**Funktionsweise:** Echte native UI-Komponenten, gesteuert durch JavaScript. Kein WebView — rendert direkt UIKit (iOS) bzw. Android Views. Neue Architektur (Fabric + TurboModules) seit 2024 Standard. + +**Plattformen:** iOS und Android (Kernfokus). Desktop experimentell (react-native-macos/windows von Microsoft). + +| Aspekt | Bewertung | +|--------|-----------| +| SvelteKit-Wiederverwendung | Keine — komplett andere Technologie (React + JSX statt Svelte) | +| IndexedDB/Dexie.js | Nicht verfügbar — Alternativen: SQLite, MMKV, WatermelonDB | +| Native APIs | Exzellent — voller Zugriff auf alle nativen APIs. 50+ Expo-Module | +| Bundle-Grösse | 20–50 MB | +| App Store Distribution | Exzellent — EAS Build + EAS Submit für automatisierte Store-Submissions | +| Performance | Beste Mobile-Performance aller Optionen (native Rendering) | +| Community | Sehr gross — Meta, Microsoft, Amazon, Shopify nutzen React Native | + +**Vorteile:** + +- Beste Performance auf Mobile (kein WebView-Overhead) +- Voller Zugang zu allen nativen APIs +- Bestehende Expo-Erfahrung und Apps im Monorepo +- OTA-Updates via EAS Update + +**Nachteile:** + +- **Kein Code-Sharing mit SvelteKit** — komplettes UI-Rewrite nötig +- Dexie.js/IndexedDB nicht verfügbar, Datenschicht muss komplett neu gebaut werden +- 27+ Module doppelt pflegen = enormer Aufwand +- Kein verlässlicher Desktop-Support + +--- + +### 6. Wails + +**Funktionsweise:** Wie Tauri, aber Backend in Go statt Rust. Nutzt die System-WebView. Go-Funktionen direkt aus dem Frontend aufrufbar. + +**Plattformen:** macOS, Windows, Linux. Kein Mobile-Support. + +| Aspekt | Bewertung | +|--------|-----------| +| SvelteKit-Wiederverwendung | Gut — SPA, Svelte offiziell unterstützt | +| IndexedDB/Dexie.js | Wie Tauri — abhängig von System-WebView | +| Native APIs | Basis — Fenster, Menüs, Dialoge, Events, Clipboard. Eigene APIs in Go | +| Bundle-Grösse | 5–15 MB | +| App Store Distribution | Desktop-Stores möglich | +| Performance | Gut auf Desktop | +| Community | Mittel (~26k Stars), Wails v3 seit langem in Entwicklung | + +**Vorteile:** + +- Passt zur bestehenden Go-Expertise (6 Go-Services im Monorepo) +- Kleine Bundles +- Go-Backend kann direkt auf bestehende Service-Logik zugreifen + +**Nachteile:** + +- Kein Mobile-Support +- Deutlich kleinere Community als Tauri oder Electron +- Weniger Native APIs als Tauri +- Wails v3 Entwicklung schleppend + +--- + +## Vergleichsmatrix + +| Kriterium | Tauri v2 | Capacitor | Electron | PWA | React Native | Wails | +|---|---|---|---|---|---|---| +| **iOS** | Ja (seit 2024) | Ja (ausgereift) | Nein | Eingeschränkt | Ja (ausgereift) | Nein | +| **Android** | Ja (seit 2024) | Ja (ausgereift) | Nein | Ja | Ja (ausgereift) | Nein | +| **macOS** | Ja | Via Electron | Ja | Via Browser | Experimentell | Ja | +| **Windows** | Ja | Via Electron | Ja | Via Browser | Experimentell | Ja | +| **Linux** | Ja | Via Electron | Ja | Via Browser | Nein | Ja | +| **SvelteKit direkt nutzbar** | Ja (SPA) | Ja (SPA) | Ja (SPA/SSR) | Ja (100%) | Nein | Ja (SPA) | +| **IndexedDB/Dexie.js** | Gut¹ | Gut¹ | Exzellent | Riskant² | N/A | Gut¹ | +| **Native API Umfang** | Gut | Sehr gut | Sehr gut | Begrenzt | Exzellent | Basis | +| **Bundle-Grösse** | 2–10 MB | 15–30 MB | 80–200 MB | 0 MB | 20–50 MB | 5–15 MB | +| **App Store tauglich** | Ja | Ja | Ja (Desktop) | Schwierig | Ja | Ja (Desktop) | +| **Community** | Gross (85k★) | Gross | Sehr gross | Web-Standard | Sehr gross | Mittel (26k★) | +| **Wartungsaufwand** | Mittel | Niedrig–Mittel | Mittel | Minimal | Hoch (2. Codebase) | Niedrig | + +¹ iOS-WebKit-Limit ~500 MB für IndexedDB +² iOS Safari: Löschung nach 7 Tagen Inaktivität + +--- + +## Empfehlung + +### Primärstrategie: Tauri v2 + +Tauri v2 ist das einzige Framework, das alle 5 Zielplattformen (iOS, Android, macOS, Windows, Linux) mit einer einzigen SvelteKit-Codebase abdeckt. Svelte ist offiziell unterstützt, die Bundles sind winzig, und die Plugin-Architektur ist erweiterbar. + +**Risiken die im Auge behalten werden müssen:** + +- Mobile-Support ist jung — gründliches Testing mit allen 27+ Modulen nötig +- WebView-Inkonsistenzen auf älteren Android-Geräten +- iOS-WebKit-Limit für IndexedDB (~500 MB) bei wachsender Datenmenge + +### Fallback: Capacitor (Mobile) + Tauri (Desktop) + +Falls Tauri v2 Mobile sich für die Komplexität der 27+ Module als zu unreif erweist: + +- **Capacitor** für iOS/Android — ausgereifter, grösstes Mobile-Plugin-Ökosystem +- **Tauri v2** für Desktop — leichtgewichtig, Svelte-First-Class +- Dieselbe SvelteKit SPA-Codebase für beide Wrapper + +### PWA als sofortige Massnahme + +Unabhängig von der nativen Strategie: Service Worker und Web App Manifest hinzufügen. Kostet fast nichts, bringt sofortige Installierbarkeit auf Desktop (Chrome/Edge). Auf iOS für local-first allerdings nicht verlässlich. + +### React Native / Expo nur für dedizierte Einzel-Apps + +Die bestehenden Expo-Apps im Monorepo machen Sinn für Module, die eine fundamental native Mobile-UX brauchen (z.B. Cards mit Swipe-Gesten, Chat mit nativen Push Notifications). Für "die gesamte unified App auf Mobile bringen" ist der Aufwand (komplettes Rewrite) nicht verhältnismässig. + +### IndexedDB-Risiko mitigieren + +Das grösste technische Risiko über alle WebView-Ansätze hinweg ist das iOS-WebKit-Verhalten: + +- **SQLite-Plugin als Alternative auf Mobile** — Tauri hat `tauri-plugin-sql`, Capacitor hat `@capacitor-community/sqlite` +- **Hybride Strategie:** IndexedDB im Web, SQLite im nativen Wrapper +- **Dexie.js** arbeitet an experimentellen SQLite-Backends (Dexie Cloud) + +--- + +## Nächste Schritte + +1. **PWA-Grundlagen einbauen** — Service Worker + Manifest für sofortige Desktop-Installierbarkeit +2. **Tauri v2 Proof-of-Concept** — SvelteKit-App als SPA mit adapter-static bauen, in Tauri laden, auf allen 5 Plattformen testen +3. **IndexedDB-Limits evaluieren** — Tatsächlichen Speicherbedarf der 120+ Collections messen, iOS-Verhalten unter Last testen +4. **SQLite-Fallback prototypen** — Dexie.js mit SQLite-Backend oder Storage-Abstraktionsschicht evaluieren +5. **Entscheidung treffen** — Basierend auf PoC-Ergebnissen: Tauri allein oder Capacitor+Tauri Kombi diff --git a/docs/PLAN_TAURI_V2.md b/docs/PLAN_TAURI_V2.md new file mode 100644 index 000000000..af0f4e2e7 --- /dev/null +++ b/docs/PLAN_TAURI_V2.md @@ -0,0 +1,627 @@ +# Implementierungsplan: PWA + Tauri v2 für ManaCore + +> Schrittweiser Plan um die ManaCore Unified Web App zuerst als PWA auszubauen und anschliessend als native Desktop- und Mobile-App via Tauri v2 auszuliefern — Plattform für Plattform. +> +> Stand: April 2026 + +--- + +## Übersicht + +### Roadmap + +``` +Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6 Phase 7 Phase 8 +PWA → SPA-Modus → macOS → Windows → Linux → Android → iOS → CI/CD & QA +(Web) (Basis) (Desktop) (Desktop) (Desktop) (Mobile) (Mobile) (alle) + + ◄── geringster Aufwand höchster Aufwand ──► +``` + +Jede Phase liefert ein funktionsfähiges Release. Man muss nicht alle Plattformen gleichzeitig fertig haben. + +### Zielstruktur + +``` +apps/manacore/ +├── apps/ +│ ├── web/ # Bestehende SvelteKit-App (Web + PWA) +│ ├── tauri/ # NEU: Tauri v2 Shell (alle nativen Plattformen) +│ │ ├── src-tauri/ +│ │ │ ├── src/ # Rust Backend +│ │ │ ├── capabilities/ # Permissions pro Plattform +│ │ │ ├── icons/ # App-Icons +│ │ │ ├── Cargo.toml +│ │ │ └── tauri.conf.json +│ │ └── package.json +│ └── ... +``` + +--- + +## Phase 1: PWA ausbauen + +**Ziel:** Die Web-App wird installierbar, offline-fähig und fühlt sich auf allen Geräten wie eine App an. Diese Arbeit ist **direkte Vorarbeit für Tauri** — nichts davon ist verschwendet. + +**Aufwand:** 1–2 Wochen (davon Responsive UI der grösste Posten) + +### 1.1 Service Worker Caching-Strategie + +`@vite-pwa/sveltekit` ist bereits integriert. Was fehlt ist eine durchdachte Caching-Strategie: + +- [ ] **App-Shell** (HTML, CSS, JS, Fonts) → Precaching (beim Install sofort cachen) +- [ ] **Modul-Assets** (Icons, Bilder) → Cache-First mit Stale-While-Revalidate +- [ ] **API-Calls** → Network-First mit Fallback auf Cache (für Offline-Lesbarkeit) +- [ ] **Dexie.js Daten** → Brauchen kein SW-Caching (liegen in IndexedDB) + +Konfiguration in `vite.config.ts` erweitern: + +```typescript +// Workbox-Strategien für @vite-pwa/sveltekit +{ + workbox: { + globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'], + runtimeCaching: [ + { + urlPattern: /^https:\/\/.*\.mana\.how\/api\//, + handler: 'NetworkFirst', + options: { cacheName: 'api-cache', expiration: { maxEntries: 100 } } + } + ] + } +} +``` + +### 1.2 Icons & Manifest vervollständigen + +- [ ] App-Icons in allen Grössen generieren (16×16 bis 512×512) +- [ ] Maskable Icon für Android (sichere Zone beachten) +- [ ] Apple Touch Icons (180×180) +- [ ] `manifest.json` Felder prüfen: + - `display: "standalone"` (kein Browser-Chrome) + - `orientation: "any"` + - `theme_color` und `background_color` + - `shortcuts` für Quick-Actions (Neue Aufgabe, Neuer Termin, etc.) + - `categories: ["productivity", "utilities"]` + +### 1.3 Offline-UX + +Da die App local-first ist, funktioniert sie offline bereits grundlegend. Was fehlt: + +- [ ] **Offline-Indikator** — dezentes Banner/Icon wenn kein Internet +- [ ] **Sync-Status-Anzeige** — "3 Änderungen warten auf Sync" +- [ ] **Graceful Degradation** — Module die Backend brauchen (Chat AI, Picture AI) zeigen "Offline" statt Error +- [ ] **Queued Actions** — Pending Changes sichtbar machen + +### 1.4 Update-Flow + +- [ ] "Neue Version verfügbar" Dialog wenn Service Worker updated +- [ ] Sanfter Übergang — nicht mitten in der Arbeit neu laden +- [ ] Skip-Waiting Strategie mit User-Bestätigung + +### 1.5 Responsive UI + +Der grösste Einzelposten — aber **identische Arbeit** die für Tauri Mobile (Phase 6–7) sowieso anfällt: + +- [ ] **Audit:** Welche der 27+ Module haben bereits Mobile-Breakpoints? +- [ ] **Navigation:** Sidebar → Bottom-Tab-Bar oder Hamburger-Drawer auf Mobile +- [ ] **Touch-Targets:** Mindestens 44×44px für alle interaktiven Elemente +- [ ] **Keyboard-Handling:** Input-Felder nicht von Soft-Keyboard verdeckt +- [ ] **Viewport Meta-Tag:** `viewport-fit=cover` für Edge-to-Edge +- [ ] **Hover-States:** Alternativen für Touch-Geräte (kein Hover) +- [ ] **Modale/Dialoge:** Full-Screen auf Mobile statt zentriertes Overlay + +### 1.6 Validierung + +- [ ] Chrome DevTools → Lighthouse PWA-Audit → Score 100 +- [ ] App installieren auf: macOS (Chrome), Windows (Edge), Android (Chrome), iOS (Safari) +- [ ] Offline testen: Flugmodus → App öffnen → CRUD-Operationen → Internet an → Sync +- [ ] Update testen: Neue Version deployen → "Update verfügbar" erscheint + +### 1.7 Bekannte PWA-Limitationen (beobachten, nicht lösen) + +Diese Punkte sind der Grund warum Tauri als nächster Schritt folgt: + +- iOS Safari: IndexedDB-Löschung nach 7 Tagen Inaktivität (betrifft local-first) +- iOS Safari: Keine Push-Notifications im Hintergrund +- Kein System Tray, keine globalen Shortcuts +- Kein Deep Link Protocol (`manacore://`) +- App Store Präsenz nicht möglich (ausser TWA auf Android) + +--- + +## Phase 2: SvelteKit SPA-Modus + +**Ziel:** Die Web-App kann als statische SPA gebaut werden — Voraussetzung für Tauri. + +**Aufwand:** 2–4 Tage + +### 2.1 Adapter-Static Konfiguration + +Aktuell nutzt die App `@sveltejs/adapter-node`. Für Tauri brauchen wir `adapter-static`: + +- [ ] `@sveltejs/adapter-static` als Dependency hinzufügen +- [ ] Build-Flag für Tauri-Modus: + +```js +// svelte.config.js +import adapterNode from '@sveltejs/adapter-node'; +import adapterStatic from '@sveltejs/adapter-static'; + +const isTauri = process.env.TAURI_ENV === 'true'; + +const config = { + kit: { + adapter: isTauri + ? adapterStatic({ pages: 'build-static', assets: 'build-static', fallback: 'index.html' }) + : adapterNode({ out: 'build' }), + }, +}; +``` + +- [ ] `fallback: 'index.html'` setzen für SPA-Routing (alle Routen → index.html) + +### 2.2 Server-seitige Logik auflösen + +**`hooks.server.ts` — Runtime Env-Injection (grösste Hürde):** + +Aktuell injiziert `hooks.server.ts` ~15 API-URLs als `window.__PUBLIC_*__` Variablen. Lösung: + +- [ ] Config-Abstraktionsschicht bauen die Web und Tauri bedient: + +```typescript +// src/lib/config/env.ts +export async function getApiUrl(key: string): Promise { + if (window.__TAURI__) { + const config = await invoke('get_config'); + return config[key]; + } + return window[`__PUBLIC_${key}__`] || import.meta.env[`PUBLIC_${key}`] || ''; +} +``` + +- [ ] Bestehende `window.__PUBLIC_*__` Lösung bleibt für Web-Deployment intakt + +**`hooks.server.ts` — Subdomain-Routing & Security Headers:** + +- [ ] Beide irrelevant in Tauri — werden automatisch übersprungen + +**Server-Routes (`routes/api/`, `routes/status/`):** + +- [ ] `routes/api/*` Endpunkte inventarisieren +- [ ] Falls Client sie aufruft: auf direkte Backend-Aufrufe umstellen +- [ ] `routes/status/+page.server.ts` → Client-seitige Health-Checks + +### 2.3 Validierung + +- [ ] `TAURI_ENV=true pnpm --filter @manacore/web build` erzeugt `build-static/` mit `index.html` +- [ ] `build-static/` in einem einfachen HTTP-Server testen (`npx serve build-static`) +- [ ] Alle 27+ Module durchklicken — Client-Side-Routing funktioniert +- [ ] **Go/No-Go:** Falls fundamental SSR-abhängig → Plan überdenken + +--- + +## Phase 3: macOS Desktop + +**Ziel:** ManaCore läuft als native Desktop-App auf macOS. Erste Tauri-Plattform. + +**Aufwand:** 2–3 Tage (inkrementell über SPA-Basis) + +**Warum zuerst:** Entwicklung passiert auf macOS → direktes Testen, kein Extra-Setup. Tauri Desktop seit 2022 stabil (4 Jahre Reife). WebKit auf macOS = gleiche Engine wie Safari, bekanntes Verhalten. Kein App Store nötig — DMG direkt verteilen. + +### 3.1 Voraussetzungen + +- [ ] Rust Toolchain installieren (`rustup`) +- [ ] Xcode installieren/aktualisieren (für macOS Builds) +- [ ] Tauri CLI: `pnpm add -D @tauri-apps/cli` + +### 3.2 Tauri-Projekt initialisieren + +- [ ] `apps/manacore/apps/tauri/` erstellen +- [ ] `package.json` mit Workspace-Referenz zu `@manacore/web` +- [ ] `tauri.conf.json` konfigurieren: + +```json +{ + "build": { + "beforeBuildCommand": "TAURI_ENV=true pnpm --filter @manacore/web build", + "devUrl": "http://localhost:5173", + "frontendDist": "../../web/build-static" + }, + "app": { + "title": "ManaCore", + "windows": [ + { + "title": "ManaCore", + "width": 1280, + "height": 800, + "minWidth": 800, + "minHeight": 600 + } + ] + }, + "bundle": { + "identifier": "how.mana.manacore", + "icon": ["icons/icon.png"] + } +} +``` + +### 3.3 Rust-Backend Setup + +- [ ] Minimales `src-tauri/src/main.rs` mit Config-Provider: + +```rust +#[tauri::command] +fn get_config() -> serde_json::Value { + serde_json::json!({ + "MANA_CORE_AUTH_URL": "https://auth.mana.how", + "SYNC_SERVER_URL": "wss://sync.mana.how", + // ... + }) +} +``` + +### 3.4 Capabilities & Permissions + +- [ ] `capabilities/default.json`: + - `core:default` (Fenster, Events) + - `http:default` (HTTP-Requests an Backend-APIs) + - `notification:default` (Benachrichtigungen) + - `clipboard-manager:default` (Zwischenablage) + - `shell:default` (URLs im Browser öffnen) + +### 3.5 Dev-Workflow einrichten + +- [ ] Turborepo-Tasks für `tauri:dev`, `tauri:build` +- [ ] Root-Level Script: `"dev:manacore:desktop": "pnpm --filter @manacore/tauri dev"` +- [ ] Tauri Dev-Mode nutzt Vite Dev-Server (`devUrl: http://localhost:5173`) → Hot Reload + +### 3.6 IndexedDB auf macOS WebKit testen + +- [ ] Dexie.js Persistenz: App schliessen → öffnen → Daten noch da? +- [ ] Speicherverbrauch der 120+ Collections messen +- [ ] WebSocket-Sync zu mana-sync funktioniert? +- [ ] Reconnect nach Sleep/Wake? + +### 3.7 Validierung + +- [ ] App startet als natives macOS-Fenster +- [ ] Login/Auth funktioniert (gegen mana-auth) +- [ ] IndexedDB/Dexie.js persistiert Daten +- [ ] Sync funktioniert (WebSocket zu mana-sync) +- [ ] Mindestens 10 Module durchklicken und testen +- [ ] **Go/No-Go:** IndexedDB/Sync stabil? → Weiter. Instabil? → Electron-Fallback evaluieren. + +--- + +## Phase 4: Windows Desktop + +**Ziel:** ManaCore als native Windows-App. + +**Aufwand:** 2–3 Tage (inkrementell über macOS) + +**Warum als Zweites:** Relevanteste Desktop-Plattform nach macOS. Nutzt WebView2 (Chromium-basiert) — **andere Rendering-Engine als macOS** (WebKit). Das Testen hier bereitet auf Android vor (ebenfalls Chromium-basiert). + +### 4.1 Voraussetzungen + +- [ ] Windows-Testumgebung (VM, Dual-Boot, oder CI) +- [ ] WebView2 Runtime (auf Windows 10/11 vorinstalliert, Fallback für ältere Systeme einrichten) +- [ ] Rust Target hinzufügen: `rustup target add x86_64-pc-windows-msvc` + +### 4.2 Plattform-spezifische Anpassungen + +- [ ] NSIS oder MSI Installer konfigurieren in `tauri.conf.json` +- [ ] Code Signing Zertifikat beschaffen und einrichten +- [ ] Windows-spezifische Fenster-Optionen (Dekorationen, Startmenü-Integration) + +### 4.3 Rendering-Unterschiede testen + +Da WebView2 auf Chromium basiert (≠ macOS WebKit): + +- [ ] CSS Rendering vergleichen (Flexbox, Grid, Scrollbars) +- [ ] IndexedDB-Verhalten prüfen (Chromium hat andere Limits/Verhalten als WebKit) +- [ ] Font-Rendering prüfen (Windows rendert Fonts anders) +- [ ] Scroll-Verhalten (Windows hat keine Rubber-Band-Scrolling) + +### 4.4 Validierung + +- [ ] App startet auf Windows 10 + 11 +- [ ] Alle Module funktionieren (besonders UI-intensive: Calendar, Presi, Music) +- [ ] Installer erzeugt saubere Installation + Deinstallation +- [ ] Auto-Start Option funktioniert + +--- + +## Phase 5: Linux Desktop + +**Ziel:** ManaCore als native Linux-App. + +**Aufwand:** 0.5–1 Tag (inkrementell über macOS) + +**Warum als Drittes:** Technisch fast identisch zu macOS (beide WebKitGTK-basiert). Geringster zusätzlicher Aufwand aller Plattformen. Kein Signing nötig. + +### 5.1 Voraussetzungen + +- [ ] Linux-Testumgebung (VM, WSL2, oder GPU-Server) +- [ ] WebKitGTK + System-Dependencies: `sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev` +- [ ] Rust Target: `rustup target add x86_64-unknown-linux-gnu` + +### 5.2 Paketformate + +- [ ] AppImage generieren (universell, kein Install nötig) +- [ ] DEB-Paket für Debian/Ubuntu +- [ ] Optional: RPM für Fedora, Flatpak für breitere Distribution + +### 5.3 Validierung + +- [ ] App startet auf Ubuntu 22.04+ und Fedora 38+ +- [ ] WebKitGTK-spezifische Rendering-Checks +- [ ] AppImage funktioniert ohne Installation +- [ ] System-Tray Integration (falls in Phase 8 implementiert) + +--- + +## Phase 6: Android + +**Ziel:** ManaCore als Android-App im Play Store. + +**Aufwand:** 1–2 Wochen (inkrementell über Desktop) + +**Warum vor iOS:** Android WebView basiert auf Chromium — ähnlich wie Windows WebView2, also bereits vertrautes Terrain. Kein Developer Account nötig zum Testen (APK Sideloading). Tauri v2 Android-Support ist etwas reifer als iOS. + +### 6.1 Voraussetzungen + +- [ ] Android Studio + Android SDK installieren +- [ ] Android Emulator oder physisches Testgerät +- [ ] Tauri Android-Target: `tauri android init` +- [ ] Keystore für Signing erstellen +- [ ] Google Play Developer Account (25$ einmalig) + +### 6.2 Android-spezifische Anpassungen + +- [ ] `AndroidManifest.xml` — Permissions (Internet, Notifications, Camera falls nötig) +- [ ] Minimum SDK Version festlegen (API 24 / Android 7.0 = WebView 80+) +- [ ] Status Bar / Navigation Bar Farben anpassen +- [ ] Back-Button Verhalten (Android Hardware-Back) +- [ ] Splash Screen (`tauri-plugin-splash-screen`) + +### 6.3 Responsive UI auf echten Geräten testen + +Die Responsive-Arbeit aus Phase 1.5 (PWA) wird hier validiert: + +- [ ] Navigation auf kleinen Screens (Bottom-Tab / Drawer) +- [ ] Touch-Targets auf verschiedenen Bildschirmgrössen +- [ ] Landscape vs Portrait Orientation +- [ ] Soft-Keyboard schiebt Layout nicht kaputt +- [ ] Scroll-Performance in langen Listen + +### 6.4 WebView-Versionen + +Grösstes Android-spezifisches Risiko — die System-WebView variiert je nach Gerät: + +- [ ] Minimum WebView-Version definieren und enforzen +- [ ] Auf älteren Geräten testen (Android 8, 9, 10) +- [ ] Feature-Detection für kritische APIs (IndexedDB, WebSocket) + +### 6.5 Mobile-spezifische Plugins + +- [ ] `tauri-plugin-haptics` — Haptisches Feedback bei Interaktionen +- [ ] `tauri-plugin-biometric` — Fingerprint für Login +- [ ] Push Notifications via FCM (Firebase Cloud Messaging) + +### 6.6 Play Store Vorbereitung + +- [ ] App-Icons in allen Android-Grössen (Adaptive Icons) +- [ ] Play Store Screenshots (Phone + Tablet) +- [ ] Privacy Policy URL +- [ ] App-Beschreibung (Deutsch + Englisch) +- [ ] Internal Testing Track einrichten +- [ ] AAB (Android App Bundle) statt APK für Store-Upload + +### 6.7 Validierung + +- [ ] App läuft auf Android 10+ stabil +- [ ] IndexedDB-Persistenz über App-Neustarts +- [ ] Sync funktioniert (inkl. Reconnect nach Background/Foreground) +- [ ] Play Store Internal Testing erfolgreich +- [ ] **Go/No-Go:** Android stabil? → Weiter zu iOS. Probleme? → Capacitor als Mobile-Fallback evaluieren. + +--- + +## Phase 7: iOS + +**Ziel:** ManaCore als iOS-App im App Store. + +**Aufwand:** 1–2 Wochen (inkrementell über Android) + +**Warum zuletzt:** Höchster Overhead aller Plattformen: Apple Developer Account (99$/Jahr), Provisioning Profiles, Xcode-Pflicht, strengster App Store Review. iOS WebKit hat die strengsten IndexedDB-Limits. Hier entscheidet sich ob ein SQLite-Fallback nötig wird. + +### 7.1 Voraussetzungen + +- [ ] Apple Developer Account (99$/Jahr) — zwingend auch zum Testen auf echtem Gerät +- [ ] Xcode aktualisieren (neueste Version) +- [ ] Provisioning Profile + Signing Certificates erstellen +- [ ] Tauri iOS-Target: `tauri ios init` +- [ ] Physisches iOS-Gerät zum Testen (Simulator reicht nicht für alles) + +### 7.2 iOS-spezifische Anpassungen + +- [ ] `Info.plist` — Permissions, URL Schemes, Privacy Descriptions +- [ ] Safe Area Insets (Notch, Dynamic Island, Home Indicator) +- [ ] `viewport-fit=cover` + CSS `env(safe-area-inset-*)` für Edge-to-Edge +- [ ] iOS-spezifische Scroll-Bouncing / Overscroll-Verhalten +- [ ] Status Bar Style (Light/Dark Content je nach Theme) + +### 7.3 IndexedDB Stresstest (kritisch) + +Das ist der **wichtigste Test der gesamten Roadmap:** + +- [ ] Speicherverbrauch der 120+ Collections unter realer Nutzung messen +- [ ] iOS WebKit-Limit (~500 MB) Stresstest — wie nah kommen wir? +- [ ] Persistenz: App schliessen → Tage warten → öffnen → Daten noch da? +- [ ] Vergleich: PWA Safari vs installierte Tauri-App (Tauri sollte stabiler sein) + +Falls Limits zum Problem werden: + +- [ ] `tauri-plugin-sql` (SQLite) als Fallback evaluieren +- [ ] Hybride Strategie: IndexedDB im Web, SQLite in Tauri iOS +- [ ] Storage-Abstraktionsschicht in Dexie.js integrieren + +### 7.4 Mobile-spezifische Plugins (iOS) + +- [ ] `tauri-plugin-haptics` — Taptic Engine Feedback +- [ ] `tauri-plugin-biometric` — Face ID / Touch ID +- [ ] Push Notifications via APNs (Apple Push Notification service) +- [ ] Optional: `tauri-plugin-barcode-scanner` für QR-Codes + +### 7.5 App Store Vorbereitung + +- [ ] App-Icons in allen iOS-Grössen (1024×1024 Store Icon) +- [ ] App Store Screenshots (iPhone 6.7", 6.1", iPad) +- [ ] App Store Beschreibung + Keywords (Deutsch + Englisch) +- [ ] Privacy Policy + Terms of Service URLs +- [ ] App Review Information (Demo-Account für Apple Reviewer) +- [ ] TestFlight einrichten für Beta-Tester + +### 7.6 App Store Review vorbereiten + +Apple prüft strenger als Google. Wichtige Punkte: + +- [ ] Guideline 4.2 (Minimum Functionality) — App muss Mehrwert über Website hinaus bieten +- [ ] Tauri erzeugt echte native Apps (kein reiner WebView-Wrapper) → sollte akzeptiert werden +- [ ] Native Features dokumentieren (Notifications, Biometrics, Haptics) als Differenzierung zur Web-App +- [ ] Offline-Fähigkeit hervorheben + +### 7.7 Validierung + +- [ ] App läuft auf iOS 16+ stabil (iPhone + iPad) +- [ ] IndexedDB-Persistenz über Wochen (!) testen +- [ ] Face ID / Touch ID funktioniert +- [ ] Push Notifications kommen an +- [ ] TestFlight Beta-Test erfolgreich +- [ ] App Store Review bestanden + +--- + +## Phase 8: Desktop-Features, CI/CD & Qualitätssicherung + +**Ziel:** Plattformübergreifende Stabilität, native Desktop-Features und automatisierte Builds. + +**Aufwand:** 2–3 Wochen + +### 8.1 Desktop-Features (alle Desktop-Plattformen) + +- [ ] **System Tray** — `tauri-plugin-positioner`, Minimieren in Tray, Quick-Actions +- [ ] **Auto-Updater** — `tauri-plugin-updater`, Update-Server, In-App Dialog +- [ ] **Native Notifications** — `tauri-plugin-notification`, Calendar-Erinnerungen +- [ ] **Globale Shortcuts** — `Cmd/Ctrl+N` (Neues Item), `Cmd/Ctrl+K` (Quick-Suche), `Cmd/Ctrl+1-9` (Modul wechseln) +- [ ] **Deep Links** — `manacore://` Protocol für Links aus Emails/Chat +- [ ] **Dateisystem** — Drag & Drop, "Öffnen mit", Export (PDF/CSV) + +### 8.2 Build Pipeline (Forgejo CI) + +- [ ] macOS Build → DMG + App Bundle +- [ ] Windows Build → MSI + NSIS Installer +- [ ] Linux Build → AppImage + DEB +- [ ] Android Build → APK + AAB +- [ ] iOS Build → IPA +- [ ] Signing für alle Plattformen automatisieren +- [ ] Build-Artefakte als Releases veröffentlichen + +### 8.3 Auto-Update Infrastruktur + +- [ ] Update-Server / Release-Endpunkt auf Mac Mini +- [ ] Versionierung: SemVer aus Git-Tags +- [ ] Delta-Updates wo möglich + +### 8.4 App Store Deployment + +- [ ] Apple App Store: Upload via `xcrun altool` oder Transporter +- [ ] Google Play: Upload via Fastlane oder Play Console API +- [ ] Optional: Microsoft Store (MSIX), Snapcraft (Linux) + +### 8.5 Testmatrix + +| Test | macOS | Windows | Linux | Android | iOS | +|------|-------|---------|-------|---------|-----| +| App startet | | | | | | +| Login/Auth | | | | | | +| IndexedDB Persistenz | | | | | | +| Sync (Push/Pull) | | | | | | +| WebSocket Reconnect | | | | | | +| Alle 27+ Module | | | | | | +| Offline-Modus | | | | | | +| Auto-Update | | | | | | +| Deep Links | | | | | | +| Native Notifications | | | | | | +| Biometrics | — | — | — | | | + +### 8.6 Performance-Benchmarks + +- [ ] Cold-Start: Ziel < 2s Desktop, < 3s Mobile +- [ ] RAM: Ziel < 150 MB Desktop, < 100 MB Mobile +- [ ] IndexedDB R/W Performance: Web vs Tauri vergleichen +- [ ] Scroll-Performance mit 1000+ Items in Listen + +### 8.7 Edge Cases + +- [ ] Kein Internet → App funktioniert offline +- [ ] Sleep/Wake → Sync reconnect +- [ ] Mehrere Desktop-Instanzen gleichzeitig +- [ ] Web-Nutzer öffnet Desktop-App → Daten synchronisieren automatisch + +--- + +## Aufwand-Übersicht + +| Phase | Plattform | Aufwand (inkrementell) | Kumuliert | Grösste Hürde | +|-------|-----------|----------------------|-----------|---------------| +| **1** | PWA (Web) | 1–2 Wochen | 1–2 Wochen | Responsive UI | +| **2** | SPA-Basis | 2–4 Tage | ~2.5 Wochen | `hooks.server.ts` → Client-Config | +| **3** | macOS | 2–3 Tage | ~3 Wochen | — (geringster Aufwand) | +| **4** | Windows | 2–3 Tage | ~3.5 Wochen | Andere Rendering-Engine (Chromium) | +| **5** | Linux | 0.5–1 Tag | ~3.5 Wochen | Nur Testen | +| **6** | Android | 1–2 Wochen | ~5.5 Wochen | WebView-Versionen älterer Geräte | +| **7** | iOS | 1–2 Wochen | ~7.5 Wochen | IndexedDB-Limits, App Store Review | +| **8** | CI/CD & QA | 2–3 Wochen | ~10 Wochen | Plattformübergreifende Stabilität | + +**Gesamt: ca. 8–12 Wochen** von PWA bis zur stabilen Auslieferung auf allen 5 Plattformen + App Stores. + +### Was jede Phase freischaltet + +| Nach Phase | Nutzer können... | +|------------|-----------------| +| Phase 1 | App auf jedem Gerät aus dem Browser installieren (PWA) | +| Phase 3 | ManaCore als macOS Desktop-App nutzen (DMG) | +| Phase 4 | ManaCore als Windows Desktop-App nutzen (Installer) | +| Phase 5 | ManaCore auf Linux nutzen (AppImage) | +| Phase 6 | ManaCore aus dem Play Store installieren | +| Phase 7 | ManaCore aus dem App Store installieren | +| Phase 8 | Automatische Updates, native Features, stabile CI/CD | + +--- + +## Risiken & Mitigationen + +| Risiko | Wahrscheinlichkeit | Impact | Mitigation | +|--------|-------------------|--------|------------| +| iOS WebKit IndexedDB-Limit | Mittel | Hoch | SQLite-Fallback evaluieren (Phase 7.3) | +| WebView-Inkonsistenzen Android | Mittel | Mittel | Minimum WebView-Version enforzen, Polyfills | +| Server-Routes im SPA-Modus | Sicher | Mittel | Phase 2.2 löst dies systematisch | +| Tauri Mobile Bugs | Mittel | Hoch | Capacitor als Fallback bereithalten | +| App Store Rejection (Apple) | Niedrig | Hoch | Native Features als Differenzierung betonen | +| Bundle-Grösse zu gross | Niedrig | Niedrig | Tauri-Bundles typisch 2–10 MB | +| Responsive UI Aufwand unterschätzt | Mittel | Mittel | In Phase 1 (PWA) anpacken, nicht aufschieben | + +--- + +## Entscheidungspunkte (Go/No-Go) + +| Nach Phase | Frage | Falls Nein | +|------------|-------|------------| +| **Phase 2** | Funktioniert die App stabil als SPA? | Falls fundamental SSR-abhängig → Architektur überdenken | +| **Phase 3** | Läuft Desktop auf macOS? IndexedDB/Sync stabil? | → Electron als Desktop-Fallback | +| **Phase 6** | Android stabil? WebView-Performance akzeptabel? | → Capacitor als Mobile-Fallback | +| **Phase 7** | iOS IndexedDB-Persistenz ausreichend? | → SQLite-Fallback oder Capacitor + SQLite | +| **Phase 7** | App Store Review bestanden? | → Native Features nachrüsten, ggf. Capacitor |