Initial FeelAloud project

This commit is contained in:
MrDiderot
2026-07-22 22:18:33 +02:00
commit 10fca0756d
48 changed files with 8942 additions and 0 deletions

152
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,152 @@
# Architektur
## Überblick
FeelAloud ist eine einzelne native iOS-App ohne Backend und ohne externe
Paketabhängigkeiten. Alle Produktdaten werden mit Apple-Frameworks auf dem
Gerät verarbeitet. Das Xcode-Projekt enthält derzeit ein App-Target.
## Komponenten
| Datei | Verantwortung |
| --- | --- |
| `FeelAloudApp.swift` | App-Einstieg, SwiftData-Container und globaler Router |
| `RootView.swift` | Tabs, Sheets, App-Intent-Ausführung und Follow-up-Auswahl |
| `HomeView.swift` | Startseite, Schnellaktionen und 7-Tage-Zusammenfassung |
| `EntryFlowView.swift` | Aufnahme-, Analyse-, Prüf- und Speicherablauf |
| `SpeechRecognizer.swift` | Mikrofon, lokale deutsche Spracherkennung und Transkript |
| `MoodAnalysisService.swift` | Typisierte Extraktion über Foundation Models |
| `MoodEntry.swift` | Datenmodell eines ausführlichen Tagebucheintrags |
| `MoodSnapshot.swift` | Datenmodell und Regeln eines kurzen Check-ins |
| `SnapshotView.swift` | Fünf-Stufen-Auswahl und spätere Kontextfrage |
| `SnapshotNotificationScheduler.swift` | Lokale Erinnerungen und Notification-Routing |
| `HistoryView.swift` | Zeitraumfilter, Diagramm, Detailansichten und Exportstart |
| `SettingsView.swift` | Erinnerungszeiten, KI-Status, CSV-Export und Hinweise |
| `XLSXExporter.swift` | OOXML-Arbeitsmappe und minimaler ZIP-Writer |
| `CSVExporter.swift` | Semikolon-CSV mit UTF-8-BOM für Numbers/Excel |
| `StartDiaryEntryIntent.swift` | Kurzbefehl und Action-Button-Integration |
| `ShareSheet.swift` | Übergang zum systemweiten iOS-Share-Sheet |
## Datenfluss: ausführlicher Eintrag
1. `EntryFlowView` startet `SpeechRecognizer`.
2. `SpeechRecognizer` fordert Mikrofon- und Speech-Berechtigung an und setzt
`requiresOnDeviceRecognition = true`.
3. Nach dem Stoppen erhält `MoodAnalysisService` ausschließlich das erkannte
Transkript.
4. `LanguageModelSession` erzeugt eine typisierte `GeneratedDiaryEntry`-Antwort.
5. Die Person prüft und korrigiert alle Werte im Formular.
6. Erst die bestätigten Werte werden als `MoodEntry` in SwiftData gespeichert.
Ist Sprache oder Foundation Models nicht verfügbar, kann die Person zur
manuellen Eingabe wechseln. Die App fällt nicht auf einen eigenen Cloud-Dienst
zurück.
## Datenfluss: Momentaufnahme
1. Ein Check-in wird manuell oder über eine lokale Mitteilung geöffnet.
2. Ein Tipp erzeugt einen `MoodSnapshot` mit Wert 1 bis 5 und Quelle.
3. Bei **Sehr gut**, **Schlecht** oder **Sehr schlecht** bleibt
`awaitsFollowUp` aktiv.
4. Beim nächsten normalen Aktivieren der App am selben Kalendertag sucht
`RootView` den jüngsten offenen Snapshot.
5. Eine Antwort setzt `followUpNote`; **Heute nicht mehr fragen** setzt
`followUpDismissed`.
Das direkte Öffnen aus einer Mitteilung unterdrückt genau eine sofortige
Follow-up-Prüfung, damit zuerst die gewünschte Fünf-Stufen-Auswahl erscheint.
## Persistenz
Der `ModelContainer` verwaltet zwei SwiftData-Modelle:
### MoodEntry
| Feld | Zweck |
| --- | --- |
| `id`, `createdAt` | Eindeutigkeit und Zeitpunkt |
| `moodRaw` | Dreistufige Bewertung des ausführlichen Eintrags |
| `musicInHead`, `songName`, `earwormStrengthRaw` | Musik-/Ohrwurmangaben |
| `socialContact` | Sozialkontakt vorhanden |
| `distressRaw` | Leidensdruck durch Musik im Kopf |
| `countermeasures`, `countermeasureActivity` | Gegenmaßnahmen |
| `stress` | Stress, wenn keine Musik im Kopf vorhanden ist |
| `transcript` | Bestätigter gesprochener Text |
### MoodSnapshot
| Feld | Zweck |
| --- | --- |
| `id`, `createdAt` | Eindeutigkeit und Zeitpunkt |
| `ratingRaw` | Fünfstufige Bewertung |
| `followUpNote` | Später ergänzter Kontext |
| `followUpDismissed` | Kontextfrage für diesen Snapshot verworfen |
| `sourceRaw` | `manual` oder `notification` |
Für zukünftige Schemaänderungen muss vor Veröffentlichung einer inkompatiblen
Version ein `VersionedSchema` mit `SchemaMigrationPlan` eingeführt werden.
## Routing und Lebenszyklus
`AppRouter` ist ein `@MainActor`-gebundener, beobachtbarer Singleton. Er hält
nur flüchtigen UI-Zustand. `RootView` reagiert auf:
- manuelle Aktionen der Oberfläche;
- `StartDiaryEntryIntent`;
- Antworten auf lokale Mitteilungen;
- Wechsel der `scenePhase` zurück zu `.active`.
Persistente Produktdaten liegen nicht im Router, sondern ausschließlich in
SwiftData beziehungsweise `@AppStorage` für Erinnerungseinstellungen.
## Erinnerungen
`SnapshotNotificationScheduler` verwendet drei stabile Request-IDs. Beim
Ändern der Konfiguration werden bestehende Requests entfernt und neu geplant.
Die Trigger enthalten nur Stunde und Minute und wiederholen sich täglich.
Es handelt sich um lokale Notifications. APNs, Push-Zertifikate und ein Server
sind nicht erforderlich.
## Export
Der XLSX-Exporter erstellt drei Arbeitsblätter:
1. **Übersicht** Zeitraum, Anzahl, Durchschnitt und Verteilung;
2. **Momentaufnahmen** Zeitpunkt, Bewertung, Kontext und Quelle;
3. **Tagebuch** strukturierte Felder und Transkript.
Die Arbeitsmappe besteht aus OOXML-Dateien in einem unkomprimierten ZIP-Archiv.
Text wird XML-escaped; ZIP-Einträge erhalten CRC32-Prüfsummen. Der CSV-Export
bleibt als kompatibler Alt-Export für ausführliche Einträge erhalten.
Temporäre Exportdateien werden im temporären App-Verzeichnis erzeugt und erst
nach einer ausdrücklichen Aktion an das Share-Sheet übergeben.
## Fehler- und Verfügbarkeitsmodell
- Fehlende Berechtigungen werden als verständliche, lokale Fehlermeldung
angezeigt.
- Fehlende lokale Spracherkennung verhindert eine versehentliche Cloud-
Transkription.
- Vor jeder KI-Nutzung wird `SystemLanguageModel.default.availability` geprüft.
- Fehler beim Speichern werden aktuell nicht sichtbar eskaliert (`try?`). Vor
einem öffentlichen Release sollte dafür ein zentraler Fehlerpfad ergänzt
werden.
- FeelAloud erteilt keine medizinischen Ratschläge und gibt dem Modell
ausdrücklich nur eine Extraktionsaufgabe.
## Abhängigkeiten
Es gibt keine Drittanbieterpakete. Verwendete Frameworks:
- AppIntents
- AVFoundation
- Charts
- Foundation / FoundationModels
- Observation
- Speech
- SwiftData
- SwiftUI
- UIKit
- UserNotifications