73 KiB
TODO:
- Fehler: Explore ohne Filterfunktion
- Benachrichtigung - Button klein Alles Gelesen markieren.
- Head-Bereich verdeckt Handy-Infos nicht lesbarer Bereich Uhrzeit, WIFI Battery - Bitte GoogleRichtlinen beachten
- Dark-Mode ? wo ?
TODO Neu:
- Explore Filter ist jetzt vorhanden, der Rassen-Dropdown, schiebt die Vorhanden elemente nach unten statt darüber zu lappen.
- Explore Seite ist nur Halb im Darkmode
- Benachrichtiungsseite nicht wirklich im Darkmode
TODO Neu2:
- Sprache ist Standard Englisch auch schon im Login-Screen, hier wäre bei der ersten Einwahl in die App, eine Prüfung der Systemsprache wichtig damit direkt Englisch oder Deutsch ausgewählt wird. → Ursache: expo-localization (Geräte-Spracherkennung) ist als natives Modul noch nicht in den Dev-Client eingebunden, daher greift aktuell immer der Englisch-Fallback. Löst sich mit dem geplanten nativen Rebuild von selbst.
- Im Feed habe ich als Nutzer keine Möglich einen Beitrag zu Reporten! Das wäre wichtig. Report-Funktion ist in der Webansicht vollfunktionsfähig und wird im Admin-Bereich getrackt. → Melden-Button (⋮) auf jedem Beitrag, 5 Report-Gründe, live getestet (Übermittlung + Speicherung bestätigt).
- Bilder lassen sich nicht Vergrößern mit 2 Fingern. → Pinch-to-Zoom im Bild-Viewer ergänzt (ohne neue native Abhängigkeit). Über adb nicht als echte Zwei-Finger-Geste simulierbar, daher nur Code+Typecheck geprüft, nicht live.
- Innerhal des Tierprofils + Gesundheitskarte ist der DarkMode nicht umgesetzt → Tierprofil, Profil bearbeiten, Follower/Folgt sowie die komplette Gesundheitsseite (inkl. Einwilligungs-Screen) sind jetzt dark-mode-fähig, live bestätigt.
- Gesundheitsdaten werden nicht gespeichert, sowie kein Zurückbutton sobald man fertig ist mit der bearbeitung der daten. → Zurück-Pfeil war nur unsichtbar (schwarz auf schwarzem Header im Dark Mode), jetzt auf allen Unterseiten sichtbar. Speicherproblem lag am Datumsformat (nächster Punkt) plus fehlender Fehlermeldung bei ungültiger Eingabe — beides behoben, End-to-End getestet.
- Datum wird Korrekt dargestellt, die eingabe ist aber, aktuelle ansicht JJJJ-MM-DD // korrekt wäre DD-MM-JJJJ → Eingabefelder akzeptieren jetzt TT-MM-JJJJ, werden intern korrekt umgewandelt; ungültige Eingaben zeigen eine Fehlermeldung.
- Gewichtsdaten werden nicht als Diagramm angezeigt (feature)
→ Echtes Feature, kein Bug — noch offen, Rückmeldung ob/wann gewünscht.
→ Umgesetzt (04.10.): Neues
WeightChart(src/components/health/WeightChart.tsx, Port des Web-Diagramms mitreact-native-svg) erscheint ab 2 Einträgen über der Gewichtsliste. Die x-Achse ist zeitproportional (unregelmäßige Wiegetermine werden nicht verzerrt), die y-Achse hat runde Werte, Datumslabels überlappen nicht (bei über einem Jahr „Feb. 25“). Antippen wählt die nächste Messung, Wert + Datum stehen im Kopf; rechts die Veränderung seit der ersten Messung. Linienfarbe als neues TokenchartLine(#ea580c), mit dem Dataviz-Validator gegen helle und dunkle Flächen geprüft (Kontrast ≥ 3:1). Geometrie insrc/lib/weight-chart.tsmit 11 Tests; die Darstellung habe ich als Vorschau mit der echten Geometrie in Hell + Dunkel gerendert und geprüft. Commite60abba, OTA Runtime 1.0.6: Android16d95168-caf2-4c0d-a0c7-730acd1bfb96, iOSd8e82f19-2a66-4f21-9558-b16296a7ba3f. Nicht auf einem Gerät getestet. - Technische Frage, was wird beim Feed abgerufen? Zum vergleich in der Web umgebung wird mein feed(followerbezogen) und der trend (könnte dir auch gefallen) seperat eingeblendet, wird in der App eine kombination daraus gemacht ? falls ja super. → Nein: Mobile Feed zeigt ausschließlich den chronologischen Follower-Feed (feed.getFeed, mode "chrono"). Web's separater "Trending"-Tab (explore.getTrending, "könnte dir auch gefallen") ist in der App noch gar nicht gebaut — bekannte Lücke, bereits in der README dokumentiert.
- unter meine Tiere, bitte Impressum datenschutz und agbs als link einbinden. sowie eine Versionsnummer der App → Links + "Version 1.0.0" unterhalb der Sprachauswahl ergänzt, live getestet (Impressum öffnet im Browser).
- Symbole für Deutsch Englisch und Automatisch im Meine tiere menü ändern. auf flaggen z.b. → 🇩🇪 / 🇬🇧 / 🌐 statt Icon, live bestätigt.
- Benachrichtigungen trennen zwischen den einzelnen Benachrichtigungen für mehr optik → Sichtbare Trennlinie zwischen den Einträgen ergänzt, live bestätigt.
- Benachrichtigungen sind nicht anklickbar, sollten aber zu dem jeweiligen Post / Pet gehen. → Tap markiert als gelesen und navigiert zum Ziel (Post-Kommentare bzw. Tierprofil je nach Typ), live bestätigt.
- Drei Punkte, menü im Feed, falls es der eigene Beitrag ist, lösch funktion hinzufügen, statt Report. → Bei eigenem Beitrag öffnet "⋮" jetzt einen Lösch-Bestätigungsdialog statt der Report-Ansicht, bei fremden Beiträgen bleibt Report wie gewohnt; beides live bestätigt.
- im Feed fehlt ein Indikator wenn in einem Post mehrere Bilder hinterlegt sind. das wischen funktioniert, aber nur wenn man weiß das dort mehrere bilder hinterlegt sind. unwissende würde nur ein bild sehen können. → Zähler-Badge oben rechts ("1 / 3") plus Punkte-Indikator unter dem Bild ergänzt (analog zur Web-Version), live bestätigt.
- Kommentar Fenster ist nicht im Darkmode
- Tier Anlegen ist nicht im Darkmode + Rassen werden als Dropdown angezeigt lassen sich aber nicht scrollen.
→ Darkmode: PetCreateForm.tsx + onboarding/pet.tsx nutzten noch die statischen (Hell-only)
colors/typographystattuseTheme()— umgestellt auf das gleiche Muster wie sign-up.tsx/OptionPicker.tsx. Scroll-Bug: onboarding/pet.tsx nutzte als äußeren Container ein normalesScrollView, darin verschachtelt der Rassen-Dropdown (OptionPicker) sein eigenesScrollView— zwei gleichachsige ScrollViews ineinander verschlucken auf Android die Scroll-Geste des inneren, auch mitnestedScrollEnabled. Fix: äußeren Container aufFlatList(leere Liste +ListHeaderComponent) umgestellt, exakt das bereits funktionierende Muster aus explore.tsx für dieselbe OptionPicker-Komponente. Typecheck + Lint sauber, i18n-Parität unverändert (243/243) — nicht live auf Android getestet (kein Emulator in dieser Session), nur strukturell gegen den bekannten Explore-Fix abgeglichen. - Nach dem Speichern des ersten Tiers, und dem Hochladen des Profilfotos, wird man wieder zurück geworfen auf Tier erstellen. erst ein neustart der app lässt einen auf den feed zugreifen. (BUG)
→ Ursache:
pets.create-Mutation in PetCreateForm.tsx hat dietrpc.pets.list-Query (ActivePetContext) nie invalidiert. Nach dem Avatar-Schritt landet man in(app), aberOnboardingRedirect(app/_layout.tsx) sah dort weiterhin den alten, leeren Pets-Stand aus dem Cache und schickte sofort wieder zurück nach/onboarding/pet— nur ein Neustart hat die Liste frisch geladen. Fix:queryClient.invalidateQueriesauftrpc.pets.listdirekt imonSuccessder Create-Mutation. Typecheck sauber.
TODO Neu3:
- Videos die angeklickt werden, laufen in Endlosschleife weiter obwohl man im Feed weiter scrollt.
→ expo-video hat kein eingebautes "bin ich noch sichtbar"-Bewusstsein; der Player lief nach dem Wegscrollen einfach weiter (mit
loop = true). Neuer HookuseVisiblePostIds(FlatList-viewabilityConfigCallbackPairs) trackt sichtbare Post-IDs,isVisible-Prop läuft durch PostCard → VideoPlayer, der beim Verschwindenplayer.pause()aufruft. In Feed UND Tierprofil-Postliste verdrahtet (beide nutzen VideoPlayer). Typecheck + Lint sauber, nicht live auf Android getestet (kein Emulator in dieser Session). - Profilbilder sind nicht vergrößerbar
→ Das Tierprofilbild (Tierprofil-Kopfbereich, size="lg") war reines, nicht antippbares
<Image>. Öffnet jetzt bei Vorhandensein eines Avatars den bereits vorhandenen/image-viewer(denselben Viewer inkl. Pinch-to-Zoom, den Beitragsbilder schon nutzen) mit dem vollen Avatar-Bild. Ohne hinterlegtes Foto (Initialen-Fallback) bleibt es unangetippt, da nichts zu vergrößern ist. Typecheck + Lint sauber. Nicht live getestet (kein Emulator in dieser Session). - Profilbearbeiten, lässt sich die Rasse nicht mehr ändern; wäre wichtig wenn man bei der Erstellung Fehler gemacht hat.
- Sowie kann man beim Tier kein Geburtstag hinterlegen oder Adoptionstag wie es im Web vorhanden ist.
→ Beides war nur eine Mobile-UI-Lücke, das Backend (
pets.update) unterstütztbreedId/birthday/adoptedAtbereits (Web nutzt es längst). Rassen-Dropdown aus PetCreateForm.tsx in eine geteilteBreedPicker-Komponente ausgelagert (DRY) und in edit.tsx eingebaut (Tierart selbst bleibt fix, nur die Rasse ist neu wählbar). Geburtstag/Adoptionstag als TT-MM-JJJJ-Textfelder ergänzt, gleiches Validierungs-/Konvertierungsmuster wie bei den Health-Formularen (date-format.ts). Da BreedPicker wie zuvor ein eigenes ScrollView verschachtelt, wurde edit.tsx aus demselben Grund wie onboarding/pet.tsx vonScrollViewaufFlatListumgestellt. Typecheck + Lint sauber (ein vorbestehender, nicht selbst verursachterset-state-in-effect-Lint-Hinweis in der bereits vorhandenen Effect besteht unverändert fort), i18n-Parität 247/247. Nicht live getestet (kein Emulator in dieser Session). - Meilensteine sind nicht im Darkmode verfügbar
→ milestones.tsx (Liste) und milestone-new.tsx (neuer Meilenstein) nutzten noch die statischen (Hell-only)
colors/typographystattuseTheme()— auf das etabliertemakeStyles(colors)-Muster umgestellt. Typecheck sauber, Lint zeigt nur vorbestehende, nicht selbst verursachte Warnungen (fehlendest-Dep, fehlendesalt). Nicht live getestet (kein Emulator in dieser Session).
TODO Neu4 (Tester-Feedback aus der Google Group, Closed Testing):
- Im Darkmode hatte ein User nach dem Login "alles in Schwarz" gesehen (kein Gerät bekannt).
→ Zwei konkrete Lücken gefunden und behoben: (1) Der
LoadingScreeninapp/_layout.tsx(Anzeige während Fonts/Clerk-Auth laden, u.a. direkt nach dem Login) war fest auf helle Farben verdrahtet, da er vor dem ThemeProvider rendert unduseTheme()dort nicht zur Verfügung steht — jetzt löstresolveInitialColors()(neu in ThemeContext.tsx) dieselbe Preference-oder-System-Vermutung auf, die der ThemeProvider selbst für seinen ersten Frame nutzt. (2) Der Splash-Screen (app.json) hatte nur eine hellebackgroundColor, keine Dark-Variante — im expo-splash-screen-Plugin per Source-Code verifiziert: ohnedark.backgroundColorbleibt der Splash in jedem System-Modus hell (kein automatisches Schwarz, aber eben auch kein Dark-Modus) — jetzt mitdark.backgroundColor: "#111111"(identisch zudarkColors.porchWhite) ergänzt, gleiches Icon (verifiziert: transparenter Alpha-Kanal, funktioniert auf beiden Hintergründen). Speculativ, da ohne Repro/Gerätedaten nicht 100% zu verifizieren — sollte den wahrscheinlichsten Kandidaten (helle Screens/Splash im dunklen Kontext) aber abdecken. Nicht live getestet (kein Emulator in dieser Session). - Tablet-Login-Screenshot: komplette App sieht "sehr großgezogen" aus.
→ Ursache (ohne den Screenshot selbst gesehen zu haben, aber strukturell bestätigt): sign-in.tsx/sign-up.tsx hatten keine Breitenbegrenzung — das äußere
Viewwarflex:1ohnemaxWidth, wodurch Inputs/Button per Default-alignItems:"stretch"auf die volle Bildschirmbreite gezogen wurden. Auf einem Phone (~350dp) unauffällig, auf einem Tablet (~800-1200dp) wirkt das wie randlos aufgeblasene Formularfelder. Fix: Inhalt in einen zentriertenform-Container mitmaxWidth: 420gepackt (beide Screens). Scope bewusst auf die gemeldeten Auth-Screens begrenzt — falls der Effekt laut nächstem Feedback app-weit auftritt, braucht es einen gemeinsamen Screen-Wrapper statt Einzelfixes. Nicht live auf einem Tablet getestet (kein Emulator/Tablet in dieser Session). - Ein User wünscht sich SSO mit Google.
→ Umgesetzt und live getestet (funktioniert).
expo-auth-session+expo-web-browserinstalliert (native Module, kein OTA-Update möglich), neuerGoogleSignInButton(eigenes SVG-„G"-Icon) auf sign-in.tsx + sign-up.tsx,useSSO()aus@clerk/expo(stable, nicht/experimental— konsistent mit dem Rest der App),WebBrowser.maybeCompleteAuthSession()im Root-Layout +useWarmUpBrowser-Hook. Zwei echte Blocker unterwegs gefunden und gelöst: (1) Google-Connection war im Clerk-Dashboard zunächst nicht aktiviert (per öffentlichem/v1/environment-Endpoint live verifiziert) — vom User nachgeholt. (2)pawfeed://sso-callbackwar nicht als erlaubte Redirect-URL in Clerk eingetragen → Clerk fiel auf einenhome_url+/sign-in-Fallback zurück, der auf dieser App nicht existiert (404, da die Web-Route/log-inheißt) — vom User im Dashboard eingetragen, jetzt behoben. Zusätzlich behandelt: Diese Clerk-Instanz verlangtlegal_consent_enabled: true, aber Clerks SSO-Transfer-Flow übergibt kein Consent-Feld — hätte sonst bei neuen Google-Konten im selbenmissing_requirements-Hänger geendet wie früher der Passwort-Flow. Fix: sign-up.tsx sperrt den Google-Button bis die bestehende Checkbox angehakt ist und ruft danachsignUp.update({ legalAccepted: true })nach; sign-in.tsx hat keine Consent-UI und zeigt bei einem noch nicht existierenden Account stattdessen eine Fehlermeldung, die auf „Registrieren" verweist, statt still ein Konto ohne Zustimmung anzulegen. Vorab noch ein reines EAS Update (Runtime 1.0.2, Branchproduction, Update-Gruppef1f3a381) mit nur den Dark-Mode-/Tablet-Fixes an die bestehenden Nutzer ausgeliefert, bevor der SSO-Code dazukam — die SSO-Verdrahtung ruftexpo-web-browserbeim App-Start auf (natives Modul, im installierten 1.0.2-Build nicht vorhanden); ein OTA-Update mit dieser Verdrahtung hätte den bestehenden Build zum Absturz gebracht. Dafür wurdeapp.json/app/_layout.tsx/sign-in.tsx/sign-up.tsx temporär auf den Stand ohne SSO zurückgesetzt, das Update veröffentlicht, danach alles 1:1 wiederhergestellt (Typecheck+Lint nach beiden Schritten sauber).
TODO Neu5 (weiteres Tester-Feedback):
- Erster Content-Load fühlt sich für Nutzer zu langsam an — Frage nach CDN-loser Beschleunigung.
→ Query-Cache (MMKV-persistiert, 24h gcTime), DB-Indizes und die Redis-gestützte Feed-Rangliste waren schon solide, das war nicht die Ursache. Eigentlicher Flaschenhals: Uploads liefen nur mit JPEG-Kompression (
quality: 0.8), aber ohne Auflösungs-Downscale — ein Kamerafoto blieb bei 3000-4000px, und jeder Feed-Betrachter lud dieses Vollbild nur um es auf Kartenbreite zu skalieren. User hat parallel geprüft: Supabase Image Transform API (serverseitiges Resize) ist nur im Pro-Plan verfügbar, den wir nicht haben — daher Fix am Schreib- statt Lesezeitpunkt. NeueresizeForUpload()-Utility (src/lib/resize-image.ts, nutztexpo-image-manipulators aktuelleImageManipulator.manipulate(uri).resize().renderAsync()-Chain-API, nicht das deprecatedmanipulateAsync) — skaliert auf max. 1600px lange Kante (nur falls nötig, kein Hochskalieren) und re-encoded immer auf JPEG @ 0.8 Kompression, unabhängig vom Ursprungsformat. In allen 4 Upload-Stellen eingebaut: AvatarStep.tsx, post-new.tsx, story-new.tsx, milestone-new.tsx.expo-image-manipulatorinstalliert (natives Modul, kein OTA-Update möglich — wird zusammen mit dem SSO-Build 1.0.3 ausgeliefert). Typecheck + Lint sauber (nur vorbestehendet-Dep-Warnungen). Nicht live getestet (kein Emulator in dieser Session) — insbesondereFile(uri).sizeist in den TS-Typdefs des installierten expo-file-system nicht direkt sichtbar, aber im nativen iOS-Quellcode (Property("size")) bestätigt. - Auf einem Android 17 - Pixel 10 Pro XL: App erneut gestartet (zweiter Tag) und dauerhafter Ladescreen. Frage nach Log-Einsicht.
→ Kein Log-Zugriff möglich: Mobile hatte bislang kein Crash-/Error-Tracking, kein Gerät/Emulator in dieser Session verfügbar. Verdacht:
app/_layout.tsxs allererster Ladescreen wartet auf ClerksisLoaded— beim Wiederöffnen nach längerer Pause ist der gespeicherte Session-Token abgelaufen, Clerk muss dann still über Netzwerk erneuern; hängt dieser Refresh (schlechte Verbindung o.ä.), bliebisLoadedfür immerfalseund der Spinner drehte endlos, ohne Fehleranzeige oder Retry-Möglichkeit. Zwei Fixes: (1) Sentry/GlitchTip für Mobile eingerichtet (@sentry/react-native, self-hosted GlitchTip-Instanz wie bei Web, eigener DSN überEXPO_PUBLIC_SENTRY_DSN).Sentry.init()nur wenn DSN gesetzt (No-op sonst),Sentry.wrap(RootLayout)als Error Boundary für sonst unbemerkte Render-Fehler. Bewusst ohne Sourcemap-Upload aus dem JS-Code heraus verdrahtet (schlägt bei dieser GlitchTip-Instanz für Web schon mit CSRF 403 fehl, siehe CLAUDE.md) — trotzdem versuchte der native Android-Build automatisch, Sourcemaps hochzuladen (Sentrys Expo-Config-Plugin hängt das standardmäßig als Gradle-Task ein), was den ersten 1.0.4-Build miterror: An organization ID or slug is required (provide with --org)hat scheitern lassen. Fix:SENTRY_DISABLE_AUTO_UPLOAD: "true"ineas.json(preview/productionenv) ergänzt — das ist die von@sentry/react-nativessentry.gradleselbst geprüfte Umgebungsvariable, um den Upload-Task zu überspringen. (2) 10-Sekunden-Timeout für die Auth-Ladephase: neueruseTimedOut()-Hook +AuthTimeoutScreen— zeigt nach 10s Wartezeit aufisLoadedstatt des endlosen Spinners einen Hinweistext + Retry-Button (Updates.reloadAsync(), nutzt das schon vorhandene EAS-Update-Runtime). Sentry-Warnmeldung wird sowohl beim Erscheinen des Timeout-Screens als auch beim Retry-Tap abgesetzt, damit ein künftiger Vorfall diesmal nachvollziehbar ist.expo-updates/expo-web-browserbereits vorhanden,@sentry/react-nativeist ein neues natives Modul (Config-Plugin automatisch in app.json ergänzt) — kein OTA-Update möglich, geht mit dem 1.0.4-Build raus. Typecheck + Lint sauber, i18n-Parität 252/252. Nicht live getestet (kein Emulator in dieser Session). - Bitte prüfen, ob das Rassen-Dropdown-Scroll-Problem bei "Tier erstellen" theoretisch erneut auftreten kann — ein Nutzer hat das bemängelt.
→ Struktur-Vergleich: onboarding/pet.tsx, edit.tsx und explore.tsx nutzen alle exakt dasselbe Muster (äußeres FlatList + OptionPickers inneres ScrollView mit
nestedScrollEnabled) — keine Inkonsistenz, kein Regressions-Bug zwischen den dreien. Das eigentliche Problem:nestedScrollEnabledist auf Android seit Jahren bekanntermaßen unzuverlässig bei verschachtelten gleichachsigen Scrollbereichen (FlatList/VirtualizedList + ScrollView) — kann je nach Android-Version/Listenlänge/Touch-Timing mal funktionieren, mal nicht (der Tester war auf Android 17, einer brandneuen Version). Strukturelle statt kosmetische Lösung:OptionPicker.tsxaufModalumgebaut — das Dropdown rendert jetzt in einer eigenen nativen Ebene komplett außerhalb der äußeren Scroll-Hierarchie, damit ist die ganze Klasse von Nested-Scroll-Bugs eliminiert statt nur umschifft. Button-Position wird permeasureInWindow()gemessen, damit das Dropdown weiterhin optisch wie ein Inline-Dropdown direkt unter dem Button erscheint (nicht als Vollbild-Sheet). Wirkt automatisch für alle 3 Verbraucher (Explore, Tier erstellen, Profil bearbeiten), keine Änderung an deren Props nötig. Aufräumen als Folge: explore.tsx'sheaderWrapper-zIndex-Hack (war nur für das alte absolut-positionierte Overlay nötig) entfernt; veraltete Kommentare in onboarding/pet.tsx + edit.tsx aktualisiert (FlatList bleibt dort bestehen, ist aber nicht mehr zwingend aus diesem Grund nötig). Kein neues natives Modul (Modal ist RN-Core) — theoretisch auch per OTA an 1.0.2-Nutzer ausliefbar, geht aber ohnehin mit dem 1.0.3-Build raus. Typecheck + Lint sauber. Nicht live getestet (kein Emulator/Gerät in dieser Session) — größtes Restrisiko: die Positions-Messung (measureInWindow) könnte auf einem echten Gerät leicht daneben liegen (z.B. bei Statusbar-Offsets), bitte beim nächsten Test gezielt prüfen.
TODO Neu6:
- Ein User hat ein Redirect-Problem beim Google-Login gemeldet, nicht reproduzierbar. Wann wurde die Redirect-Fix-Änderung gemacht?
→ Die
pawfeed://sso-callback-Whitelist wurde im Clerk-Dashboard noch vor dem 1.0.3-Build eingetragen (reine Backend-Config, kein App-Code) — wirkt serverseitig sofort für jede App-Version mit SSO-Code (1.0.3+), nicht an eine Build-Nummer gebunden. Ein Redirect-Problem danach wäre also entweder ein Tester auf einer Version vor 1.0.3 (kein SSO-Code, "Redirect-Problem" eher ein Missverständnis) oder ein bisher unbekannter Android-/Browser-Edge-Case. Echter Fund dabei:GoogleSignInButton.tsxs catch-Block meldete Fehler bisher nur lokal (Bildschirmtext), nicht an Sentry — nachgerüstet (Sentry.captureException(err)), damit ein künftiger Fall tatsächlich Logs hinterlässt. Per EAS Update (Runtime 1.0.4, Branchproduction, Update-Gruppeeea1524b) ausgeliefert — kein neuer Build nötig, reiner JS-Fix auf bereits vorhandenem@sentry/react-native. - Im Explorer gibt es beim Breed-Dropdown jetzt auch das Scroll-Problem.
→ War NICHT nur ein Altlast-Feedback von vor 1.0.4 — User hat nach dem ersten Fix-Versuch (EAS Update, s.o.) bestätigt: immer noch nicht scrollbar. Erster Fix-Versuch (Pressable→View bei der Dropdown-Karte) war unvollständig: die Karte steckte immer noch als Kind-Element im vollflächigen Backdrop-
Pressable, und einPressableIRGENDWO oberhalb einerScrollViewim Baum ist immer noch ein konkurrierender Responder-Kandidat für die Scroll-Geste. Nach erneuter Bestätigung durch den User ("neu gestartet, weiterhin defekt") das eigentliche Problem gefunden: Backdrop und Dropdown-Liste müssen Geschwister sein, nicht Eltern-Kind — jetzt so umgebaut, dass ein Tap innerhalb der Liste direkt in deren eigenen Teilbaum trifft und den Backdrop-Pressable darunter nie erreicht. Zweimal per EAS Update (Runtime 1.0.4) ausgeliefert, kein neuer Build nötig. Wichtige Erkenntnis für künftige Vorfälle: nach einem OTA-Update muss die App komplett geschlossen und neu geöffnet werden (nicht nur in den Hintergrund) —expo-updateswendet ein heruntergeladenes Update erst beim übernächsten Start an, der erste Start nach Download läuft noch mit dem alten Bundle. Typecheck + Lint sauber. Nicht live getestet (kein Emulator in dieser Session) — bitte diesmal wirklich explizit bestätigen lassen. - Kein Logout-Button in der App vorhanden — Neu-Anmeldung mit anderem Konto nicht möglich.
→ Echte Funktionslücke, nicht vorher gebaut. Neue
LogoutSectionunter „Meine Tiere" (ganz unten, nach den rechtlichen Links), mit Bestätigungsdialog (analog zum bestehenden "Tier löschen"-Muster in edit.tsx). Ruft ClerkssignOut()(useAuth()aus@clerk/expo) plusclearActivePetId()auf, damit nach einem Konto-Wechsel keine alte Pet-ID aus dem vorherigen Konto hängen bleibt — die Weiterleitung zum Login übernimmt automatischuseProtectedRoute()in app/_layout.tsx, sobaldisSignedInauffalsekippt. Kein neues natives Modul, per EAS Update (Runtime 1.0.4) ausgeliefert. Typecheck + Lint sauber, i18n-Parität 255/255. Nicht live getestet (kein Emulator in dieser Session).
Wichtiger Kontext im Nachhinein (User-Hinweis): Der 1.0.4-Build wurde zwar erstellt, aber nie in die Play Console hochgeladen — die Tester/Neuinstallationen liefen die ganze Zeit noch auf der vorherigen Version (vermutlich 1.0.2, ohne SSO-Code). Das erklärt rückwirkend, warum der Google-Redirect-Fehler und der Dropdown-Bug auch nach mehreren EAS Updates (die alle auf Runtime 1.0.4 zielten) und einer Neuinstallation weiter auftraten — die Updates konnten ein Gerät, das nie 1.0.4 installiert hatte, gar nicht erreichen. Die Analysen/Fixes selbst bleiben gültig, waren aber bis zum echten 1.0.4-Rollout nicht wirklich verifizierbar. User lädt 1.0.4 jetzt nach — sobald das live ist, sollten alle drei EAS-Update-Runden (Sentry-Fix, erster Dropdown-Versuch, finaler Sibling-Fix + Logout) automatisch beim übernächsten App-Start greifen, ohne weiteren Build.
Fortsetzung — echtes 1.0.4 live, EAS Updates kommen trotzdem nie an: Nachdem 1.0.4 wirklich in der Play Console lag, blieb der Logout-Button trotzdem unsichtbar. Diagnose-Werkzeug gebaut (UpdateDiagnosticsSection + FooterErrorBoundary in pets.tsx, temporär, per EAS Update ausgeliefert) — aber selbst DAS kam nie an, auch nach 20 Neustarts und 2 kompletten Neuinstallationen auf zwei komplett unterschiedlichen Geräten (Pixel 10 Pro XL extern, Xiaomi 13 Pro beim User selbst). Netzwerk-Check ausgeschlossen: https://u.expo.dev/<projectId> ist vom Testgerät aus erreichbar (erwartete Header-Fehlermeldung, kein Timeout/Blockade). Build-Metadaten (eas build:view) bestätigten Channel/Runtime-Version korrekt eingebettet — kein Konfigurationsfehler bei den Publishes selbst.
Ursache gefunden: app.jsons Plugin-Liste enthielt expo-dev-client — und zwar ungefiltert für alle Build-Profile inkl. production. Dieses Paket ist laut eigener Doku nur für Debug-/Development-Builds gedacht und bringt eine eigene Update-/Branch-Auswahl-Logik mit, die den normalen automatischen expo-updates-Check verdrängen kann — passt exakt zum Symptom (Updates kommen strukturell nie an, geräteunabhängig). Der lokale Dev-Client war laut früheren Sessions ohnehin schon kaputt, kein Verlust durchs Entfernen. Fix: expo-dev-client aus der gemeinsamen plugins-Liste entfernt (Paket bleibt in package.json, eas.jsons development-Profil hat sein eigenes developmentClient: true, unabhängig von dieser Liste). Braucht einen neuen nativen Build (Plugin-Änderungen sind nicht OTA-fähig) — 1.0.5/versionCode 6 angestoßen. Falls das die Ursache war, sollte ab diesem Build der normale automatische Update-Check endlich greifen.
Notiz für einen künftigen Build (nicht dringend, rein vorsorglich): Beim 1.0.5-Build meldete EAS Patch-Versions-Abweichungen bei etlichen Expo-Paketen (expo, expo-router, expo-updates, expo-image, u.v.m. — installiert liegt jeweils einen Patch hinter dem für SDK 57 aktuell erwarteten Stand). Nur Patch-Ebene, kein Build-Blocker, aber beim nächsten ohnehin anstehenden Build sollte vorher npx expo install --fix laufen, um das aufzuräumen.
Bestätigt und abgeschlossen: 1.0.5 freigegeben und getestet — Logout-Button UND das Diagnose-Tool waren sichtbar, expo-dev-client war also tatsächlich die Ursache. EAS Update funktioniert damit ab 1.0.5 wieder normal. Feedback: Logout-Button sah "wie ein Dev-Button" aus — lag am direkt danebenstehenden, absichtlich roh gehaltenen Diagnose-Block ("Update-Diagnose (temporär)" + Monospace-Dump + Debug-Button). Diagnose-Tool war ohnehin nur zur Fehlersuche gedacht und jetzt entfernt (UpdateDiagnosticsSection + zugehörige Styles raus aus pets.tsx); FooterErrorBoundary um LogoutSection bleibt als dauerhaftes, günstiges Sicherheitsnetz bestehen. Per EAS Update (Runtime 1.0.5, Gruppe 105f39e3) ausgeliefert, kein neuer Build nötig. Typecheck + Lint sauber.
Kleiner Nachklapp: Das Cleanup-Update (105f39e3) wurde von checkForUpdateAsync() als updatePreviouslyFailed gemeldet — vermutlich wurde der Download/Start bei einem der vielen Testneustarts unterbrochen, bevor die App sich als erfolgreich gestartet melden konnte; expo-updates blockiert eine einmal fehlgeschlagene Update-ID danach dauerhaft, unabhängig davon ob der Code eigentlich intakt ist (war er hier: Typecheck sauber, keine verwaisten Referenzen). Per eas update:republish mit frischer Update-ID (fdba4e10) umgangen — sollte jetzt ohne die Blockade ankommen.
Doch kein Interrupt-Artefakt — echter Absturz bestätigt: Der Republish (fdba4e10) zeigte im Expo-Dashboard ebenfalls "known launches: 1, known crashes: 1", identisch zum Original. Das widerlegt die Interrupt-Theorie (eine frische Update-ID hätte keinen alten Absturz "erben" können) — der Absturz ist real und reproduzierbar. GlitchTip zeigte dazu nichts (nur 2 alte, unabhängige Meldungen) — d.h. der Crash passiert unterhalb der JS-Ebene, bevor Sentry.wrap() überhaupt greifen kann, exakt beim Umschalten auf das heruntergeladene Bundle. Das eingebettete Bundle (im APK selbst) läuft dagegen einwandfrei — jedes bisher unter Runtime 1.0.5 versuchte OTA-Update war das allererste OTA-Update überhaupt auf diesem (Dev-Client-befreiten) nativen Build, und es scheiterte konsistent.
Verdacht: expo-updates lag laut expo install --check-Warnung beim 1.0.5-Build einen Patch hinter (57.0.21 statt erwartet ~57.0.22) — genau solche Patches beheben oft subtile Update-Apply-Bugs. Mit npx expo install --fix alle Expo-Pakete auf den erwarteten Stand gebracht (u.a. expo-updates → 57.0.22, expo → 57.0.22, expo-router → 57.0.21). Typecheck + volles Lint danach unverändert sauber (identische 39 vorbestehende Probleme wie zu Sessionbeginn, nichts Neues). Neuer nativer Build 1.0.6/versionCode 7 nötig (Dependency-Update wirkt nur bei einem frischen nativen Build) — bewusst neue Runtime-Version (nicht 1.0.5 wiederverwendet), um jede Verwechslung mit dem bekannt kaputten 1.0.5-Runtime-Zustand auszuschließen. Falls das die Ursache war, sollte OTA ab 1.0.6 tatsächlich funktionieren — sonst brauchen wir echte native Logs vom Gerät (Sentry kann diesen Absturz nicht sehen).
1.0.6 installiert, Diagnose-Text weg, Logout-Button da — aber "DEV-Optik". Nachfrage ergab: zu schlicht/unfertig (dünner Rahmen, kein Füllhintergrund), Farbe/Kontrast falsch, UND Icon/Schrift passen nicht — alle drei zugleich. Ursache: der Button war komplett handgestylt (kopiert von edit.tsx's Delete-Pet-Muster: roter Rahmen, LogOut-Icon, eigene Styles) statt die etablierte, überall sonst genutzte Button-Komponente zu verwenden. Logout ist zudem nicht destruktiv/irreversibel wie Löschen — die neutrale outline-Variante (heller Hintergrund, Ink-Text, Hairline-Rahmen) passt semantisch besser als Alarmrot. Fix: LogoutSection nutzt jetzt <Button variant="outline"> statt eigenem Pressable+Icon+Styles; LogOut-Icon-Import und radii-Import (nicht mehr gebraucht) entfernt. Per EAS Update (Runtime 1.0.6, Gruppe cb97d058) ausgeliefert.
DIESES Update hing wieder (60+ Sekunden Splash-Screen, kein ANR-Dialog) — expo-updates-Patch-Fix hat NICHT geholfen. Echte Gerätelogs geholt (adb logcat vom per USB verbundenen Xiaomi während eines Reproduktionsversuchs) und ausgewertet. Der dev.expo.updates-Log-Tag zeigte den kompletten Update-Lifecycle strukturiert als JSON — und darin die eigentliche Ursache:
ErrorRecovery: exception encountered: Error: Missing required env var EXPO_PUBLIC_API_URL — check mobile/.env
Echte Root Cause gefunden — expo-dev-client war eine Ablenkung, nicht die Ursache: eas update --environment production lädt Umgebungsvariablen aus einem serverseitigen EAS-Umgebungsspeicher (eas env:list/eas env:set), komplett getrennt von eas.jsons build.production.env-Block (der nur für eas build gilt). Dieser Server-Speicher war die ganze Session über leer ("No environment variables... found" stand in JEDEM Update-Log, wurde aber als harmlos übersehen) — jedes OTA-Bundle dieser Session lief also ohne EXPO_PUBLIC_*-Variablen, und env.tss requireEnv()-Check wirft dann sofort beim Laden (importiert von praktisch jeder Datei). Das erklärt auch rückwirkend, warum alle bisherigen "Updates kommen an"-Bestätigungen (Diagnose-Tool + Logout-Button sichtbar in 1.0.5) vermutlich nie ein echtes OTA-Update waren, sondern nur das beim eas build-Zeitpunkt eingebettete Bundle (das die Env-Vars korrekt aus eas.json bekommt) — expo-dev-client könnte für das ursprüngliche 1.0.4-Problem trotzdem ein Faktor gewesen sein, war aber nicht die vollständige Erklärung.
Fix: eas env:set production --name EXPO_PUBLIC_API_URL --value "..." --visibility plaintext (und ebenso für EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY, EXPO_PUBLIC_SUPABASE_URL, EXPO_PUBLIC_SENTRY_DSN) für die Environments production und preview gesetzt. Test-Update (Gruppe 6eb8b061) zeigte danach im Log "Environment variables... loaded from the 'production' environment on EAS: ..." statt "No environment variables... found" — Variablen kommen jetzt nachweislich mit.
✅ Am Gerät bestätigt: Logout-Button erscheint, funktioniert. Das OTA-Update kommt jetzt tatsächlich an und startet erfolgreich — die fehlenden EAS-Server-Env-Vars waren die echte, vollständige Ursache der gesamten Update-Odyssee dieser Session. expo-dev-client-Entfernung bleibt trotzdem sinnvoll (gehört nicht in Production), war aber nicht der entscheidende Fix. TODO Neu6 damit abgeschlossen.
Neu 7:
- Datums eingabe unüblich mit - getrennt statt mit . ansicht am Handy wird meist durch die tastatur überblendet. können wir für die mobile eine data wheel picker nutzen ?
→ Analyse erledigt, betrifft 4 Dateien (edit.tsx Geburtstag/Adoptionsdatum + 3 Health-Sektionen). Wheel-Picker braucht ein natives Modul (
@react-native-community/datetimepicker) → kein einzelner Build nur dafür, stattdessen aufPENDING-NATIVE-BUILD.mdverschoben und wird mit dem nächsten ohnehin anstehenden nativen Build mitgenommen. Der reine Trennzeichen-Fix ("-" → ".") ist davon unabhängig und OTA-fähig, sobald gewünscht. → Trennzeichen erledigt (04.10.), siehe iOS-Abschnitt unten (DateField, TT.MM.JJJJ). Wheel-Picker weiter offen (nativer Build). - Ein User bemängelt, das die Regisrierung gut ist, aber beim eingeben des Passworts diese hinter der "Bildschrimtastatur" verschwindet, ausserdem gibt es keine Möglichkeit für den User die korrekte eingabe nochmal zu prüfen.
→ Beides im Code bestätigt (
app/(auth)/sign-up.tsx, gleiches Muster auch insign-in.tsxgefunden und mitbehoben): (1) Der Screen nutzte nur ein einfachesViewals äußeren Container, keinScrollView/KeyboardAvoidingView— auf kleinen Screens schob sich die Tastatur einfach über die unteren Felder. Fix: äußerer Container jetztKeyboardAvoidingView(iOS:padding) +ScrollView(keyboardShouldPersistTaps="handled",contentContainerStylemitflexGrowstattflex, damit weiterhin zentriert bleibt aber scrollbar wird). (2) Neue geteiltePasswordField-Komponente (src/components/PasswordField.tsx) mit Auge/Auge-durchgestrichen-Toggle (lucideEye/EyeOff) ersetzt das nacktesecureTextEntry-TextFieldin beiden Screens. Kein natives Modul, OTA-fähig. Typecheck sauber (Mobile). - Ein anderer User, meinte wäre es nicht schöner und aufgeräumter wenn die App Settings nicht unter MyPets stehen würden sondern einen eigenen Tab erhalten.
→ Umgesetzt (Plan:
~/.claude/plans/mobile-settings-tab-extraction.md, Gitea-Issue #36, Branchfeature/settings-header-icon). Statt eines 5. Bottom-Tabs (ursprünglich vorgeschlagene Variante, siehe Mockupmobile-settings-tab-mockup.pngim Plan-Ordner) wurde ein Zahnrad-Icon im Header gewählt, neben der Mailbox — auf Wunsch des Users, da Settings realistisch nur 1–2× im Halbjahr geöffnet wird und ein permanenter 5. Tab dafür unnötig Platz kostet (Mockup:mobile-settings-header-icon-mockup.png). Neuer Screenapp/(app)/settings.tsx(Stack-Push wie "Suche", kein Modal, keine Tab-Bar sichtbar währenddessen), erreichbar überSettingsHeaderButtonin(tabs)/_layout.tsx— erscheint auf allen 4 Tabs nebenMessagesHeaderButton. Die 5 Footer-Sektionen auspets.tsx(Darstellung/Sprache/Tier-Vorschläge/Rechtliches/Logout) wurden nachsrc/components/settings/*.tsxextrahiert (DRY, je eigene Datei).pets.tsxist jetzt reine Tierliste. Nebenbei behoben:FooterErrorBoundaryschützt jetzt den gesamten Settings-Screen statt nur den Logout-Button (Lücke aus der Code-Review beim OTA-Indikator-Feature). Typecheck + Lint sauber, i18n-Parität geprüft. Gemerged nachmainin Commit30c57b6(Merge vonfeature/settings-header-icon, Issue #36 geschlossen), end-to-end auf einem Android-Emulator verifiziert (Zahnrad öffnet Einstellungen korrekt, Zurück-Navigation funktioniert, keine Tab-Bar sichtbar währenddessen, "Meine Tiere" zeigt nur noch die Tierliste) und per OTA live veröffentlicht (Update-Groupf31e3b54).- Ein user hat die meldung erhalten, "you do not have premission to access this pet" - kannst du mir erklären woher das kommen könnte ?
→ Ursache im Code gefunden (Web-seitig, nicht Mobile): Der Fehlertext kommt exakt aus
assertPetOwnership(src/lib/assert-pet-ownership.ts:19), dem gemeinsamen Ownership-Check, den praktisch jede pet-bezogene Mutation zuerst durchläuft. Web speicherte die "aktive Tier"-ID inlocalStorage["active_pet_id"](src/context/ActivePetContext.tsx) — anders als Mobile (siehe TODO Neu6:LogoutSectionruft dort bewusstclearActivePetId()auf) wurde dieser Wert auf Web nirgends geleert, auch nicht beim Sign-out über Clerks<UserButton />.ActivePetInitializersetzt nur dann einen Wert, wennactivePetIdleer ist — er prüfte nie, ob die gespeicherte ID überhaupt noch zum aktuell eingeloggten Owner gehört. Konkretes Szenario: Nutzer A meldet sich ab, Nutzer B meldet sich im selben Browser an (gemeinsamer Rechner, oder A erstellt ein zweites Konto) — B's Session lud weiterhin A's alteactive_pet_id, und jede Aktion schickte diese fremde Pet-ID ans Backend, das sie zu Recht mit genau dieser Fehlermeldung ablehnte. Gleiche Bug-Klasse wie der bereits auf Mobile behobene Logout-Fund, hier aber nie für Web nachgezogen. Fix:clearActivePetId()insrc/context/ActivePetContext.tsxergänzt (Pendant zu Mobile). DaActivePetProviderim Root-Layout außerhalb vonClerkThemeProvidersitzt (Clerk-Hooks dort nicht verfügbar — bewusste Architektur laut(app)/layout.tsx-Kommentar, um den Clerk-Bundle aus öffentlichen Routen rauszuhalten), kein direkteruseAuth()-Zugriff im Context selbst möglich. Stattdessen neueSignOutCleanup-Komponente (src/components/layout/SignOutCleanup.tsx), mounted in(app)/layout.tsxnebenActivePetInitializer— beobachtetuseAuth().isSignedInund ruftclearActivePetId()beim Wechsel vontrueauffalse, statt einen Klick-Handler an Clerks<UserButton/>zu hängen (die bietet dafür keinen sauberen Hook-Punkt). Deckt damit jeden Sign-out ab, unabhängig vom Auslöser. Typecheck + voller Testlauf (209/210, 1 skip wie zuvor) sauber, keine neuen Lint-Fehler.
- Ein user hat die meldung erhalten, "you do not have premission to access this pet" - kannst du mir erklären woher das kommen könnte ?
→ Ursache im Code gefunden (Web-seitig, nicht Mobile): Der Fehlertext kommt exakt aus
- Nutzer Feedback - DarkMode - Neuer Beitrag - Text die getippt werden sind weiß auf weißem grund.
→ Ursache gefunden:
app/(app)/post-new.tsxgehörte noch zu den nicht auf Dark Mode migrierten Screens — es importierte die statischen, Light-onlycolors/typographyaustheme/tokens.tsdirekt, statt sie peruseTheme()zu beziehen (gleiche Bug-Klasse wie die bereits behobenen Fälle aus dem Darkmode-Audit, siehe README/CLAUDE.md-Kommentar intheme/tokens.ts: "dark-mode support has to be added file-by-file"). Der Container-Hintergrund blieb dadurch immer hell (colors.porchWhite), während die geteilteTextField-Komponente korrekt theme-abhängige Textfarbe zieht (colors.ink, im Dark Mode hell) — macht bei aktivem Dark Mode aus hellem Text auf hellem Hintergrund den gemeldeten "weiß auf weiß"-Effekt in der Caption-Eingabe. Fix:post-new.tsxaufuseTheme()+makeStyles(colors)-Muster umgestellt (identisch zumilestone-new.tsx). Gleiches Muster/gleicher Fund auch instory-new.tsxentdeckt (dort ohne Texteingabe, macht sich als falscher heller Hintergrund statt unlesbarem Text bemerkbar) — gleich mitbehoben. Typecheck + Lint sauber (0 neue Warnungen, 6 vorbestehendeexhaustive-deps-Warnungen unverändert). Nachtrag:app/(app)/search.tsx(gleicher Fehler im Suchfeld) auf Nachfrage ebenfalls behoben — dort bekommen die separaten Unterkomponenten (TabButton,PetRow,Loading,EmptyState)styles/colorsjetzt als Props von der Hauptkomponente durchgereicht, statt selbst die statischen Tokens zu importieren. Typecheck + Lint sauber (1 vorbestehende, unverändertealt-text-Warnung beiexpo-image). - Google-SSO-Login ging nicht mehr, obwohl das schon mal gelöst war ("The current redirect url passed in the sign in or sign up request does not match an authorized redirect URI for this instance... pawfeed://sso-callback").
→ Kein Code-Bug —
GoogleSignInButton.tsx/useWarmUpBrowser.ts(Commit99575dd) waren unverändert korrekt. Ursache lag außerhalb des Repos: Clerk führt pro Instanz eine eigene, serverseitige Allowlist autorisierter Redirect-URLs (GET/POST https://api.clerk.com/v1/redirect_urls, Auth viaCLERK_SECRET_KEY) — komplett getrennt vom App-Code, kann also unabhängig vom letzten "war doch schon gelöst"-Stand geändert/geleert worden sein. Registriert war nur ein falscher/veralteter Eintragclerk://org.pawfeed.app2.callback(vermutlich Rest einer früheren Bundle-ID-Iteration mit einer "2" drin) —pawfeed://sso-callback(ausapp.jsons"scheme": "pawfeed") fehlte komplett. Fix: fehlenden Eintrag per Clerk Backend API ergänzt (POST /v1/redirect_urls,{"url":"pawfeed://sso-callback"}) — live sofort wirksam, kein App-Deploy/Rebuild nötig. Am Emulator bis zum Google-Consent-Screen verifiziert (öffnet korrekt, leitet zu pawfeed.org weiter), kompletten Rücksprung dann vom User auf echtem Gerät bestätigt. Merke für künftige Sessions: wenn SSO trotz unverändertem Code plötzlich bricht, zuerst die Clerk-Redirect-URL-Allowlist prüfen, bevor im App-Code gesucht wird — die liegt nicht in git und kann von außerhalb dieser Session geändert worden sein. - Story Ring - ist abgeschnitten in der Mobil-App.
→ Ursache: Die zwei mittleren "Zehen" der Pfote (
cy: 1, r: 10) ragen in der 0–100-viewBox bis y = -9. Web zeichnet das SVG mitoverflow: visible,react-native-svgschneidet dagegen an der viewBox ab. Fix insrc/components/PawRing.tsx: viewBox nach oben erweitert (0 -10 100 110), Box entsprechend höher (getPawRingBox()); der "Story hinzufügen"-Knopf inStoryTray.tsxnutzt dieselbe Box und sitzt jetzt auf gleicher Höhe. Commit2ef439c, per OTA für Android veröffentlicht (Update-Group4dc6f797), noch nicht am Gerät bestätigt. - Mehrere Nutzer melden nach Google-Login die Meldung "Unmatched Route pawfeed://sso-callback".
→ Anderer Bug als der frühere Clerk-Redirect-URL-Allowlist-Fund oben (der Eintrag ist weiterhin korrekt registriert) — diesmal ein echter Code-Bug, spezifisch Android.
useSSO()(@clerk/expo) baut die Redirect-URI selbst viaAuthSession.makeRedirectUri({ path: "sso-callback" })→pawfeed://sso-callback, undWebBrowser.openAuthSessionAsync()fängt die Rückleitung normalerweise über eine eigene Custom-Tab-Session ab (das ist der Zweck vonWebBrowser.maybeCompleteAuthSession()inapp/_layout.tsx). Auf Android liefert das OS den Redirect-Intent aber zusätzlich als normalen Deep-Link an die App — den sieht auch Expo Routers eigener Linking-Listener, und weil es dafür keine passende Route gab, zeigte Expo Router kurz seinen eingebauten "Unmatched Route"-Fehlerschirm, bevorGoogleSignInButtonsrouter.replace("/(app)")(nach erfolgreichemsetActive()) übernahm — bei langsameren Geräten/Netzwerken blieb der Fehlerschirm sichtbar hängen statt wegzuflippen. Bekanntes Muster bei Clerk+Expo-Router (u. a. expo/expo#22662, mehrere Community-Fixes mit identischer Lösung). Fix: neue Dateiapp/sso-callback.tsx— reiner Lade-Spinner (kein eigenes Redirect/Auth-Logic), gibt Expo Router für dieses kurze Zeitfenster ein gültiges Ziel. Die bestehendeuseProtectedRoute()-Umleitung inapp/_layout.tsxübernimmt danach wie gewohnt (leitet nicht-eingeloggte Nutzer automatisch weiter, sobald sie außerhalb der(auth)-Gruppe landen),GoogleSignInButtonnavigiert bei Erfolg wie bisher aktiv weiter. Reine JS/TSX-Änderung, kein natives Modul betroffen → OTA-fähig, kein neuer Store-Build nötig. Typecheck + Lint sauber (kein Live-Test auf Emulator/Gerät möglich in dieser Session). Gemerged nachmain(Fast-Forward vonfix/sso-callback-unmatched-route, Commit17a17bd, unabhängig von der noch offenenfeature/mobile-video-stories-Merge-Entscheidung) und per OTA live veröffentlicht (npx eas-cli update --branch production --environment production --platform android, Update-Groupdf2a3ce9-7eba-4cb8-bf10-7d478a4a8a60, Runtime-Version1.0.6). Installierte Apps ziehen das automatisch beim nächsten Start. Stolperstein beim Publish: Das lokale (gitignorete)mobile/android/-Verzeichnis vom Device-Test der letzten Session ließeas updatedas Projekt fälschlich als "Bare Workflow" erkennen (CommandError: runtime version policies are not supportedstatt der konfigurierten"policy": "appVersion") — Fix war,android/kurz umzubenennen/wegzuschieben, Update zu publishen, danach zurückzubenennen. Für künftige OTA-Publishes nach einem lokalenexpo run:android-Test: dasselbe Problem erwarten. - Im Pet-Profil ist der Erste Post nicht Klickbar da er in die Gesten-Steuerung rein ragt.
→ Ursache: Android läuft edge-to-edge, und die Stack-Screens (ohne Tab-Leiste darunter) hatten unten keinen Safe-Area-Abstand — der letzte Inhalt lag unter der Gesten-Leiste. Fix: neuer Hook
src/hooks/useBottomSafePadding.ts(paddingBottom = 16 + insets.bottom), eingebaut in Tierprofil, Follower, Folgt, Gesundheit, Meilensteine, Profil bearbeiten, Einstellungen, Suche, Nachrichten-Liste und Konto löschen. Commitde237f1, per OTA für Android veröffentlicht (Update-Group4dc6f797), noch nicht am Gerät bestätigt. Gilt automatisch auch für iOS (Home-Indicator). - Nutzer-Feedback: Nach dem Posten einer Story erscheint man selbst nicht als Ring — man kann die eigene Story nicht ansehen.
→ Ursache (Web und App gleich): Die Story-Leiste zeigt nur die „+“-Kachel und Storys gefolgter Tiere (
follows.getPetsWithActiveStories); das eigene aktive Tier ist darin nie enthalten. Fix: zusätzlicher Ring „Deine Story“ direkt nach der „+“-Kachel, solange das aktive Tier eine aktive Story hat (stories.hasActiveStory, wird nach dem Posten schon invalidiert). Web:src/components/stories/StoryTray.tsx(öffnet den StoryViewer — dort sieht der Owner auch die Zuschauerliste); App:src/components/StoryTray.tsx. Commit204d5f6, live (Web + OTA Android58e99a29, iOS2aaa3975). Typecheck/Tests/Build grün; die 2 Lint-Fehler „Cannot access refs during render“ in der Web-StoryTray bestanden schon vorher (horizontales Scrollen). Story-Kommentare: Backend (stories.addComment/listComments/deleteComment,toggleReaction,getViewers) und Web-UI (StoryCommentsOverlay) existieren bereits — nur der App-Viewer (app/(app)/story-viewer.tsx) hat Kommentare, Reaktionen und Zuschauerliste beim Portieren bewusst ausgelassen. Offen als eigener Punkt. - Story-Kommentare, Pfoten-Reaktionen und Zuschauerliste in der App (Folge-Punkt zum Story-Feedback).
→ Neuer App-Viewer (
app/(app)/story-viewer.tsx) mit Pfote (src/components/stories/StoryPawButton.tsx), Kommentar-Bottom-Sheet (StoryCommentsSheet.tsx, Schreiben + eigene löschen) und — nur bei der eigenen Story — Zuschauerliste (StoryViewersSheet.tsx, Augen-Symbol oben links). Solange ein Sheet offen ist, pausiert der Story-Timer (anders als im Web, damit die Story beim Tippen nicht weiterspringt). Nutzt die vorhandenen Server-Prozeduren; einzige Server-Änderung:stories.listActivenimmt optionalviewerPetIdund liefertreactedByViewer, damit die Pfote gefüllt startet, wenn man schon reagiert hat — abwärtskompatibel, und der Web-Viewer nutzt es jetzt auch (bekannte Einschränkung "Pfote startet immer leer" behoben). Tests insrc/__tests__/stories.test.ts, alle 268 Tests + Build + App-Typecheck grün. Nicht auf einem Gerät getestet; Tastaturverhalten im Kommentar-Sheet (AndroidKeyboardAvoidingViewbehavior "height" im Modal) bitte bei Testern beobachten. Weiterhin offen: keine Benachrichtigung bei Story-Kommentaren/-Pfoten (Notification hat keinestoryId, bräuchte Schemaänderung); Video-Storys spielt der App-Viewer weiterhin nicht ab. Commitccebfa4, live (Web + OTA Runtime 1.0.6: Androida3941052-a3ec-4c3c-a875-24ad3dcd1c98, iOS5e855c5b-f6db-44d0-8350-6b0b91308804).
!!! iOS - Founds beginnen hier - nicht mit Android vertauschen !!!
-
Nutzer-Feedback: Storys und Beiträge mit Bildern im HEIF/HEIC-Format (Apple) lassen sich nicht erstellen. → Kein reines Serverproblem. Der Server nimmt bewusst nur JPEG/PNG/WebP an (
ALLOWED_CONTENT_TYPESinsrc/lib/supabase-storage.ts), und die Bytes gehen direkt vom Client zu Supabase — umgewandelt wurde HEIC nirgends. Zwei Fundstellen: 1. App, Beiträge:app/(app)/post-new.tsxfilterte gewählte Fotos nach ihrem Original-MIME-Typ (image/jpeg|png|webp) und warfimage/heic/image/heifstill raus — obwohlresizeForUpload()danach sowieso jedes Bild in JPEG umwandelt. Storys/Meilensteine/Avatar in der App filtern nicht und waren nicht betroffen. 2. Web, alle Bild-Uploads (Beiträge, Storys, Meilensteine, Tierbild): nur JPEG/PNG/WebP erlaubt; ein.heicvom Mac oder eine rohe HEIC-Datei aus iOS-Safari (Storys nutzenaccept="image/*,video/*", das Safaris automatische HEIC→JPEG-Umwandlung aushebelt) wurde abgelehnt. Fix: App — HEIC/HEIF inpost-new.tsxzugelassen, plus Hinweis-Alert, falls doch einmal Bilder übersprungen werden (post.unsupportedFormat). Web — neuessrc/lib/heic-to-jpeg.tswandelt HEIC vor dem Upload per Browser-Dekodierung (Canvas → JPEG 0,9) um, eingebaut inMultiImageUpload,StoryForm,MilestoneForm,AvatarUpload;acceptum HEIC ergänzt, damit der Mac-Dateidialog sie anbietet. Bewusst ohne Zusatzbibliothek (heic-to: LGPL-3.0, ~26 MB; heic2any: seit 2023 ungepflegt): Safari (iOS 17+/macOS 14+) dekodiert HEIC selbst; Browser ohne HEIC-Support (z. B. Chrome/Windows) bekommen eine klare Meldung „Öffne PawFeed in Safari oder speichere das Foto als JPG“ (heicUnsupported). Tests insrc/__tests__/heic-to-jpeg.test.ts, alle 266 Tests + Build grün. Nicht auf einem echten iPhone getestet. Commit1bf0f92, Web per Rolling-Deploy live, OTA Runtime 1.0.6: Android1b4baa80-a35a-49b7-ac6e-f44ebe93b4db, iOSc31382ee-83b7-4a81-a06d-1a2e53180d7d. Vom Nutzer bestätigt (02.10.2026): funktioniert. -
Nutzerfeedback - Story löschbar ? wie kann man die story löschen, falls man mal was falsches in die story geladen hat ? → Gab es bisher nirgends. Neu: Server
stories.delete(nur Owner; löscht Aufrufe —StoryViewhat bewusst kein Cascade —, dann die Story, Pfoten/Kommentare per Cascade; danach Bild in Supabase Storage bzw. Mux-Asset best-effort). Web: Papierkorb neben der Zuschauerzahl in der eigenen Story + Rückfrage (AlertDialog), Bild-Timer pausiert während der Rückfrage, gelöscht wird die beim Antippen gemerkte Story-ID. App: gleicher Papierkorb + native Rückfrage, Timer pausiert. Nach dem Löschen springt der Viewer zur nächsten Story bzw. schließt, wenn keine mehr da ist. 5 neue Tests insrc/__tests__/stories.test.ts. Nicht auf einem Gerät getestet. Commit81d9c6d, live (Web + OTA Runtime 1.0.6: Android49757586-c443-4952-a679-c66a4225ef82, iOS48d22b11-abc9-4c75-be52-a122b0130c5e). -
Storys nur für Ersteller länger einsehbar wegen den Kommentaren (7Tage) → Umgesetzt (02.10.): Der Ersteller sieht seine Storys 7 Tage lang (danach löscht der Aufräum-Job sie), alle anderen weiterhin nur 24 Stunden. Server:
stories.listActiveliefert dem Owner die Storys der letzten 7 Tage mitisExpired;stories.hasActiveStorymeldet mitincludeOwnRecent(nur die Story-Leiste setzt das) einen grauen RingexpiredOnly, damit Profilbilder im Feed nicht ebenfalls grau umrandet werden. Web + App: grauer Ring „Deine Story“, Hinweis „Abgelaufen – nur für dich sichtbar“ im Viewer, Kommentare bei abgelaufenen Storys nur lesbar, Pfote nur als Zähler; Zuschauerliste und Löschen bleiben. Keine Schemaänderung. 4 neue Tests. Nicht auf einem Gerät getestet. Commit2c0680c, live (Web + OTA Runtime 1.0.6: Android5b324ee8-4821-4ca5-b6e7-6a02635a41f7, iOSa430ccd0-f2bb-452f-b3cd-45e94910901b). → Noch offen. Befund: abgelaufene Storys werden nie gelöscht (Einträge, Bilder, Mux-Videos bleiben liegen) — Vorschlag: grauer Ring "Deine Story" 7 Tage für den Ersteller, danach Aufräum-Cron (braucht einen Auslöser auf dem NAS, die bestehenden Cron-Routen haben keinen) + Satz unter "Speicherdauer" in der Datenschutzerklärung. Teil erledigt (02.10.): Aufräum-Job gebaut —/api/cron/cleanup-storieslöscht Storys älter als 7 Tage komplett (Aufrufe, Pfoten, Kommentare, Bild, Mux-Video; gemeinsame Funktionsrc/lib/story-cleanup.ts, auch von „Story löschen“ genutzt), täglich 04:30 über die bestehende NAS-Crontab (docker/run-cron.sh, Log indocker/cron.log); Datenschutzerklärung Abschnitt 6 ergänzt. Offen bleibt nur die 7-Tage-Ansicht für den Ersteller. -
Video-Storys in der App (Upload + Wiedergabe) → Umgesetzt (03.10.): Branch
feature/mobile-video-stories(Gitea #37, 20.09. auf Emulator + Gerät getestet) auf den seit 02.10. umgebauten Story-Viewer portiert. Galerie-Picker nimmt Fotos und Videos (max. 30 s, Prüfung vor dem Upload), Upload direkt zu Mux überstories.createVideoUpload; Viewer spielt READY-Videos überexpo-videoab (Fortschritt austimeUpdate, weiter beiplayToEnd,play()erst beireadyToPlay), zeigt „wird verarbeitet“/Fehler und pausiert das Video, solange Kommentare/Zuschauer/Löschen offen sind. Nur JS (expo-videoist seit dem 1.0.6-Build nativ drin). App-Typecheck grün; der Port selbst (Pause bei offenem Sheet) nicht auf einem Gerät getestet. Kamera nimmt weiterhin nur Fotos auf (Video-Aufnahme bräuchte Mikrofon-Berechtigung = neuer Build). Commit69e2c13, OTA Runtime 1.0.6: Android665f2bf0-7e19-4b38-a07f-5da03459a55c, iOS963e721c-3c7c-4d45-b08a-b3c49969e5a2. -
Nutzer-Feedback: Beim Video-Story-Upload sieht man nur einen Spinner — Fortschritt nicht erkennbar. → Umgesetzt (03.10.): Beim Video zuerst „Upload wird vorbereitet …“, dann Fortschrittsbalken mit Prozent („Video wird hochgeladen … 45 %“) aus
File.uploadonProgress(expo-file-system 57.0.7, nativ im 1.0.6-Build — Android meldet alle 100 ms). Vorschau während des Uploads gesperrt. Fotos behalten den Spinner (Upload dauert dort nur Sekundenbruchteile). App-Typecheck grün, nicht auf einem Gerät getestet. Commit5606a81, OTA Runtime 1.0.6: Android000908ec-4aac-4bc3-80c7-a86ea438d1c2, iOScd0481b9-84d3-4734-987b-c1b418d51c61. -
Feedback kam über iOS, betrifft aber das System, bei Impfungen die man anlegt, sollte ein Wiederholungstermin nach dem Abklingen der Impfung eingebunden werden, mit einem Reminder -1Monat vor ablauf damit man einen neuen Termin vereinbaren kann zum Impfen. → Umgesetzt und live (04.10.). Den Folgetermin gab es schon (
Vaccine.nextDueDate, Web + App), es fehlte nur die Erinnerung. Neu: täglicher Cron/api/cron/vaccine-reminders(src/lib/vaccine-reminders.ts) erinnert einmalig 30 Tage vor dem Folgetermin per MitteilungVACCINE_DUE+ Push („Die Impfung „Tollwut“ für Bubi ist am 01.11.2026 fällig …“). Bereits überfällige Termine werden nicht nachträglich erinnert (die zeigt die Gesundheitsseite als „überfällig“). Schema:NotificationType.VACCINE_DUE,Notification.vaccineId(Cascade),Vaccine.reminderSentAt(Schutz gegen doppelten Versand, wird bei Fehler wieder freigegeben). Web + App zeigen die Mitteilung mit 💉, Tippen öffnet die Gesundheitsseite. App: Schnellauswahl „+1 Jahr / +3 Jahre“ für den Folgetermin plus Hinweis „Mit Folgetermin erinnern wir dich 30 Tage vorher“. 8 neue Tests, Typecheck Web + App grün. Commitc74bbff, App-Teil per OTA Runtime 1.0.6: Android64144379-e335-45ca-bb05-bc12155da54c, iOSb8f31fed-aa02-41a2-97c3-3707d02857ce. Schema perdb pushauf dem NAS (rein additiv), Rolling-Deploy (7ab74f8; der erste Versuch brach ab, weil ein Test aussrc/__tests__nachmobile/importierte, das im Docker-Build fehlt — Test liegt jetzt inmobile/src/lib/date-format.test.ts), Crontab täglich 08:15. Testaufruf: HTTP 200,sent: 0(derzeit nichts fällig). Der echte Versand inkl. Push ist noch nicht mit einer fälligen Impfung beobachtet, die App nicht auf einem Gerät getestet. -
Feedback iOS Datums eingabe läuft noch mittels - Trennung statt . ( option für iOS - Data Wheel Picker) → Trennzeichen umgesetzt (04.10.): Neue
DateField-Komponente (src/components/DateField.tsx) für alle Datumsfelder (Geburtstag, Adoptionstag, Gewicht, Tierarzt, Impfungen): Zifferntastatur, die Punkte setzt die App beim Tippen selbst (TT.MM.JJJJ; die iOS-Zifferntastatur hat keinen Punkt). Ältere Eingaben mit „-“ oder „/“ und einstellige Tage/Monate werden weiter akzeptiert. Tests insrc/__tests__/mobile-date-format.test.ts. Commitc74bbff, OTA wie oben. Nicht auf einem Gerät getestet. Wheel-Picker weiterhin offen — braucht ein natives Modul, steht inPENDING-NATIVE-BUILD.mdfür den nächsten Build. -
Nutzer-Feedback iOS (Screenshot
feedback-ios/WhatsApp Image 2026-10-04 at 12.50.58.jpeg): Beim Antippen eines Datumsfelds in „Profil bearbeiten“ verdeckt die Tastatur das Feld, die Eingabe ist nicht zu sehen. → Behoben (04.10.): Der Screen hatte keinen Tastatur-Ausgleich (nurFlatList, keinKeyboardAvoidingView). Neu:automaticallyAdjustKeyboardInsets(iOS: unterer Inset in Tastaturhöhe und automatisches Scrollen zum aktiven Feld, im RN-QuellcodeRCTScrollViewComponentView.mmgeprüft) pluskeyboardShouldPersistTaps="handled". Gleiche Lücke auch in Gesundheit (Gewicht/Impfung/Tierarzt), Neuer Beitrag, Neuer Meilenstein, Tier anlegen/Onboarding und Einladen gefunden und mitbehoben. Android unverändert (Prop gilt nur für iOS, dort nicht gemeldet). Typecheck sauber. Commit333ba16, OTA nur iOS Runtime 1.0.6718ede5a-91c4-4e4e-b444-174ab3af66a2. Nicht auf einem Gerät getestet. -
Feedback iOS - Rassen suche ist als Dropdown, ohne Suchfunktion. Bei Hunden und Katzen ist die Liste lang, die Suche würde verkürzt werden, wenn man eintippen könnte um das Dropdown zu kürzen. → Umgesetzt (04.10.):
OptionPickerzeigt ab 10 Einträgen oben ein Suchfeld („Suchen …“), das beim Tippen filtert — ohne Groß-/Kleinschreibung und Akzente („frise“ findet „Bichon Frisé“,src/lib/filter-options.ts+ Tests). Öffnet sich die Tastatur, rückt die Liste nach oben, damit sie nicht verdeckt wird. Wirkt in Tier anlegen, Profil bearbeiten und Explore-Filter; die kurze Tierarten-Liste bleibt ohne Suchfeld. Typecheck sauber. Commit01459c7, OTA Runtime 1.0.6: Android02f677cc-406b-4475-9601-e61b8a4b963a, iOS708be8d6-9786-44ad-a3c9-c305a3f93dd2. Nicht auf einem Gerät getestet — bitte besonders das Hochrücken über der Tastatur prüfen. -
Feature: Storie-Edit Modus, mittels Overlays eigene Storys hübsch machen, durch Texteingaben in das Bild oder Effekte oder Gifs. (Analog zu Instagram) ->Branch → Umgesetzt und live (04.10.) als Story-Editor (Branch
feature/story-editor, nachmaingemergt): In der App nach Foto/Video oder als Text-Story auf Farbverlauf: Text (3 Stile, 8 Farben, 2 Schriften), @-Markierungen anderer Tiere, GIFs (GIPHY, nur jugendfrei), 8 Sticker — verschieben, mit zwei Fingern zoomen/drehen, zum Löschen auf den Papierkorb ziehen. Markieren richtet sich nach „Wer darf die Follower sehen?“ (Alle / nur Follower / niemand), markierte Tiere und Story-Besitzer bekommen Mitteilungen (Markierung, Kommentar, Pfote). Web zeigt alles an, erstellt aber nicht. Overlays sind Daten über dem Bild (nicht eingerechnet), daher alles per OTA, kein Store-Build. Notschalter im Admin-Dashboard („Story-Editor“), blendet Editor und Overlays ohne Update aus. 20 neue Tests, alle 376 grün, Produktions-Build ok, gerenderte Vorschau geprüft. db push + RLS, Rolling-Deploy, OTA Runtime 1.0.6: Android8a1a12cb-d61a-4d14-91ab-391396781d87, iOSfe114163-abea-4ccc-ad19-cd1f8ccc7532. Nicht am Gerät getestet — besonders Zwei-Finger-Gesten und Tastatur im Texteditor prüfen. -
Admin-Dashboard -> Zurückgewiesene Reports, als Meldung an den Melder mit einer Begründung warum abgewiesen wurde. Sowie Meldung bei bestätigter Report löschung, z.b mit Danksagung für die Meldung. → Umgesetzt und live (04.10.), als Team-Nachricht. Admin → Reports: „Report ignorieren“ hat jetzt ein Feld „Begründung für den Melder“; der Melder bekommt vom PawFeed-Team „Danke für deine Meldung zum Beitrag/Profil von X … kein Verstoß … Begründung: …“ (Begründung steht zusätzlich im Moderations-Log). „Post löschen“ dankt jedem Melder des Beitrags einmal („… Inhalt entfernt. Danke, dass du hilfst …“); die interne Lösch-Begründung geht bewusst nicht an den Melder. Beides per Schalter im Dialog abschaltbar, Versand erst nach erfolgreicher Moderation und ohne sie bei einem Fehler zu kippen. Nebenbei behoben: Beim Löschen eines gemeldeten Beitrags blieben dessen Reports verwaist in der Liste (
targetPostIdist keine Relation) — werden jetzt mitgelöscht. 7 neue Tests (admin-report-feedback.test.ts), alle 336 Tests grün. Commitf51b158, Rolling-Deploy auf dem NAS. Kein App-Update nötig. Im Live-Admin noch nicht mit einem echten Report ausprobiert. -
Feedback - iOS & Andriod, Story-Bilder und Videos mit Overlays bearbeiten direkt in der App. Text hinzufügen, Gifs einbinden, Markierungen auf andere Pets setzten (Analog zu Instagram) bitte als neues Branch anlegen. → Umgesetzt und live (04.10.) als Story-Editor (Branch
feature/story-editor, nachmaingemergt): In der App nach Foto/Video oder als Text-Story auf Farbverlauf: Text (3 Stile, 8 Farben, 2 Schriften), @-Markierungen anderer Tiere, GIFs (GIPHY, nur jugendfrei), 8 Sticker — verschieben, mit zwei Fingern zoomen/drehen, zum Löschen auf den Papierkorb ziehen. Markieren richtet sich nach „Wer darf die Follower sehen?“ (Alle / nur Follower / niemand), markierte Tiere und Story-Besitzer bekommen Mitteilungen (Markierung, Kommentar, Pfote). Web zeigt alles an, erstellt aber nicht. Overlays sind Daten über dem Bild (nicht eingerechnet), daher alles per OTA, kein Store-Build. Notschalter im Admin-Dashboard („Story-Editor“), blendet Editor und Overlays ohne Update aus. 20 neue Tests, alle 376 grün, Produktions-Build ok, gerenderte Vorschau geprüft. db push + RLS, Rolling-Deploy, OTA Runtime 1.0.6: Android8a1a12cb-d61a-4d14-91ab-391396781d87, iOSfe114163-abea-4ccc-ad19-cd1f8ccc7532. Nicht am Gerät getestet — besonders Zwei-Finger-Gesten und Tastatur im Texteditor prüfen. -
Admin-Dashboard - Tiere zeigt aktuell neben dem Namen nur einen Rang an, zur besseren übersicht sollten alle erlangten Ränge angezeigt werden in der Liste. → Umgesetzt und live (04.10.): Die Liste zeigte nur den höchsten Rang (Cache
referralRankId) und nur mit Vorteil NAME_BADGE. Jetzt lädtpetAdmin.listalle Rang-Einträge des Besitzers (nach Schwelle sortiert) und zeigt jedes Rangsymbol (AchievedRankBadges), unabhängig von NAME_BADGE. Entzogene Ränge erscheinen ausgegraut, Tooltip mit „manuell vergeben“ / „entzogen“. Commitdbc416c, Rolling-Deploy. -
Feedback - iOS, wenn man Nachrichten erhält bekommt man zwar eine Benachrichtung aber in der App wird bei der Sprechblase kein Indicator angezeigt z.b. ein Orangener Punkt der auf eine ungelesene nachricht hindeutet. → Umgesetzt (04.10.): Die Sprechblase oben zeigt jetzt wie die Glocke einen orangen Zähler mit der Zahl ungelesener Nachrichten (
conversations.unreadCount, gab es serverseitig schon). Aktualisiert sich alle 30 s, solange die App offen ist, und verschwindet nach dem Lesen des Chats. Commit2bd4b2d, OTA Runtime 1.0.6: Android70b064d1-3424-44af-b834-7e77a60475e6, iOSe0993ecc-0961-4270-8876-a999e8339ba3. Nicht auf einem Gerät getestet. -
Testuser hat Goldene Pfote als Rang erhalten, im Rang habe ich Profil_RING mit eingesetzt damit sich der Profil-Ring mit färbt. aber das passiert nicht. → Ursache: Kein Datenfehler — der Testnutzer („Krypton“) hatte PROFILE_RING korrekt im Cache. Der Ring war bewusst nur im Tierprofil oben zu sehen, nicht im Feed oder an Storys. Auf Wunsch erweitert und live (04.10.): (1) Ring in Rangfarbe jetzt überall am Tierbild — Feed, Kommentare, Suche, Explore, Nachrichten, Mitteilungen, Follower-Listen, Meilenstein-/Repost-Karten, Story-Kommentare/-Zuschauer (Web + App). Dafür liefert die gemeinsame Tier-Abfrage (
petIdentitySelect) die Rangdaten jetzt mit. Der Ring liegt außen um das Bild, Listen verrutschen nicht. (2) Story-Ring: Bei ungesehener Story leuchtet die Pfote in der Rangfarbe statt Orange; ohne Story gibt es einen schlichten Ring in Rangfarbe; gesehene Storys bleiben grau. 6 neue Tests, alle 353 Tests grün. Commitc7c1473, Rolling-Deploy + OTA (wie oben). Nicht auf einem Gerät getestet. -
Prüfung ob es möglich wäre, wenn ein Haushalt mit 2 Accounts, aber dem gleichen Tier. sich beide um das gleich tier kümmern können??? reiner research auf machbarkeit. pro / kontra liste erstellen → Research erledigt (04.10.) — ausführlich in Obsidian:
PawFeed/Punkte/Gemeinsame Tierhalter – Machbarkeit. Kurz: Heute hat ein Tier genau einen Account (Pet.ownerId). Möglich wären (A) gemeinsamer Login — geht schon, aber Push nur aufs zuletzt angemeldete Handy; (B) echte Mitbetreuer mit eigenen Accounts — passt gut zum tierzentrierten Konzept, ist aber ein großer Umbau (zentrale Rechteprüfung + ~22 Dateien, Einladungsablauf, Regeln für Empfehlungsrang, Gesundheitsdaten/DSGVO, Konto-Löschung), grob 4–6 Tage, ohne Store-Build; (C) Tier übertragen — klein, löst die Frage aber nicht. Empfehlung: erst „Push an mehrere Geräte“ bauen (½–1 Tag, hilft sofort), B nur bei häufigerem Wunsch und nach Klärung der offenen Regeln. -
Tester-Feedback 04.10. zum Story-Editor: Android — Farbwahl im Texteditor liegt im Gesten-/Schutzbereich. iOS — „Text-Story“ lässt sich nicht öffnen (stattdessen „klickt es auf das X“), Foto aus der Galerie: alles verschwindet, das X leuchtet kurz auf. → Behoben (04.10.): Ursache iOS: Der Editor lief im Auswahl-Screen „Neue Story“, der auf iOS ein Sheet ist — beim Öffnen wurde dessen Kopfzeile ausgeblendet (das aufleuchtende X) und zusätzlich ein natives Fenster (Texteditor) eingeblendet, was iOS während einer laufenden Präsentation verweigert. Jetzt eigener Vollbild-Screen
story-editor(ohne Kopfzeile, ohne Wisch-zum-Schließen), Texteditor und Auswahlfenster sind Ebenen statt nativer Fenster (EditorLayer, Android-Zurück schließt sie). Android: echte Safe-Area-Abstände oben/unten. Neu: Tippen auf eine freie Stelle öffnet den Texteditor. Am Android-Emulator durchgeklickt (Text-Story, Texteditor, Verschieben, GIF-Suche live, Sticker, X zurück) — iOS hier nicht testbar, bitte am iPhone prüfen. Commit6d31367, OTA Runtime 1.0.6: Androidda1a187e-5032-4e4e-8401-43ba167e9fd5, iOSc90c270f-8c89-42fa-ae11-5202163f3f80. -
Tester-Feedback 04.10.: Mitteilung „STORY_MENTION“ — anklickbar, aber man landet auf dem Profil statt auf der Story; der Text ist nicht korrekt. → Behoben (04.10.): Web öffnet die Story jetzt direkt als Overlay an der markierten Story (vorher bewusst Profil — unnötiger Umweg), die App öffnet sie über den ganzen Eintrag inkl. Namen und springt im Viewer direkt zur richtigen Story. Der rohe Text „STORY_MENTION“ kam von einem Gerät mit älterem App-Stand, der den neuen Typ noch nicht kannte — künftig zeigen App und Web für unbekannte Typen einen neutralen Text statt des Code-Namens. Zusätzlich: keine Markier-Mitteilung mehr an eigene Tiere. Commit
8aca1bc, Rolling-Deploy, OTA Runtime 1.0.6: Androidda0b5a30-6a00-47f7-8c2f-91274f2629ec, iOS18681e15-dadf-46f4-b3cf-b44aab78fe42. Bitte die App zweimal komplett neu starten. -
Wunsch 04.10.: Eine Nachrichten-Mitteilung soll beim Antippen direkt zur Nachricht führen (wie bei Kommentaren) — für alle Funktionen: „Benachrichtigung bringt dich auf kürzestem Weg dorthin, wo es wichtig ist.“ → Umgesetzt (04.10.): Gemeinsame Zielregel für Mitteilungsliste und Push (
mobile/src/lib/notification-route.ts, mit Tests): Nachricht → Gespräch, Kommentar/Pfote/Erwähnung/Paw-Back → Beitrag, Story-Mitteilungen → die Story, Follow/Vorschlag/Einladung → Profil, Rang → Einladen, Geburtstag/Adoptionstag/Impfung → Gesundheit. Neu: Antippen einer Push-Mitteilung führt direkt dorthin (vorher öffnete sich nur die App), auch beim Kaltstart; gilt sie für ein anderes eigenes Tier, wird vorher umgeschaltet. Bei Nachrichten und Storys führt auch der Name zum Ziel. Web: Nachrichten öffnen das Gespräch. Server liefert dafür das Gespräch zur Mitteilung und erweiterte Push-Daten. 386 Tests grün. Commit4cf2821, Rolling-Deploy, OTA Runtime 1.0.6: Android7ea956bf-b519-4a57-a9f0-4008aa212899, iOSb8f7c983-fc18-43d7-aea3-10fa4315d4c6. Nicht am Gerät getestet; Push-Ziele greifen für Mitteilungen ab jetzt (ältere Pushes haben die neuen Daten noch nicht). -
Gefunden 04.10. (Marketing-Aufnahmen): Nach „Vermisst-Meldung starten“ war die Bestätigung auf Android abgeschnitten („… dass Berli schnell nac…“). → Behoben (04.10.): Android kürzt Dialog-Titel auf zwei Zeilen, und der ganze Text stand als Titel im Dialog. Jetzt kurzer Titel + vollständige Nachricht: „Die Meldung ist raus“ / „Wir drücken die Daumen, dass {Name} schnell nach Hause findet.“, Entwarnung „Wie schön! 🎉“ / „Willkommen zurück, {Name}!“, Fehler „Hoppla“ + Meldung des Servers. Am Android-Emulator geprüft (Fehlerdialog bei der 24-h-Sperre vollständig lesbar). Typecheck, Lint und 406 Tests grün. Commit
b1d3b61, OTA Runtime 1.0.6: Androidab6e7fc6-9b24-44a6-bb65-b88e2b0cf937, iOSf63c0db6-6f5b-49de-b369-bf6aa7d52a1b. -
Wunsch 09.10. (Obsidian „Mobile - UI Rework“): Login-Seite wirkt statisch, Sprachwahl zu dominant, Logo fehlt, Reihenfolge seltsam. Nachtrag: Nutzer versteht nicht, warum „Mit Google anmelden“ auf der Registrierung ausgegraut ist. → Umgesetzt (09.10.): Login und Registrierung neu aufgebaut (gemeinsamer Rahmen
src/components/auth/AuthShell.tsx): Logo + „PawFeed“ oben, Sprache als kleiner „DE ⌄“-Chip mit Menü, Formular unten (E-Mail/Passwort → Anmelden → „oder weiter mit“ Apple/Google). Animationen nur mit eingebautemAnimated(OTA-fähig): Logo federt rein, Inhalte gleiten gestaffelt ein, Feldrahmen orange bei Fokus, Ladekringel im Knopf, Felder wackeln + rot bei falschem Login; „Bewegung reduzieren“ wird beachtet. Android: Abstände über Statusleiste/Gestenleiste per Safe-Area, 28 pt Seitenrand (Zurück-Wischzone), Sprachmenü als Modal (Zurück-Geste schließt nur das Menü), Tastatur schiebt das Formular jetzt hoch (KeyboardAvoidingViewauch auf Android, nötig seit Edge-to-Edge). Google/Apple auf der Registrierung nicht mehr ausgegraut: Tippen ohne Haken markiert die Checkbox rot, lässt sie wackeln und zeigt einen Hinweis. Typecheck + Lint sauber, live im Android-Emulator (Pixel 10 Pro, Gestensteuerung) getestet: Layout, Sprachmenü + Zurück-Geste, Tastatur, Fehlerfall, Hinweis. iOS nur per HTML-Vorschau abgenommen, nicht auf Gerät. Per OTA ausgeliefert 09.10. (Runtime 1.0.6, Android + iOS). -
Wunsch 09.10. (Obsidian „Mobile - UI Rework“): „Freunde einladen“ in den Einstellungen sieht nach AI-Slop aus; Onboarding dynamischer machen statt statischer Seiten. Nachtrag beim Test: Die Detailseite „Freunde einladen“ passte nicht mehr zum neuen Design. → Umgesetzt (09.10.): Neue
InviteCard(src/components/referrals/) in den Einstellungen und oben auf/invite: Rang mit Abzeichen (ohne Rang gestrichelt „Dein erster Rang wartet“), markierbarer Code (Kopieren-Knopf bräuchte natives Modul), animierter Fortschrittsbalken, „Link teilen“./inviteneu: Ränge als Zeitleiste mit „Als Nächstes“, Status-Etiketten bei eingeladenen Tieren. Onboarding (app/onboarding/pet.tsx+src/components/onboarding/flow/): Willkommen mit 3 Regel-Karten + beiden Bestätigungen auf einer Seite → Name (Buchstabe live) → Tierart als Chips + Rasse → Beschreibung/Geschichte (legt Tier an) → Foto → Spinnen-Schalter (entfällt bei Spinne) → Herkunft (nur erstes Tier) → Abschluss mit Pfoten-Konfetti; Fortschrittsbalken, Zurück (nicht nach dem Anlegen), Android-Zurück-Geste geht einen Schritt zurück. Fund: Neue Nutzer sahen auf „Bevor es losgeht“ alle 7 Änderungsnotizen der Rechtstexte statt der Regeln — Regeln jetzt als feste App-Texte,legal.acknowledgeunverändert (Web-Onboarding hat dasselbe Problem noch). Typecheck + Lint sauber, live im Android-Emulator (Dunkelmodus) getestet: Karte,/invite, kompletter Onboarding-Durchlauf mit Testtier „Testi“ (danach über „Tier löschen“ entfernt, DB geprüft). Einmal reagierte „Profil anlegen“ erst beim zweiten Tippen, nicht reproduziert. Hellmodus und iOS nicht auf Gerät geprüft. Per OTA ausgeliefert 09.10. (Runtime 1.0.6, Android + iOS). -
Gefunden 09.10. (Video-Aufnahmen): Nach dem Onboarding zeigte „Meine Tiere“ das neue Tier nur mit Anfangsbuchstaben, obwohl das Foto hochgeladen war (bis zum App-Neustart). → Behoben (09.10.):
AvatarSteplädt nach dem Upload die Tierliste neu (pets.listinvalidiert). Außerdem zeigt der Abschluss-Screen des Onboardings jetzt das hochgeladene Foto statt des Buchstabens. Typecheck + Lint sauber, live im Emulator geprüft (Liste zeigt Foto sofort, Abschluss mit Foto).