Initial FeelAloud project
This commit is contained in:
152
docs/ARCHITECTURE.md
Normal file
152
docs/ARCHITECTURE.md
Normal 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
107
docs/PRIVACY.md
Normal 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
129
docs/QA-CHECKLIST.md
Normal 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
133
docs/TESTFLIGHT.md
Normal 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)
|
||||
Reference in New Issue
Block a user