Files
FeelAloud/docs/ARCHITECTURE.md
2026-07-22 22:18:33 +02:00

6.0 KiB
Raw Permalink Blame History

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