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

107
docs/PRIVACY.md Normal file
View File

@@ -0,0 +1,107 @@
# Datenschutz und Datenverarbeitung
Dieses Dokument beschreibt den aktuellen technischen Stand von FeelAloud. Es
ist eine Entwicklungsdokumentation und ersetzt keine individuell geprüfte,
öffentlich erreichbare Datenschutzerklärung für den App Store.
## Kurzfassung
FeelAloud hat kein Konto, kein eigenes Backend, keine Werbung, kein Tracking
und keine Analyse-SDKs. Die App überträgt nach aktuellem Code keine
Tagebuchdaten an den Entwickler. Produktdaten verbleiben lokal, bis die Person
selbst einen Export über das iOS-Share-Sheet auslöst.
## Verarbeitete Daten
| Datenart | Zweck | Speicherort | Automatische Übertragung |
| --- | --- | --- | --- |
| Mikrofon-Audio während einer Aufnahme | Spracherkennung | Nur laufende Audio-Pipeline | Nein; On-Device-Erkennung wird erzwungen |
| Transkript | Tagebucheintrag und lokale Strukturierung | SwiftData nach Bestätigung | Nein |
| Stimmungs- und Ohrwurmfelder | Persönliche Dokumentation | SwiftData | Nein |
| Check-in-Wert und Kontextnotiz | Verlauf und Durchschnitt | SwiftData | Nein |
| Erinnerungszeiten | Lokale Notification-Planung | UserDefaults über `@AppStorage` | Nein |
| XLSX-/CSV-Datei | Freiwilliger Export | Temporäres App-Verzeichnis | Nur über selbst gewähltes Share-Ziel |
## Berechtigungen
### Mikrofon
Wird erst beim Start einer Spracheingabe angefragt. Das Audio wird an
`SFSpeechAudioBufferRecognitionRequest` übergeben und nicht als Audiodatei
gespeichert.
### Spracherkennung
Der Request setzt `requiresOnDeviceRecognition = true`. Ist die lokale deutsche
Erkennung nicht verfügbar, bricht FeelAloud ab und bietet eine manuelle Eingabe
an. Es existiert kein eigener Cloud-Fallback.
### Mitteilungen
Wird erst beim Aktivieren täglicher Erinnerungen angefragt. Die Erinnerungen
werden mit `UNCalendarNotificationTrigger` lokal geplant. Der Notification-
Inhalt enthält keine gespeicherte Stimmung und keinen Tagebuchtext.
## Lokale KI
FeelAloud verwendet `SystemLanguageModel.default` aus Apples Foundation Models.
Vor der Nutzung wird die Verfügbarkeit geprüft. Das Modell erhält das
Transkript und soll ausschließlich strukturierte Felder extrahieren. Die Person
prüft das Ergebnis vor dem Speichern.
Foundation Models sind kein Diagnosesystem. Der Prompt untersagt medizinische
Einschätzungen, Ratschläge und das Erfinden nicht genannter Inhalte.
## Speicherung, Aufbewahrung und Löschung
- Einträge und Check-ins liegen im lokalen SwiftData-Store des App-Containers.
- Einstellungen liegen in den lokalen UserDefaults des App-Containers.
- Es gibt keine automatische Aufbewahrungsfrist und keine Cloud-Synchronisation
durch eigenen App-Code.
- Der aktuelle Stand besitzt noch keine Schaltfläche **Alle Daten löschen**.
Das Entfernen der App löscht den lokalen App-Container. Eine In-App-Löschung
ist vor einer öffentlichen Veröffentlichung empfohlen.
- Falls später iCloud, Backup, Crash Reporting oder ein Backend ergänzt wird,
müssen dieses Dokument, die öffentliche Datenschutzerklärung, das Privacy
Manifest und die App-Store-Angaben neu bewertet werden.
## Export und Weitergabe
Ein Export erfolgt nur nach Tippen auf eine Exportfunktion. Anschließend zeigt
iOS das Share-Sheet. Ab diesem Zeitpunkt bestimmt die Person selbst das Ziel,
zum Beispiel Dateien, Mail oder eine Therapie-Praxis. Für den Datenschutz des
gewählten Ziels ist FeelAloud technisch nicht mehr zuständig.
Exporte können besonders sensible Freitexte enthalten. Die Oberfläche und die
App-Store-Beschreibung sollten darauf deutlich hinweisen.
## Privacy Manifest
`FeelAloud/PrivacyInfo.xcprivacy` deklariert:
- kein Tracking;
- keine vom Entwickler gesammelten Datentypen;
- Zugriff auf UserDefaults mit Required-Reason-Code `CA92.1`, ausschließlich
zum Lesen und Schreiben app-eigener Einstellungen.
Vor jedem App-Store-Upload sollte Xcodes Privacy Report geprüft werden. Neue
Frameworks oder APIs können weitere Required-Reason-Einträge erforderlich
machen.
## Erwartete App-Store-Datenschutzangabe
Auf Basis des derzeitigen Codes ist voraussichtlich **Data Not Collected** die
passende Angabe für die durch den Entwickler erhobenen Daten. Diese Einschätzung
muss unmittelbar vor der Einreichung anhand des finalen Builds und aller
aktivierten Apple-Dienste erneut geprüft werden.
TestFlight selbst kann im Auftrag von Apple Crash-, Nutzungs- und freiwillige
Feedbackdaten verarbeiten. Diese Verarbeitung ist von der Produktlogik der App
zu unterscheiden.
## Medizinischer und sicherheitsbezogener Hinweis
FeelAloud dient nur der persönlichen Dokumentation. Die App erkennt keine
Krisen zuverlässig und ersetzt weder medizinische Beratung noch Therapie oder
Notfallhilfe. Marketingtexte dürfen keine Diagnose- oder Heilversprechen
enthalten.

129
docs/QA-CHECKLIST.md Normal file
View File

@@ -0,0 +1,129 @@
# QA- und Release-Checkliste
Diese Liste ist für einen Release Candidate auf einem echten iPhone gedacht.
Simulator-Tests allein reichen wegen Foundation Models, lokaler
Spracherkennung, Notifications und Action Button nicht aus.
## Build und Installation
- [ ] Clean Build mit der Release-Konfiguration erfolgreich
- [ ] Keine neuen Compilerwarnungen
- [ ] Automatisches Signing verwendet das erwartete Team
- [ ] Bundle-ID entspricht App Store Connect
- [ ] Marketing-Version und Build-Nummer sind korrekt
- [ ] App-Icon erscheint scharf auf Home Screen, Spotlight und Einstellungen
- [ ] Display Name lautet **FeelAloud**
- [ ] App läuft nur als iPhone-Target und nicht versehentlich als iPad-App
## Erststart und Berechtigungen
- [ ] Erststart zeigt keine unnötige Berechtigungsabfrage
- [ ] Mikrofonabfrage erscheint erst beim ersten Spracheintrag
- [ ] Speech-Abfrage erscheint nur für die Spracheingabe
- [ ] Ablehnung des Mikrofons erzeugt eine verständliche Meldung
- [ ] Ablehnung der Spracherkennung erzeugt eine verständliche Meldung
- [ ] Mitteilungsabfrage erscheint erst beim Aktivieren der Erinnerungen
- [ ] Bei abgelehnten Mitteilungen wird der Toggle zurückgesetzt
## Spracheintrag
- [ ] Aufnahme startet und die rote Stop-Schaltfläche ist erreichbar
- [ ] Teiltranskript erscheint während der Aufnahme
- [ ] Stoppen beendet Mikrofon und Audio Session
- [ ] Deutsche lokale Spracherkennung funktioniert im Flugmodus
- [ ] Nicht verfügbare lokale Spracherkennung fällt nicht auf Cloud zurück
- [ ] Leeres Transkript zeigt eine hilfreiche Meldung
- [ ] Manuelle Eingabe ist jederzeit möglich
## Lokale KI und Prüfmaske
- [ ] Foundation-Models-Status wird unter **Mehr** korrekt angezeigt
- [ ] Ein typischer deutscher Text wird sinnvoll strukturiert
- [ ] Nicht erwähnte Songnamen oder Aktivitäten werden nicht erfunden
- [ ] Alle KI-Felder lassen sich vor dem Speichern korrigieren
- [ ] Musik im Kopf blendet Ohrwurmfelder ein
- [ ] Ohne Musik im Kopf wird stattdessen Stress angeboten
- [ ] Nicht verfügbares Modell führt zur manuellen Eingabe
- [ ] Flugmodus verändert den lokalen KI-Pfad nicht
## Momentaufnahmen und Follow-up
- [ ] Manuelle Check-in-Schaltfläche öffnet genau fünf Gesichter
- [ ] Jede Stufe speichert exakt einen Snapshot
- [ ] Mehrfaches schnelles Tippen erzeugt keine Duplikate
- [ ] Haptisches Erfolgsfeedback wird ausgelöst
- [ ] **Gut** erzeugt keine Kontextfrage
- [ ] **Mittel** erzeugt keine Kontextfrage
- [ ] **Sehr gut** fragt beim nächsten normalen Öffnen am selben Tag nach
- [ ] **Schlecht** fragt beim nächsten normalen Öffnen am selben Tag nach
- [ ] **Sehr schlecht** fragt beim nächsten normalen Öffnen am selben Tag nach
- [ ] Kontextantwort wird gespeichert und im Verlauf angezeigt
- [ ] **Heute nicht mehr fragen** unterdrückt nur diesen Snapshot
- [ ] Offene Kontextfragen eines Vortags erscheinen nicht am Folgetag
## Erinnerungen
- [ ] Auswahl zwischen zwei und drei Erinnerungen funktioniert
- [ ] Alle konfigurierten Uhrzeiten erzeugen lokale Requests
- [ ] Ändern einer Uhrzeit ersetzt alte Requests
- [ ] Deaktivieren entfernt alle drei stabilen Requests
- [ ] Banner erscheint im Vordergrund
- [ ] Tipp auf Banner im Hintergrund öffnet den Check-in
- [ ] Tipp auf Banner nach Kaltstart öffnet den Check-in
- [ ] Notification-Öffnung löst nicht sofort eine alte Kontextfrage darüber aus
- [ ] Zeitzonen- und Sommerzeitwechsel wurden plausibilisiert
## Persistenz und Verlauf
- [ ] Gespeicherte Einträge bleiben nach App-Neustart erhalten
- [ ] Gespeicherte Check-ins bleiben nach App-Neustart erhalten
- [ ] 7-Tage-Filter enthält heute und die sechs vorherigen Kalendertage
- [ ] 30-Tage-Filter enthält heute und die 29 vorherigen Kalendertage
- [ ] Gesamtzeitraum beginnt beim ältesten Datensatz
- [ ] Eigener Zeitraum funktioniert auch bei vertauschten Von-/Bis-Daten
- [ ] Durchschnitt stimmt rechnerisch mit den sichtbaren Punkten überein
- [ ] Diagramm zeigt Werte 1 bis 5 korrekt
- [ ] Eintragsdetail zeigt alle bedingten Felder korrekt
## Export
- [ ] Export ist ohne Daten deaktiviert
- [ ] XLSX-Dateiname enthält den gewählten Datumsbereich
- [ ] XLSX öffnet ohne Reparaturmeldung in Apple Numbers
- [ ] XLSX öffnet ohne Reparaturmeldung in Microsoft Excel
- [ ] Arbeitsblatt **Übersicht** enthält Anzahl und korrekten Durchschnitt
- [ ] Arbeitsblatt **Momentaufnahmen** enthält Kontext und Quelle
- [ ] Arbeitsblatt **Tagebuch** enthält die Einträge des gewählten Zeitraums
- [ ] Umlaute, Emoji, Zeilenumbrüche, `&`, `<`, `>` und Anführungszeichen bleiben erhalten
- [ ] CSV besitzt UTF-8-BOM und Semikolon-Trennung
- [ ] CSV escaped Semikolon, Anführungszeichen und Zeilenumbrüche korrekt
- [ ] Abbrechen des Share-Sheets verändert keine gespeicherten Daten
## Systemintegration
- [ ] Kurzbefehl **Eintrag aufnehmen** erscheint nach Installation
- [ ] Kurzbefehl öffnet die App im Aufnahmefluss
- [ ] Action Button kann dem Kurzbefehl zugewiesen werden
- [ ] Action Button startet die Aufnahme zuverlässig aus gesperrtem/aktivem Zustand
## Oberfläche und Barrierefreiheit
- [ ] Light Mode und Dark Mode sind lesbar
- [ ] Größte Dynamic-Type-Größen verdecken keine primären Aktionen
- [ ] VoiceOver liest die fünf Bewertungen eindeutig vor
- [ ] Aufnahme-/Stop-Aktion besitzt ein eindeutiges Accessibility Label
- [ ] Farbige Informationen sind zusätzlich durch Text oder Symbol erkennbar
- [ ] Bedienung funktioniert auf der kleinsten unterstützten iPhone-Größe
- [ ] Deutsche Texte sind frei von abgeschnittenen oder überlappenden Elementen
## Datenschutz und Release Gate
- [ ] Netzwerkverkehr des Release Builds zeigt keinen eigenen Datenupload
- [ ] Keine personenbezogenen Testdaten liegen in Git oder Build-Artefakten
- [ ] `PrivacyInfo.xcprivacy` ist im erzeugten App-Bundle enthalten
- [ ] Xcode Privacy Report enthält keine unerklärten Required-Reason-APIs
- [ ] App-Store-Datenschutzangaben entsprechen dem finalen Build
- [ ] Öffentliche Datenschutz- und Support-URLs sind erreichbar
- [ ] Medizinischer Hinweis ist in App und Metadaten vorhanden
- [ ] TestFlight-Testhinweise nennen Geräte- und iOS-Voraussetzungen
- [ ] Bekannte Blocker sind dokumentiert und akzeptiert

133
docs/TESTFLIGHT.md Normal file
View File

@@ -0,0 +1,133 @@
# TestFlight- und Release-Ablauf
## Voraussetzungen
- Mac mit Xcode 26 oder neuer
- Apple Developer Program-Mitgliedschaft
- Berechtigung als Account Holder, Admin oder App Manager in App Store Connect
- Apple-Intelligence-kompatibles Test-iPhone mit iOS 26 oder neuer
- öffentlich erreichbare Support- und Datenschutz-URLs für eine spätere
App-Store-Veröffentlichung
## 1. Bundle-ID und Signing vorbereiten
1. `FeelAloud.xcodeproj` öffnen.
2. Target **FeelAloud** auswählen.
3. Unter **Signing & Capabilities** das richtige Team wählen.
4. Die voreingestellte Bundle-ID lautet `de.feelaloud`.
5. Falls sie im gewählten Team nicht verfügbar ist, eine dauerhaft eindeutige
Bundle-ID festlegen. Nach dem ersten Upload sollte sie nicht mehr geändert
werden.
6. **Automatically manage signing** aktiviert lassen, sofern kein eigener
manueller Signing-Prozess verwendet wird.
Zertifikate, `.p12`-Dateien, Provisioning Profiles und private Schlüssel gehören
nicht ins Git-Repository.
## 2. App in App Store Connect anlegen
1. In App Store Connect **Apps → + → New App** wählen.
2. Plattform **iOS** auswählen.
3. Primärsprache festlegen.
4. Als Arbeitsname **FeelAloud** verwenden.
5. Die zuvor registrierte Bundle-ID auswählen.
6. Eine interne SKU vergeben, beispielsweise `feelaloud-ios-001`.
Mögliche Metadaten für die spätere Produktseite:
| Feld | Entwurf |
| --- | --- |
| Name | `FeelAloud Mood & Voice Diary` |
| Untertitel | `Private check-ins and insights` |
| Kategorie | Health & Fitness |
| Altersfreigabe | Im App-Store-Fragebogen bestimmen |
Die Namensverfügbarkeit wird erst in App Store Connect verbindlich sichtbar.
## 3. Release-Konfiguration prüfen
Vor jedem Upload:
- `MARKETING_VERSION` kontrollieren, aktuell `1.0`;
- `CURRENT_PROJECT_VERSION` erhöhen, aktuell `1`;
- App-Icon und Display Name prüfen;
- Mikrofon- und Speech-Nutzungstexte kontrollieren;
- Privacy Manifest und App Privacy Report prüfen;
- die vollständige Checkliste in `QA-CHECKLIST.md` auf einem echten Gerät
durchführen;
- sicherstellen, dass keine Secrets oder personenbezogenen Testexporte im
Repository liegen.
Jeder Upload zu App Store Connect benötigt eine neue Build-Nummer.
## 4. Archiv erstellen und hochladen
1. In Xcode als Ziel **Any iOS Device (arm64)** oder ein angeschlossenes iPhone
auswählen.
2. **Product → Archive** wählen.
3. Im Organizer **Distribute App** öffnen.
4. **App Store Connect → Upload** auswählen.
5. Automatische Signing- und Symbol-Optionen prüfen.
6. Validierung abschließen und Build hochladen.
7. Die Verarbeitung in App Store Connect abwarten.
Alternativ kann der Upload über Xcode Cloud automatisiert werden, sobald ein
geeigneter macOS-CI-Prozess eingerichtet ist.
## 5. Interne Tests
1. In App Store Connect die App öffnen.
2. Tab **TestFlight** auswählen.
3. Testinformationen und Kontakt-E-Mail hinterlegen.
4. Eine interne Testergruppe anlegen.
5. Den verarbeiteten Build der Gruppe zuweisen.
6. Testende installieren die App über TestFlight.
Interne Tests sind der schnellste Weg für Teammitglieder. Für Personen außerhalb
des App-Store-Connect-Teams ist ein externer Test erforderlich.
## 6. Externe Tests
1. Externe Gruppe anlegen und Build hinzufügen.
2. Beta-Beschreibung, Testschwerpunkte und Kontaktinformationen ausfüllen.
3. Build zur Beta App Review einreichen.
4. Nach Freigabe per E-Mail oder öffentlichem TestFlight-Link einladen.
Empfohlener Testhinweis:
> FeelAloud benötigt ein Apple-Intelligence-kompatibles iPhone mit iOS 26.
> Bitte prüfe Spracheingabe, lokale Auswertung, tägliche Check-ins,
> Erinnerungen und Excel-Export. Die App ist kein Medizinprodukt.
## 7. Empfohlene App-Review-Notizen
- Die App besitzt kein Login und kein Backend.
- Mikrofon und Speech Recognition werden nur für einen aktiv gestarteten
Spracheintrag verwendet.
- Die Spracherkennung wird auf dem Gerät erzwungen.
- Foundation Models strukturieren Text lokal; alle Werte können vor dem
Speichern korrigiert werden.
- Erinnerungen sind lokale Notifications.
- Ein manueller Eingabepfad ist vorhanden, falls lokale Modelle nicht bereit
sind.
- Testgerät muss Apple Intelligence und die deutsche Spracherkennung
unterstützen.
## 8. Veröffentlichungsvoraussetzungen außerhalb TestFlight
Vor einem öffentlichen App-Store-Release zusätzlich erledigen:
- öffentliche Datenschutz- und Support-Seite bereitstellen;
- App-Store-Datenschutzfragebogen mit dem finalen Build abgleichen;
- Marken- und Namensprüfung abschließen;
- Screenshots für alle verlangten iPhone-Größen erstellen;
- Beschreibung, Keywords, Copyright und Review-Kontakt ergänzen;
- Datenlöschung innerhalb der App prüfen beziehungsweise implementieren;
- medizinische Aussagen und Krisenhinweise rechtlich prüfen;
- Release Candidate auf mehreren echten Geräten testen.
## Offizielle Referenzen
- [Apple: TestFlight](https://developer.apple.com/testflight/)
- [Apple: Foundation Models](https://developer.apple.com/documentation/foundationmodels)
- [Apple: Required Reason APIs](https://developer.apple.com/documentation/bundleresources/describing-use-of-required-reason-api)