ExpenseCategory DTO + GET /api/expenses/categories beim Öffnen der Liste
sowie bei Refresh. Falls der Endpunkt noch nicht ausgerollt ist (oder
fehlschlägt), Fallback auf eine lokale Default-Liste mit den aktuellen
sechs Kategorien.
AddExpenseSheet bekommt die Kategorien als Parameter, statt eigene
Liste zu führen — Source of Truth ist jetzt das Backend.
Backend-Whitelist: tierarzt, futter, zubehoer, versicherung, sitter, sonstiges.
Bisher schickte ich großgeschriebene Display-Strings, daher HTTP 400
'Ungültige Kategorie: Futter'. Jetzt: interner Key kleingeschrieben für die
API, label() für die Anzeige in der Liste und im Picker.
Tagebuch (Diary):
- DiaryEntry + DiaryMedia + DiaryCreateBody DTOs
- TagebuchView: Liste der Einträge für aktiven Hund mit Titel, Text,
Ortsname, Meilenstein-Stern, Foto-Strip
- AddDiaryEntrySheet: Titel/Text/Datum/Meilenstein/Ort/Tags +
PhotosPicker, nach POST /api/dogs/{id}/diary werden Fotos einzeln
via POST /api/dogs/{id}/diary/{entry_id}/media hochgeladen (mit
ImageResize.resizedJPEG)
Heim-Tab als neuer 1. Tab:
- DashboardSnapshot DTO für /api/dogs/{id}/welcome-dashboard
- ActiveDogStore (@Observable + UserDefaults("activeDogId")): hält
den aktiven Hund app-weit
- HeimView: tägliches Hintergrundfoto aus random_photo.url (rotiert
pro Tag, vom Backend gewählt), Gradient zur Lesbarkeit, Tagezeit-
Begrüßung mit User-Namen, Hund-Picker (Menu), Info-Karten für
letzten Eintrag/nächsten Termin/Gewicht/Eintragszahl,
Quick-Action-Buttons (Tagebuch, Wetter, Erste Hilfe)
Reorganisation:
- 5 Tabs: Heim, Touren, Aufnehmen, Statistik, Mehr
- Hunde-Liste wandert in Mehr → "Hund & Alltag"
- Tagebuch in Mehr → "Hund & Alltag" + erreichbar von Heim
Pitch-Karte erweitert um die neuen Features (sowie Hundesitting, Züchter).
Neue DTOs in DTOs.swift:
- Expense + ExpenseCreateBody
- GassiZeit + GassiZeitCreateBody (mit wochentage [String], radius_m)
- PoisonAlert + PoisonCreateBody
- LostDog + LostDogCreateBody
- WeatherForecast + WeatherDay (mit asphalt_temp, zecken, pollen-Felder)
Neue Views:
- ErsteHilfeView + Detail: sechs Notfall-Topics (Vergiftung, Hitzschlag,
Wunden, Atemnot, Krampfanfall, Magendrehung) — komplett offline, kein API
- AusgabenView: Liste mit Total, AddExpenseSheet mit Kategorie/Betrag/
Datum/Hund-Picker
- WetterView: One-Shot Location + /api/weather/forecast, 7-Tage-Vorhersage
mit Hunde-Tipps (Hitze ab 25°/30°, Frost, Asphalt ≥50°, Zecken, Regen)
- GassiZeitenView: eigene Zeiten + Add-Sheet (Wochentag-Picker, Hund-
Auswahl), automatische lokale UNCalendarNotifications via Scheduler
- GiftkoederView: Map mit Pins + Liste in 5km Umkreis, Report-Sheet mit
Typ-Auswahl
- VerloreneHundeView: Liste mit Foto/Distanz, Detail mit Karte
Support:
- OneShotLocation: kleiner CLLocationManager-Wrapper für einmalige
Positionsabfrage (Wetter, Giftköder)
- GassiZeitenScheduler: UNCalendarNotificationTrigger pro Wochentag,
Identifier-Schema "gz-{id}-{weekday}"
Navigation: Section "Hund & Alltag" im Mehr-Tab mit NavigationLinks zu
allen sechs neuen Ansichten.
- icon_transparent.py: pur-weiße Pixel werden zu #C4843A umgefärbt — der
GPS-Pfad zwischen Pin und Hund ist jetzt auf jedem Hintergrund sichtbar
- LoginView Pitch jetzt als ausklappbare Karte ('Tippen für Details')
mit spring-Animation
- Sechs Punkte statt vier: Gassi-Touren, Hunde-Community, Tagebuch & Impfpass,
Verifizierte Züchter (rosette), Giftköder-Alarm, Hundesitting (house.fill)
- icon_transparent.py: blauer Sky-Hintergrund per RGB-Schwelle entfernt
(b > 0.55, b > r+0.05 …), trimmt auf Content-Bbox
- AppIconHero.imageset mit dem freigestellten Icon
- LoginView komplett neu strukturiert als ScrollView:
- Hero: freigestelltes App-Icon (kein SF Symbol mehr) + Titel + Tagline
- Pitch-Karte: vier Feature-Highlights (Gassi-Tracking, Community,
Tagebuch, Giftköder-Alarm) für Leute, die banyaro nicht kennen
- "Schon angemeldet?"-Karte mit dem klassischen Login-Form
- "Neu hier?"-Karte mit kostenlos/DSGVO/DE-Hosting-Pitch und großem
Register-Button mit person.crop.circle.badge.plus-Icon
D.10 401-Handling: APIError.unauthorized, NotificationCenter-Bridge,
AuthSession.logout() bei 401 → User landet wieder im Login
D.12 PWA-Deep-Links: Settings-Section mit Forum/Hunde/Walks/Settings
öffnet Safari per https://banyaro.app/#fragment
B.4 Auto-Pause: 2-min-Inaktivität → isAutoPaused, automatischer Resume bei
nächstem GPS-Update. Settings-Toggle, im UI eigenes Badge "Auto-Pause"
(grau vs. Pause orange).
C.7 Edit/Delete: RouteUpdateBody + APIClient.patch + APIClient.delete,
EditRouteSheet (Name/Beschreibung/Public), Menu in Toolbar (nur eigene
Touren), Alert für Delete.
C.9 Statistik-Tab: neuer Tab "Statistik" zwischen Hunde und Mehr. Filtert
/api/routes auf meine Touren, rechnet Woche/Monat/Allzeit (Distanz, Dauer,
Touren), Längste Tour, aktuelle Streak (Tage in Folge).
B.5 Walk-Review: Map-Header an die Spitze des FinishWalkSheet-Forms.
B.6 Geo-Fotos: CapturedPhoto (Data + GPSPoint?), PhotoLocation @Model in
SwiftData. Kamera während Walk taggt mit tracker.points.last. Nach Upload:
foto_url aus Response → PhotoLocation persistiert. MiniRouteMap rendert
Annotations mit Tap-Callback, PhotoViewerSheet zeigt Foto fullscreen.
C.8 Share PNG+GPX: RouteShareImage (MKMapSnapshotter + Polyline overlay +
SwiftUI ShareCard via ImageRenderer), GPXExporter (Tempfile mit XML),
ShareSheet (UIActivityViewController-Wrapper), Menu in Route-Toolbar.
D.11 Icon-Varianten: AppIcon-Dark (0.45 Brightness), AppIcon-Tinted
(Grayscale + Kontrastverstärkung), Contents.json mit appearance entries.
A.2 HealthKit: BanYaroGo.entitlements (com.apple.developer.healthkit),
NSHealthShare/UpdateUsageDescription. WalkHealthSync.shared mit
HKWorkoutBuilder (.walking) + HKWorkoutRouteBuilder, Timestamps gleichmäßig
über Walk-Dauer verteilt. Settings-Toggle mit Permission-Request.
LocationTracker:
- isPaused, pausedAt, accumulatedPausedSeconds
- pause()/resume()/restore() Methoden
- effectiveElapsedSeconds rechnet Pausen raus
- restore() für nach App-Crash: Offline-Lücke wird als Pause gezählt
ActiveWalk @Model (SwiftData):
- startedAt, lastUpdate, pausedAt, accumulatedPausedSeconds, pointsData
- Container in BanYaroGoApp registriert
TrackingView:
- Persistenz alle 5s via Timer
- confirmationDialog beim Erscheinen wenn ActiveWalk vorhanden:
Fortsetzen / Jetzt speichern / Verwerfen
- Pause/Resume-Button + Stop-Button
- Floating Kamera-Button rechts unten
- Foto-Counter in der Stats-Karte
- Pause-Badge oben links bei Pause
CameraPicker: UIImagePickerController-Wrapper (Fallback auf Library im Simulator).
FinishWalkSheet: initialPhotos: [Data] für Kamera-Fotos während Tour.
RouteDetailView: PhotosPicker zum Hinzufügen von Fotos zu bestehender Tour,
sequentieller Upload mit Progress, Detail wird nach Upload refreshed.
NSCameraUsageDescription in BanYaroGo-Info.plist.
- APIClient.uploadFile: multipart POST mit Bearer-Token, generischer
field/filename/mime
- ImageResize: längste Kante max 2048px, JPEG q=0.8 — iPhone-Fotos sonst
5-10MB pro Stück
- FinishWalkSheet:
- PhotosPicker (iOS 16+, kein NSPhotoLibraryUsageDescription nötig)
- Thumbnail-Strip der gewählten Fotos
- Sequentieller Upload nach POST /api/routes, Toolbar zeigt "N/M"
- Bei < 50m: orangene Warnung "Sehr kurze Tour — du kannst trotzdem speichern"
- Save-Button blockt korrekt während Upload, Verwerfen auch
Das Backend bool-konvertiert nur is_premium explizit; alle anderen 0/1-Spalten
gehen unverändert durch FastAPI. Decode-Fehler vorher still verschluckt → jetzt
auch geloggt, damit das nicht nochmal passiert.
Login liefert nur {token, name, is_premium}. Für Admin-/Founder-/Tier-Info
holen wir nach Login (und beim Erscheinen von MainTabView) /api/auth/me und
zeigen ein echtes Profil mit Avatar, Email, Rolle und nur dann Premium-Status,
wenn das relevant ist.