Commit Graph
441 Commits
Author SHA1 Message Date
adminandClaude Opus 5.5 c74bbffccb feat: Datumseingabe TT.MM.JJJJ (App) + Erinnerung an Folgeimpfung
Datum (found.md, iOS-Feedback): neue DateField-Komponente mit Ziffern-
tastatur und automatisch eingefügten Punkten (TT.MM.JJJJ) für Geburtstag,
Adoptionstag, Gewicht, Tierarzt und Impfungen. Parser akzeptiert weiter
"-" und "/" sowie einstellige Tage/Monate. Wheel-Picker bleibt in
PENDING-NATIVE-BUILD.md (natives Modul).

Impf-Erinnerung (found.md, iOS-Feedback): täglicher Cron
/api/cron/vaccine-reminders erinnert einmalig 30 Tage vor
Vaccine.nextDueDate per Mitteilung (VACCINE_DUE) + Push mit Impfname und
Datum. Schema: NotificationType.VACCINE_DUE, Notification.vaccineId
(Cascade), Vaccine.reminderSentAt (Claim gegen Doppelversand, wird bei
Fehler wieder freigegeben). Web + App zeigen die Mitteilung an, Tippen
öffnet die Gesundheitsseite. App: Schnellauswahl +1/+3 Jahre für den
Folgetermin plus Hinweis auf die Erinnerung.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 12:42:20 +02:00
adminandClaude Opus 5.5 7169840000 fix(mobile): Apple-Login hängt nicht mehr still bei fehlenden Pflichtfeldern
Fehlen nach dem Apple-Login noch Pflichtangaben (z. B. Vor-/Nachname,
die Apple nur bei der allerersten Autorisierung schickt), zeigt der
Button jetzt eine Fehlermeldung und meldet die Felder an Sentry, statt
kommentarlos nichts zu tun.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:01:19 +02:00
adminandClaude Opus 5.5 f112d36f4a feat: neues Tier folgt dem Kurator-Tier zurück
Bisher folgte nur "PawFeed Team" dem neuen Tier, der Feed des neuen
Nutzers startete leer. welcomeNewPet legt jetzt auch den Follow in
Gegenrichtung an und befüllt den Redis-Feed per backfillOnFollow mit den
letzten Team-Posts. Gleicher Admin-Schalter (autoFollowEnabled),
Beschriftung im Kurator-Panel angepasst.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 19:49:46 +02:00
adminandClaude Opus 5.5 80e27a7f0b docs(mobile): found.md — Upload-Fortschritt Video-Storys
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:47:03 +02:00
adminandClaude Opus 5.5 5606a81dd2 feat(mobile): Fortschrittsbalken beim Video-Story-Upload
Statt nur Spinner: „Upload wird vorbereitet …“, dann Balken + Prozent aus
expo-file-system File.upload onProgress (nativ seit 57.0.7 im 1.0.6-Build,
daher OTA). Vorschau ist während des Uploads nicht mehr antippbar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:44:35 +02:00
adminandClaude Opus 5.5 6979447b6d docs(mobile): found.md — Video-Storys per OTA live
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:29:48 +02:00
adminandClaude Opus 5.5 69e2c1364e feat(mobile): Video-Storys in der App (Upload + Wiedergabe)
Merged feature/mobile-video-stories (Gitea #37) auf den seit 02.10.
umgebauten Story-Viewer: Galerie-Picker nimmt Videos bis 30 s, Upload
direkt zu Mux, Viewer spielt READY-Videos ab (Fortschritt aus der echten
Wiedergabe, Weiter bei playToEnd) und zeigt PROCESSING/ERROR. Offene
Kommentar-/Zuschauer-Sheets pausieren das Video wie den Foto-Timer.
Nur JS — expo-video ist seit dem 1.0.6-Build nativ enthalten, also OTA.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:25:24 +02:00
adminandClaude Opus 5.5 a9b6a57585 docs(mobile): found.md — HEIF-Fix vom Nutzer bestätigt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:37:50 +02:00
adminandClaude Opus 5.5 00fb0db168 docs: CLAUDE.md — Dashboard-Kachel Tierarten
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:34:19 +02:00
adminandClaude Opus 5.5 f1ccc78005 feat: Dashboard-Kachel Tierarten klappbar (standardmäßig zu, Zustand gemerkt)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:31:09 +02:00
adminandClaude Opus 5.5 9adba560a7 feat: Admin-Dashboard — Verteilung der Tiere nach Tierart und Rasse
- petAdmin.speciesDistribution: Anzahl pro Tierart (auch Arten ohne Tiere)
  und pro Rasse, deutsche Namen, ohne das Kurator-Tier „PawFeed Team“
- Karte "Tierarten" auf dem Dashboard: sortiertes Balkendiagramm (eine
  Reihe, Markenorange), Anzahl + Anteil als Text, Tooltip bei Hover/Fokus,
  Klick klappt die Rassen der Art auf

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:17:21 +02:00
adminandClaude Opus 5.5 efc82d636d docs: CLAUDE.md — Tierverwaltung, deletePetCompletely, Rang-Sperre
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:05:05 +02:00
adminandClaude Opus 5.5 566a2eedd0 feat: Admin-Tierverwaltung + vollständiges Löschen von Tieren
Admin /p/[secret]/pets:
- Liste mit Suche (Name, Spitzname, Empfehlungscode, ID), Filtern und
  Sortierung; Detail-Panel mit Kennzahlen, Owner, Profiltexten, Beiträgen
- Verifiziert / Gründungsmitglied pro Tier umschalten
- Empfehlungsränge des Owners: dauerhaft entziehen (bis zur Freigabe),
  freigeben oder manuell vergeben (besondere Leistung)
- Inhalte leeren (Profilbild, Bio, Adoptionsgeschichte, Spitzname) und Tier
  löschen — jeweils mit Begründung, Owner per Team-DM informiert bzw. per
  E-Mail, wenn es sein einziges Tier war

Ränge: ReferralRankAchievement bekommt revokedAt/revokeReason/
grantedManually; entzogene Ränge werden weder neu vergeben noch im Cache
berücksichtigt (awardRanks, recomputeReferralRanks, referrals.me, Export).

Fix: deletePetCompletely (src/lib/delete-pet.ts) für Owner-Löschen,
Kontolöschung und Admin — vorher konnte das Löschen an StoryView/Report/
Repost-Fremdschlüsseln ohne Cascade scheitern, und die Zähler an fremden
Beiträgen/Storys wurden nicht verringert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:03:05 +02:00
adminandClaude Opus 5.5 7a064d8a36 docs: CLAUDE.md — Download-Weiterleitung /app
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:41:49 +02:00
adminandClaude Opus 5.5 94c143e17d feat: Download-Weiterleitung /app für Flyer und QR-Codes (D3)
- Android → Google Play, UTM-Werte als Play-referrer (Play Console)
- iPhone → App Store, sobald APP_STORE_URL gesetzt ist (D5); bis dahin Web
- sonst → Web-Startseite; ?ref=<Code> führt auf die Einladungsseite /r/<Code>
- nur sichere UTM-Werte werden übernommen, nie gecacht (302, no-store)
- Zählung pro Tag/Quelle/Gerät in Redis, Anzeige im Admin unter
  Empfehlungen → Übersicht (30 Tage)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:39:40 +02:00
adminandClaude Opus 5.5 8143e7b667 docs: CLAUDE.md — Gründungsmitglieder und Kurator-Begrüßung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:33:30 +02:00
adminandClaude Opus 5.5 307b76e8fd feat: Gründungsmitglieder (erste 250 Tiere) und Kurator-Begrüßung
- Pet.isFoundingMember: in pets.create per bewachter SQL-Anweisung für die
  ersten 250 Tiere gesetzt, nie entzogen; Abzeichen (Spross) in Feed und
  Profil, Web + App, unabhängig vom Empfehlungsprogramm
- Kurator "PawFeed Team": folgt jedem neuen Tier und schickt eine
  Begrüßungs-Direktnachricht (DE/EN nach Sprache beim Anlegen), im
  Hintergrund — blockiert das Onboarding nicht
- CuratorSettings + Admin-Seite /p/[secret]/curator: Schalter, Texte mit
  Pflicht-Platzhalter {name} und Vorschau, Zähler der Gründungsmitglieder
- prisma/backfill_founding_members.sql, prisma/enable_rls_curator.sql

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:26:43 +02:00
adminandClaude Opus 5.5 9f7acf1d98 docs(mobile): found.md — 7-Tage-Story-Ansicht deployt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 19:35:46 +02:00
adminandClaude Opus 5.5 2c0680cef9 feat: 7-Tage-Ansicht der eigenen Storys für den Ersteller (Web + App)
- stories.listActive: der Owner bekommt seine Storys der letzten 7 Tage mit
  isExpired, alle anderen weiterhin nur die aktiven 24 Stunden
- stories.hasActiveStory: optional includeOwnRecent → grauer Ring
  (expiredOnly) nur in der Story-Leiste, nicht an Profilbildern im Feed
- Viewer: Hinweis "Abgelaufen – nur für dich sichtbar", Kommentare bei
  abgelaufenen Storys nur lesbar, Pfote nur als Zähler; Löschen und
  Zuschauerliste bleiben

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 19:30:22 +02:00
adminandClaude Opus 5.5 a01c58e5f0 feat: Aufräum-Job für Storys älter als 7 Tage
- /api/cron/cleanup-stories (CRON_SECRET): löscht Storys älter als 7 Tage
  samt Aufrufen, Pfoten, Kommentaren, Supabase-Bild und Mux-Asset; max. 200
  pro Lauf, Fehler einzelner Storys brechen den Lauf nicht ab
- gemeinsame Funktion deleteStoryWithMedia (src/lib/story-cleanup.ts), auch
  von stories.delete genutzt
- Datenschutzerklärung Abschnitt 6: Storys spätestens nach 7 Tagen gelöscht
- Datenexport: Story-Block heißt "stories" statt "activeStories"
- CLAUDE.md: Cron-Jobs laufen über die NAS-Crontab + docker/run-cron.sh
  (der alte Hinweis "nichts ruft trim-feeds auf" war veraltet)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:43:07 +02:00
adminandClaude Opus 5.5 ac664d488d docs(mobile): found.md — Story löschen deployt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:21:12 +02:00
adminandClaude Opus 5.5 81d9c6da30 feat: eigene Story löschen (Web + App)
- stories.delete: nur Owner; Aufrufe, Story (Pfoten/Kommentare per Cascade),
  danach Bild in Supabase Storage bzw. Mux-Asset best-effort
- Web: Papierkorb neben der Zuschauerzahl + Rückfrage, Timer pausiert,
  gelöscht wird die beim Antippen gemerkte Story
- App: gleicher Papierkorb mit nativer Rückfrage, Timer pausiert
- found.md: Nutzer-Feedback "Story löschbar" erledigt, 7-Tage-Wunsch mit
  Befund als offener Punkt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:17:16 +02:00
adminandClaude Opus 5.5 4ec5d8c5f4 docs(mobile): found.md — Story-Fixes deployt (Web + OTA)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:03:06 +02:00
adminandClaude Opus 5.5 ccebfa46a6 feat: Story-Kommentare, Pfoten und Zuschauerliste in der App
- App-Viewer: Pfote, Kommentar-Sheet (schreiben, eigene löschen) und für die
  eigene Story die Zuschauerliste; Timer pausiert, solange ein Sheet offen ist
- stories.listActive: optionales viewerPetId → reactedByViewer, damit die
  Pfote gefüllt startet (abwärtskompatibel für alte App-Builds)
- Web-StoryPawButton nutzt reactedByViewer ebenfalls und wird pro Story
  neu initialisiert

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:59:02 +02:00
adminandClaude Opus 5.5 204d5f6831 fix: eigene Story als Ring "Deine Story" in der Story-Leiste (Web + App)
Die Leiste zeigte nur Storys gefolgter Tiere — das eigene aktive Tier war
nie enthalten, man konnte die eigene Story nach dem Posten nicht ansehen.
Neuer Ring direkt nach der "+"-Kachel, solange stories.hasActiveStory für
das aktive Tier true ist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:46:29 +02:00
adminandClaude Opus 5.5 1a24ebae89 docs(mobile): found.md — HEIC-Fix deployt (Web + OTA)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:32:11 +02:00
adminandClaude Opus 5.5 1bf0f9282a fix: HEIF/HEIC-Fotos (Apple) für Beiträge und Storys annehmen
- App: post-new.tsx sortierte HEIC/HEIF still aus, obwohl resizeForUpload()
  ohnehin in JPEG umwandelt — jetzt erlaubt, plus Hinweis bei übersprungenen
  Fotos
- Web: neues src/lib/heic-to-jpeg.ts wandelt HEIC vor dem Upload im Browser
  in JPEG um (Safari kann HEIC nativ dekodieren); eingebaut in Beiträge,
  Storys, Meilensteine und Tierbild, accept um HEIC ergänzt. Browser ohne
  HEIC-Dekodierung bekommen eine klare Meldung statt "falsches Format".
- Server-Whitelist (JPEG/PNG/WebP) bleibt unverändert

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:26:24 +02:00
adminandClaude Opus 5.5 8f8fc8d75e fix: Tierbild auf der Einladungsseite /r/[code] größer darstellen
Die Avatar-Variante "lg" setzt per data-Attribut fest size-10 (40 px) und
überstimmte die eigene Größe — jetzt Standardvariante mit size-28 / sm:size-36
und dezentem Ring in Markenfarbe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 19:23:08 +02:00
adminandClaude Opus 5.5 18f25ce316 fix: DSGVO-Lücken des Empfehlungsprogramms schließen (Auskunft + Löschung)
- Datenexport (Art. 15): neuer Block referralProgram mit eigenem Code,
  Herkunftsangabe, "eingeladen von", gemachten Einladungen, erreichten Rängen,
  aktuellen Vorteilen und den früheren Einmal-Codes. Andere Personen nur über
  den Tiernamen — invitedById (Clerk-ID eines Dritten) fliegt aus dem Export.
- Kontolöschung: invitedById bei Eingeladenen und usedById bei Beta-Codes
  werden geleert, damit keine Clerk-ID der gelöschten Person zurückbleibt.
  Gezählte Einladungen bleiben gezählt.
- Einlösen sperrt jetzt auch über invitedAt, damit nach dem Leeren von
  invitedById kein zweiter Code eingelöst werden kann.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 18:57:59 +02:00
adminandClaude Opus 5.5 32ba01f7cf refactor: altes Einladungs-Gate (InviteCode/pf_invite) durch Empfehlungsprogramm ersetzen
- Proxy-Sperre für /sign-up, INVITE_REQUIRED, set-invite/consume-invite,
  invites-Router, Admin-Invite-Seite und -Prozeduren, Startcodes in
  pets.create entfernt — Registrierung ist offen
- /join?code=… leitet auf /r/<code> um, /invite auf /einladen; alte geteilte
  Links laufen nicht ins Leere
- InviteCode-Tabelle bleibt nur als Historie (Kontolöschung räumt sie weiter auf)
- Datenschutzerklärung 4b (Empfehlungsprogramm, Herkunftsangabe, pf_ref-Cookie)
  und Nutzungsbedingungen 3b (Programmbedingungen, Bestandsschutz, Missbrauch)
- CLAUDE.md: Abschnitt "Referral program" statt "Invite system"

Build, Typecheck und alle Tests grün.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 06:35:22 +02:00
adminandClaude Opus 5.5 78e16c9210 feat(mobile): Empfehlungsprogramm in der App
- Bildschirm "Freunde einladen" (/invite, aus den Einstellungen erreichbar):
  eigener Code mit nativem Teilen-Dialog, Rangleiter mit Fortschritt,
  eingeladene Tiere, nachträgliche Code-Eingabe im Einlösefenster
- Onboarding-Schritt "Wie hast du von PawFeed erfahren?" mit Code-Eingabe,
  einmal pro Owner (referrals.onboardingState)
- Rang-Abzeichen in PetIdentityBadges (Feed und Profil), Profilring in
  Rangfarbe, "Eingeladen von …" im Tierprofil
- Benachrichtigungen REFERRAL_JOINED / REFERRAL_RANK_UP
- Keine neuen nativen Module (React Native Share) — per OTA auslieferbar

Typecheck grün; nicht auf einem Gerät getestet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 06:30:11 +02:00
adminandClaude Opus 5.5 4d0aa7ab9e feat: Clerk-unabhängiges Empfehlungsprogramm mit einstellbaren Rängen (Web + Admin)
Persönliche, unbegrenzt nutzbare Empfehlungscodes (z. B. BUBI-7K3M), die erst
nach der Registrierung im Onboarding eingelöst werden — keine Kopplung an den
Clerk-Sign-up-Ablauf mehr. Registrierung ohne Code bleibt möglich.

- Schema (rein additiv): Owner-Felder für Code, Einladungsstatus, Zähler und
  Rang-Cache, ReferralRank / ReferralRankAchievement / ReferralSettings,
  AcquisitionSource, NotificationType REFERRAL_JOINED / REFERRAL_RANK_UP
- Kernlogik src/lib/referrals.ts: Einlösen (7-Tage-Fenster, kein eigener Code,
  keine Kreis-Einladungen, gesperrte Einladende ungültig), gegenseitiges
  Folgen, Qualifizierung erst nach Tier + erstem Beitrag (Foto oder fertiges
  Video), Tageslimit mit Prüf-Markierung, Ränge mit Bestandsschutz
- Web: /einladen, öffentliche Seite /r/[code], Onboarding-Schritt
  "Wie hast du von PawFeed erfahren?", Rang-Abzeichen, Profilring,
  "Eingeladen von …", neue Benachrichtigungen
- Admin /p/[secret]/referrals: Ränge anlegen/bearbeiten/deaktivieren mit
  Live-Vorschau, Einstellungen, Übersicht mit Prüfung und Aberkennung;
  bevorzugte Verifizierung als Vorteil
- prisma/scripts/referral-setup.ts: Start-Ränge, Settings, Code-Backfill,
  optional --credit-existing für Alt-Einladungen

Noch offen: Mobile-App, Abbau des alten InviteCode-Ablaufs, Rechtstexte,
db push + Deploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 06:25:13 +02:00
adminandClaude Opus 5.5 02662528cf chore(mobile/ios): bump iOS build number to 3
Build 2 was rejected in TestFlight beta review (missing demo credentials)
and cannot be resubmitted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 06:01:25 +02:00
adminandClaude Opus 5.5 959d67cc29 chore(mobile/ios): bump iOS build number to 2
Build 1.0.6 (1) was expired in TestFlight and cannot be re-used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:21:57 +02:00
adminandClaude Opus 5.5 2cd13537f7 docs(mobile): found.md — gesture-bar and story-ring fixes shipped via OTA
Also includes the user's own pending found.md edits (new entries, iOS
section header, trailing-whitespace cleanup).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:43:26 +02:00
adminandClaude Opus 5.5 2ef439c752 fix(mobile): story paw ring clipped at the top
The middle toe beans reach y = -9 in the 0–100 viewBox. Web draws the SVG
with overflow: visible; react-native-svg clips at the viewBox, cutting the
paw off. Extend the viewBox upward and grow the box to match; the "add
story" tile uses the same box so it lines up with the rings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:41:43 +02:00
adminandClaude Opus 5.5 de237f19a1 fix(mobile): content hidden under Android gesture bar on stack screens
Android is edge-to-edge, and stack screens (no tab bar below) had no
bottom inset on their scroll containers — the first post on a pet profile
sat in the gesture area and couldn't be tapped (found.md). New
useBottomSafePadding hook adds insets.bottom to the contentContainerStyle
of pet profile, followers, following, health, milestones, edit pet,
settings, search, messages list and delete account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:41:42 +02:00
adminandClaude Opus 5.5 e4139a1b9b docs(mobile/ios): App Store listing texts and iOS screenshots
- store-assets/app-store-beschreibung.md: subtitle, promotional text,
  keywords and description for App Store Connect (no emojis — ASC rejects
  them)
- store-assets/ios-screenshots (1320x2868, 6.9") and ios-screenshots-6.5
  (1284x2778, 6.5"): appetize.io iPhone screenshots scaled/cropped to
  Apple's required sizes
- .gitignore: ignore local debug/ screenshot folder

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 12:01:40 +02:00
adminandClaude Opus 5.5 3b6735ebee chore(mobile/ios): iOS build number and Apple Team ID for App Store submit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 11:19:17 +02:00
adminandClaude Opus 5.5 4213d7029e feat(mobile): block pets and delete account in-app (App Store requirements)
- Block (Guideline 1.2, UGC): useBlockPet hook (native confirm Alert,
  blocks.create). PostCard "..." on other pets' posts now offers
  Report / Block; pet profile gets a header "..." with Report pet / Block
  (hidden for any of the owner's own pets), navigating back after a block.
  Feed, comments and DMs already enforce blocks server-side; explore and
  search don't yet (server follow-up).
- Delete account (Guideline 5.1.1(v)): new delete-account screen reached
  from a quiet link below Log out in Settings. Mirrors web's
  DeleteAccountDialog (warning list + type a pet name) and calls the same
  POST /api/account/delete with the Clerk bearer token, then clears the
  query cache and signs out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 11:19:17 +02:00
adminandClaude Opus 5.5 0c3ab5c2a2 fix(mobile): onboarding steps unreadable in dark mode
ArachnophobiaOptIn, UploadConsent, OnboardingGuidelines and AvatarStep
still used the static light-palette tokens in module-level
StyleSheet.create, so titles and checkbox labels rendered dark-on-dark.
Switched them to useTheme() + makeStyles(colors) like the other screens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 09:07:49 +02:00
adminandClaude Opus 5.5 69e095ddcb fix(mobile/ios): back button showed "< (tabs)" label
iOS labels the back button with the previous screen's title, which was
the untitled (tabs) route group. Use headerBackButtonDisplayMode
"minimal" (chevron only) for all stack screens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 09:07:49 +02:00
adminandClaude Opus 5.5 1e7d76aa79 feat(mobile/ios): iOS simulator build profile and native Sign in with Apple
- eas.json: new `preview-simulator` profile (extends preview, ios.simulator)
  for EAS cloud simulator builds without an Apple Developer account
- app.json: iOS deployment target 17.0 via expo-build-properties
  (@clerk/expo's ClerkKit SPM package requires iOS 17 — pod install failed
  on the default 16.4), iPhone-only (supportsTablet: false),
  usesAppleSignIn, ITSAppUsesNonExemptEncryption: false
- AppleSignInButton: native Apple sheet via Clerk's useSignInWithApple
  (App Store Guideline 4.8, since Google login is offered); same
  legal-consent handling as GoogleSignInButton; iOS-only
- Not yet testable end-to-end: needs Apple Developer account, the
  Sign in with Apple capability on the App ID and Apple enabled in Clerk

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 09:07:49 +02:00
adminandClaude Opus 5.5 070c389786 docs: note self-hosted Inter font in DESIGN.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 20:13:39 +02:00
adminandClaude Opus 5.5 71ac36b08a feat(landing): self-host Inter font and promote Android app on Google Play
- Replace next/font/google with next/font/local + vendored Inter variable
  woff2 (latin, @fontsource-variable/inter@5.3.0), so neither visitors nor
  the Docker build contact Google's servers.
- Add PlayStoreBadge (official Google Play artwork, DE/EN by locale, served
  locally from /public/badges) to the hero, a new "PawFeed in your pocket"
  section, and the shared landing footer (also covers /ueber-uns).
- Centralize the Play Store URL in src/lib/app-links.ts (derived from the
  android.package id org.pawfeed.app).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 19:54:14 +02:00
adminandClaude Sonnet 5 779f18966d docs(mobile): note main-merge and OTA publish for sso-callback fix
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 17:36:04 +02:00
adminandClaude Sonnet 5 17a17bd392 fix(mobile): add sso-callback route to fix Unmatched Route on Android Google login
Multiple users reported "Unmatched Route pawfeed://sso-callback" after
Google sign-in. Root cause: Android's custom tab delivers the OAuth
redirect intent to the app twice — once caught correctly by
expo-web-browser's openAuthSessionAsync() session, but also as a plain
deep link seen by expo-router's own Linking listener. With no matching
route, expo-router briefly showed its built-in Unmatched Route error
screen instead of letting the real sign-in flow (GoogleSignInButton ->
setActive -> router.replace) take over.

Adds app/sso-callback.tsx as a themed loading spinner so expo-router has
a valid screen for that window; no auth logic needed there since
useProtectedRoute() in app/_layout.tsx already redirects based on
Clerk's session state. JS-only change, OTA-deployable, no native rebuild
needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 17:24:35 +02:00
adminandClaude Sonnet 5 2b285de09e feat(mobile): add video story upload and playback (Gitea #37)
Extends the gallery picker to accept videos, uploads them via Mux direct
upload (same flow web already uses), and adds PROCESSING/READY/ERROR
handling to the story viewer with real playback-driven progress instead
of a fixed timer.

Fixes a video-viewer bug found during device testing: play() was called
before the player reached readyToPlay, leaving duration at 0 and firing
playToEnd immediately — the viewer closed within ~1s instead of playing.
Now waits for statusChange to readyToPlay before calling play().

Also fixes the story-creation "Story teilen" button sitting flush against
gesture navigation on devices without a bottom safe-area inset applied.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 14:23:03 +02:00
adminandClaude Sonnet 5 aa75fe612b fix(stories): video picker not showing videos on story creation
The story upload input's accept attribute listed explicit image+video
MIME subtypes (image/jpeg,...,video/mp4,...). Several mobile
browsers'/OS's native 'Photos & Videos' pickers only reliably offer
both media kinds when given the broad image/*,video/* wildcard
categories - the explicit mixed list was silently narrowing the picker
to photos only, matching the user's report ('nur Zugriff auf Fotos,
Videos werden gar nicht angezeigt').

The actual accept/reject decision is unchanged (still enforced in
handleFile() against the specific ALLOWED_IMAGE_TYPES/
ALLOWED_VIDEO_TYPES lists) - this only relaxes what the OS offers in
the picker dialog.

Code-reviewed before commit (WORKFLOW.md step 6) - fixed the one
finding that became newly reachable by this fix: videos were
previously never selectable at all, so a parameterized/codec-suffixed
MIME string (e.g.  from some Android camera-roll
pickers) could never surface as a rejection; now strips codec
parameters before the ALLOWED_VIDEO_TYPES comparison. Documented two
other findings as accepted, not-fixed-here trade-offs in code comments
(iOS HEIC auto-transcode interaction, broader picker surfacing formats
that still get rejected post-selection) rather than silently ignoring
them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 19:08:07 +02:00
adminandClaude Sonnet 5 ea3cf1dcd4 fix(admin): music-track upload failing on valid audio files
Two independent root causes behind 'admin music upload fails':

1. Supabase bucket name mismatch — code expects 'music-tracks' (plural,
   MUSIC_STORAGE_BUCKET), but the bucket was created as 'music-track'
   (singular). Every upload failed with a bucket-not-found error from
   Supabase Storage, surfaced only as a generic toast. Fixed by creating
   the correctly-named bucket (public, 5MB limit, audio/mpeg|mp4|aac
   allowed_mime_types matching the app's own constants) via the Supabase
   Storage API; verified end-to-end with a signed-upload-url + PUT probe.
   The old empty 'music-track' bucket is unused but still exists -
   deleting it needs the user's own action (blocked here by the
   auto-mode classifier's cloud-storage-delete guard).

2. Client-side validation trusted the browser-reported File.type, which
   is sniffed from the OS's MIME registry and is inconsistent for
   .m4a/.aac (e.g. Windows Chrome reports .m4a as audio/x-m4a, not
   audio/mp4) - a perfectly valid file could get rejected as 'wrong
   type'. Now derives the content-type from the file extension instead.

Code-reviewed before commit (WORKFLOW.md step 6) - fixed two of four
findings: the extension lookup now uses a Map instead of a plain object
(prototype-shadowing via a file named e.g. 'x.constructor' previously
bypassed the rejection), and requires an actual '.' before the
extension (a bare filename like 'mp3' no longer matches). Extracted the
allowed-types/size constants into a new client-safe src/lib/music-
content-types.ts (supabase-storage.ts re-exports them) so the client
form and server-side Zod schema share one source of truth instead of
two independently maintained copies. Left the trust-the-extension
trade-off as-is (documented in code): this panel sits behind
ADMIN_SECRET + a role check, not the public upload surface, and the
old File.type check was never real content-based validation either.

Full test suite green (one unrelated legal.test.ts timeout in the
full-suite run was confirmed flaky - passes cleanly in isolation).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 18:49:51 +02:00