387 Commits
Author SHA1 Message Date
adminandClaude Sonnet 5 8b1aba1d9f feat(mobile): show OTA update id next to app version
Meine Tiere tab footer now shows 'Version X.X.X - OTA <short-id>' (or
'Build (kein OTA)' when running the embedded/non-OTA bundle) via
expo-updates' Updates.isEmbeddedLaunch/updateId. Directly answers the
support question 'did the update actually arrive on this device?' by
comparing the shown short id against the 'Android update ID' an
'eas update' publish prints - the exact ambiguity that cost a multi-day
debugging session earlier (see .claude/handoffs/2026-09-12-ota-update-
mystery-expo-dev-client-root-cause.md).

Code-reviewed before commit (per WORKFLOW.md step 6): fixed two of four
findings - wrapped the expo-updates reads in a try/catch (LegalSection
sits outside FooterErrorBoundary, so an unguarded throw here would have
taken down the whole footer) and moved the hardcoded 'OTA ' prefix into
i18n (pets.otaId). The web-shim-always-unknown finding is a documented
dead branch (this app ships no web build - eas update only ever runs
--platform android). No test coverage added - no RN test infrastructure
exists in mobile/ yet (pre-existing gap, tracked in WORKFLOW.md).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 11:05:26 +02:00
adminandClaude Sonnet 5 7187fedb38 docs: document AI-assisted dev workflow + system architecture diagram
Adds WORKFLOW.md (the living, discussion-oriented version) and a
contributor-facing summary in README.md, reflecting four automation
decisions made 2026-09-19:
- OTA publish and web rolling-deploy run automatically once
  typecheck+lint+code-review are clean, no per-change confirmation
- a code-review pass (code-review skill - the code-reviewer agent named
  in .claude/rules/ecc isn't installed in this environment) runs on
  every diff before commit
- twin instances of a found bug pattern get fixed in the same pass,
  not just reported
- large mobile features go through a planning step (Plan agent /
  EnterPlanMode - the installed equivalent of the referenced planner
  agent) and their own feature branch, merging to main (and only then
  triggering the automatic deploy) once complete

Also adds a Mermaid system architecture diagram to README.md covering
both clients (web + mobile) against the shared Next.js/tRPC backend,
data/media services, and the two deploy paths (NAS rolling-deploy vs.
EAS Build/Update) - validated by rendering it through mermaid-cli.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 10:05:33 +02:00
adminandClaude Sonnet 5 be2ab20273 fix(mobile): dark-mode white-on-white search input text
Same root cause as post-new.tsx/story-new.tsx: search.tsx imported the
static light-only colors/typography instead of useTheme(). Bigger
refactor than the other two since TabButton/PetRow/Loading/EmptyState
are separate top-level components, not closures inside the screen -
they now receive styles/colors as props from the theme-aware
makeStyles(colors) built in SearchScreen, rather than importing the
static tokens themselves.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 09:44:12 +02:00
adminandClaude Sonnet 5 9185e54402 fix(mobile): dark-mode white-on-white caption text in New Post
post-new.tsx (and story-new.tsx, same latent bug) still imported the
static, light-only colors/typography from theme/tokens.ts instead of
useTheme() - container background stayed permanently light while the
shared TextField correctly pulled dark-mode text color from the theme,
producing white text on a white background in the caption input.

Migrated both to the useTheme() + makeStyles(colors) pattern already
used by milestone-new.tsx. search.tsx has the same underlying issue but
needs a larger refactor (several sub-components reference the static
tokens directly) - left for a separate pass, noted in found.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 22:25:08 +02:00
adminandClaude Sonnet 5 a39ba76108 docs: document EAS update --platform gotcha and node_modules corruption fix
Two Known-Issues entries from tonight's OTA-publish session:
- eas update needs --platform android explicitly (no web target/
  react-native-web in this project, --platform all fails bundling)
- mobile/node_modules can end up with silently missing nested files after
  a bad install, invisible to npm install itself (seen across @expo/cli,
  @sentry/browser, @sentry-internal/browser-utils in the same session) -
  full rm -rf node_modules && npm install is the fix, not a targeted one

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 22:19:58 +02:00
adminandClaude Sonnet 5 1791aca690 docs+chore: add DB restore script and document backup/restore in README
docker/restore-db.sh - emergency-only, not wired into any crontab. Lists
available backups when run without args; restores via pg_restore
(--clean --if-exists --no-owner --no-privileges -j 4) against DIRECT_URL,
same throwaway postgres:17-alpine container pattern as backup-db.sh.
Requires typing RESTORE to confirm (FORCE=1 skips it for scripted use).

README.md gets a new 'Database backups & disaster recovery' section
(setup step 9) documenting all three scripts, the DIRECT_URL vs
DATABASE_URL reasoning, and the storage-metadata restore caveat. No
admin-panel UI for this by design - restore is SSH-only, deliberately
higher-friction than a browser button.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 20:17:57 +02:00
adminandClaude Sonnet 5 282ff4e741 chore(docker): add missing backup-db.sh NAS DB backup script
Same gap as run-cron.sh: the crontab's 03:00 backup-db.sh entry pointed
at a script that never actually existed, so there have been no automated
DB backups since that entry was added.

pg_dump via a throwaway postgres:17-alpine container (matches Supabase's
server version; no postgresql-client on the NAS host), against DIRECT_URL
(non-pooled) rather than the pgbouncer-fronted DATABASE_URL, custom
format (-Fc). Writes to /srv/dev-disk-by-uuid-ad295d7f-a870-4f70-9de2-dfded1fabf7f/BACKUPALL/pawfeed/
with 30-day retention, logs to docker/backup.log for visibility (no local
mail delivery configured on this NAS).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 19:34:10 +02:00
adminandClaude Sonnet 5 6cc697a696 chore(docker): add missing run-cron.sh NAS cron runner
Both existing crontab entries (trim-feeds, anniversaries) and backup-db.sh
referenced a run-cron.sh that was never actually created/committed - cron
has been executing it daily (04:00/08:00) with exit 127 since at least
today, silently, because no local mail delivery is configured for the
cron user's failure notifications.

Recreates it per README's documented curl pattern (bearer token via
CRON_SECRET, --resolve for the origin TLS cert quirk) and adds logging
to docker/cron.log so future failures are visible without relying on
cron's mail notification.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 19:27:00 +02:00
adminandClaude Sonnet 5 99575ddc82 fix(mobile): Google SSO, image resize, Sentry, dark-mode splash (1.0.3-1.0.6)
Catches up several native builds' worth of work that was already tested
live and shipped to the Play Store (per mobile/found.md TODO Neu4-Neu6)
but never made it into a git commit:

- Google SSO via expo-auth-session/expo-web-browser (GoogleSignInButton,
  useWarmUpBrowser) on sign-in/sign-up.
- Upload-time image downscaling (resize-image.ts) to fix slow first
  content loads — capped at 1600px, re-encoded JPEG @0.8.
- @sentry/react-native (GlitchTip-compatible) crash reporting, plus a
  10s auth-loading timeout screen.
- Dark-mode splash screen background, breed/birthday editing in
  PetCreateForm, and the OptionPicker Modal rewrite that fixed the
  Android nested-scroll dropdown bug across Explore/onboarding/edit.
- expo-dev-client removed from the shared plugin list (was silently
  blocking OTA updates in production), app.json bumped to 1.0.6/
  versionCode 7, several expo-* packages patched via `expo install --fix`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 21:54:08 +02:00
adminandClaude Sonnet 5 e9bad092f2 feat: pet-suggestion notifications, story music overlay, auth UX fixes
Three pieces of work from this session:

- Pet-suggestion notifications: a weekly cron (species/breed affinity
  heuristic) suggests pets to follow, with an owner opt-out and web/mobile
  notification UI wiring.
- Story music overlay: admin-curated royalty-free track catalog
  (/p/[secret]/music), attachable to stories on web (StoryForm/StoryViewer),
  with mute-original support for video stories. Mobile UI is deferred to
  the next native build (needs an audio-playback module) — tracked in
  mobile/PENDING-NATIVE-BUILD.md.
- Auth UX fixes: sign-in/sign-up now use KeyboardAvoidingView + ScrollView
  and a shared PasswordField with a show/hide toggle (mobile). Web's
  ActivePetContext gained clearGactivePetId(), wired to sign-out via a new
  SignOutCleanup component, fixing a false "you do not have permission to
  access this pet" error after switching accounts on the same browser.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 21:02:49 +02:00
adminandClaude Sonnet 5 af0cea6d3f feat: add MusicTrack model and Story music-overlay fields
Schema groundwork for the Story music overlay: an admin-curated
MusicTrack catalog and three new optional Story fields (musicTrackId,
musicOffsetSecs, musicMuteOriginal). No user-upload path — licensing
liability stays with the admin who uploads a track.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 19:59:42 +02:00
adminandClaude Sonnet 5 0a9038a9a5 feat: add PET_SUGGESTION notification type and owner opt-out
Backend groundwork for a new pet-suggestion notification: a
PET_SUGGESTION NotificationType value and an Owner.petSuggestionsEnabled
opt-out (defaults to true), mirroring the existing hideSpiders pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 18:51:44 +02:00
admin 597178ce3a docs(mobile): document eas update workflow, correct stale EAS Build status
README still said "no EAS Build has been run yet" — the app has since
gone through several production builds and is now live on Google Play
(closed testing). Also documents the new eas update / EAS Update
workflow for shipping JS-only fixes without a new store review,
closing out Gitea #35's last remaining task item.
2026-09-08 12:50:20 +02:00
admin bad24e6463 fix(mobile): sign-up link overflow, pre-login language switcher; set up EAS Update (1.0.2)
- Sign-up's Terms/Privacy links overflowed the screen width — they
  reused onboarding's long descriptive sentences ("Alle Details in
  unseren Nutzungsbedingungen") in a compact side-by-side row with no
  wrap. Switched to the existing short pets.legalTerms/legalPrivacy
  labels and added flexWrap as a safety net.
- Neither sign-in nor sign-up let you pick a language before logging
  in — extracted pets.tsx's language toggle into a shared
  LanguageSwitcher component and added it to both auth screens.
- Set up expo-updates (Gitea #35) via `eas update:configure`:
  runtimeVersion policy "appVersion", per-profile update channels in
  eas.json (development/preview/production). Future JS-only fixes can
  now ship via `eas update` without a new Play Store review — this
  build itself still needs a full native build since expo-updates is
  a native module. Manually removed a duplicate RECORD_AUDIO
  permission entry that update:configure's app.json rewrite introduced.
- Bumped to 1.0.2 (versionCode 3).
2026-09-08 06:34:50 +02:00
admin b663892865 chore(mobile): bump to 1.0.1 (versionCode 2) for the next Play Store build
Play Console requires a strictly increasing versionCode per upload —
the approved submission used versionCode 1. This release bundles the
sign-up fix, dark mode fixes, video-loop fix, and the pet edit/avatar
improvements from the last two commits.
2026-09-08 05:14:36 +02:00
admin df4d5ccec2 fix(mobile): video-loop, breed/birthday edit, avatar zoom, milestone dark mode
- Videos kept looping forever after scrolling off-screen (expo-video has
  no visibility awareness). New useVisiblePostIds hook tracks FlatList
  viewability and pauses VideoPlayer once a post scrolls away, wired
  into both the feed and the pet-profile post list.
- Pet edit screen couldn't change breed or set birthday/adoption date,
  even though the backend (pets.update) already supported all three —
  web already used them. Extracted BreedPicker out of PetCreateForm
  into a shared component, added it plus TT-MM-JJJJ date fields (same
  validation pattern as the health forms) to edit.tsx. Its BreedPicker
  nests a ScrollView, so edit.tsx's outer ScrollView was swapped for a
  FlatList to avoid the same nested-scroll gesture conflict fixed
  earlier for onboarding/pet.tsx.
- Pet profile's own avatar was a plain, non-tappable Image. Tapping it
  now opens the existing /image-viewer (same pinch-to-zoom viewer post
  images already use) when the pet has an avatar set.
- milestones.tsx and milestone-new.tsx still imported the static
  light-only colors/typography tokens instead of useTheme() — switched
  to the established makeStyles(colors) pattern.
2026-09-07 21:33:23 +02:00
admin f700000e87 fix(mobile): dark mode + nested-scroll fix in pet creation, invalidate pets.list after create
- PetCreateForm.tsx and onboarding/pet.tsx used the static light-only
  colors/typography tokens instead of useTheme() — pet creation stayed
  light even in dark mode.
- onboarding/pet.tsx wrapped its steps in a plain ScrollView; the breed
  OptionPicker nests its own vertical ScrollView, and two same-axis
  ScrollViews swallow the inner one's scroll gesture on Android even
  with nestedScrollEnabled. Switched the outer container to a FlatList
  (empty data + ListHeaderComponent), matching explore.tsx's already
  working fix for the same component.
- pets.create's mutation never invalidated trpc.pets.list, so
  ActivePetContext kept seeing zero pets after the first pet was
  created — OnboardingRedirect then bounced the user straight back to
  /onboarding/pet after the avatar step, with only an app restart
  breaking the loop. Added the missing invalidateQueries call.
2026-09-07 21:16:31 +02:00
admin c94df5fc6b fix(mobile): sign-up stuck on "missing_requirements" — no way to create an account
New sign-ups got stuck after entering the email verification code:
Clerk's status stayed on "missing_requirements" (surfaced via the
generic auth.signUpIncompleteError as "Sign-up incomplete") instead of
"complete", with no way to proceed. Checked this Clerk instance's
public /v1/environment config directly: first_name and last_name are
both required, and sign_up.legal_consent_enabled is true — web's
prebuilt <SignUp> component discovers and renders these automatically,
but this hand-built native form only ever collected email + password.

Added first/last name fields and a legal-consent checkbox (linking to
the actual Terms/Privacy pages), passed as firstName/lastName/
legalAccepted in the same signUp.password() call (Clerk's Futures API
accepts all three there — no separate .update() step needed). Submit
is disabled until all fields are filled and consent is checked.

This blocked 100% of new mobile sign-ups until fixed.
2026-09-07 21:03:54 +02:00
admin 4642d875de docs(mobile): correct Data Safety draft after Play Store rejection
Google rejected the first submission ("Violation of Play Console
Requirements" — apps in the "Health apps" category require an
organization account). The likely cause: this draft recommended
declaring pet weight/vet-visit/vaccination data under Data Safety's
"Health and fitness" category "as a precaution." That category is for
data about the person using the app, not their pet, and apparently
triggered Google's automated Health-app classification.

Reversed the recommendation (don't declare it there) and added a
section on checking the Play Store app category is "Social", not a
health/medical category — the rejection email names both as possible
causes.
2026-09-07 19:35:46 +02:00
admin 92d6495cc9 docs: update deploy workflow — NAS now git pull, not manual FTP
Confirmed 2026-09-07 while deploying the Child Safety Standards page:
/Dockers/PawFeed on the NAS is its own git checkout tracking the
self-hosted Gitea remote, kept up to date via git pull rather than the
manual FTP upload this file previously described. Documents the actual
deploy steps (ssh daniel@192.168.1.222 on the standard port, git pull,
then rolling-deploy.sh) so this doesn't need rediscovering next time.
2026-09-07 19:32:44 +02:00
admin 4758ce8d87 feat: add Child Safety Standards page for Google Play compliance
New public page at /kinderschutz — required by Google Play's Child
Safety Standards policy for apps with user-generated content/social
features (https://support.google.com/googleplay/android-developer/answer/14747720).
Registered as public + maintenance-exempt in proxy.ts, matching the
existing /impressum, /datenschutz, /nutzungsbedingungen pattern.

Content covers only mechanisms that actually exist in this codebase:
in-app reporting (ReportSheet + admin moderation review), a named
responsible contact (same identity as /impressum), and the German/EU
legal framework (StGB §184b/c, DSA, JuSchG) for law-enforcement
cooperation on confirmed CSAE content — no invented automated-
detection claims.

Cross-linked from the other legal pages' footers, the web /pets
footer, and the mobile app's My Pets legal-links section (new
pets.legalChildSafety i18n key, DE/EN).
2026-09-07 18:57:49 +02:00
admin 554b7cacdc docs(mobile): add Play Store feature graphic and description drafts
feature-graphic-1024x500.png — exact 1024x500, 24-bit PNG (no alpha,
per Play Console's spec), brand-matching gradient with the paw glyph
and wordmark.

beschreibung.md — short + full store listing description drafts based
on actual app features (posts, stories, milestones, health tracking
with consent, messaging, species/breed discovery, spider-hiding
preference), ready to paste into Play Console.
2026-09-07 18:18:24 +02:00
admin 919f02d773 docs(mobile): add Play Store icon and Data Safety draft
store-assets/play-store-icon-512.png — dedicated 512x512 RGBA copy of
the (now-fixed) app icon for the Play Console listing upload.

store-assets/play-console-data-safety.md — Data Safety form draft
based on an actual read of mobile/package.json's dependencies and the
relevant hooks/routers (push token flow, health-consent module), not
guessed: no payment/location/analytics SDK present in the mobile app,
account deletion exists but only via the web app (documented with the
URL Play Console needs).
2026-09-07 16:14:37 +02:00
admin de3a52f9b2 fix(mobile): fix app icon/splash rendering, prepare Play Store production build
Icon fix: android-icon-foreground/monochrome.png (and icon.png/
favicon.png/splash-icon.png) were the wide website wordmark logo
(paw + "PawFeed" text), with the actual paw glyph confined to a tiny
78x79px region on the far left of a 512x512 canvas. Android's adaptive
icon system only renders the center ~66% safe zone, so almost none of
the design was ever visible — explaining the "nearly all black" home
screen icon. Isolated the paw glyph via its orange pixel bounding box
and re-centered it properly on each target canvas (transparent for
foreground/monochrome/splash, solid background for icon.png/favicon).
monochrome.png is now a true white-alpha silhouette (Android's spec)
instead of sharp's tint() output, which produced gray instead of white.

Also removed android-icon-background.png — it was the same oversized
wordmark logo, redundant with (and overriding) the adaptiveIcon
backgroundColor that was already set to the same color.

Splash screen: expo-splash-screen was never installed despite
splash-icon.png existing in assets/ — app had no splash config at all,
which explains the light-gray placeholder/broken-image glyph seen on
launch (a generic fallback, not this app's own asset). Installed and
configured with the corrected splash-icon.png.

Play Store prep: added android.versionCode (required once
appVersionSource is "local" and unset until now) and made the
production build profile explicit about android.buildType: app-bundle
(required for Play Store; "preview" stays APK for direct install).
2026-09-07 15:29:52 +02:00
admin 768d0dda23 fix(mobile): dark mode for Messages, safe-area padding for input bars
Messages (conversation list + chat detail) used the static (light-only)
color tokens instead of useTheme() — same bug class as the earlier
auth-screen/comments/RepostCard fixes this session.

Also fixed: the comment and chat input rows sat flush against the
bottom edge with a flat 12px padding, no bottom safe-area inset. On
devices with Android's gesture nav bar this put the send button right
where the system back/home gesture also listens, making it error-prone
to tap ("in einem Schutzbereich sehr schwer anklickbar"). Both input
rows now pad by max(12, insets.bottom) instead of a flat 12px.
2026-09-07 05:42:52 +02:00
admin 04a193b8dd fix(mobile): fix EAS build failure — expo doctor schema/version errors
Build #4 failed at the expo doctor pre-build check EAS runs, with two
real issues:

- app.json's newArchEnabled key is no longer a valid Expo config field
  in SDK 57 (New Architecture is the only architecture now, so the
  opt-in toggle was removed) — the schema validator rejected it as an
  unknown property.
- expo-router was pinned to 5.1.11, an old-style version number
  predating Expo's SDK-aligned versioning — way behind the ~57.0.19
  expected for this SDK. expo-linking/expo-secure-store were a patch
  version behind too. Fixed via `npx expo install --fix` rather than
  guessing version numbers.

The expo-router bump changed tabBarIcon's expected color prop type
from `string` to RN's `ColorValue`; updated NotificationsTabIcon's
signature to match.

`npx expo-doctor` now reports 18/18 checks passed.
2026-09-06 21:47:18 +02:00
admin 6f83f47186 fix(mobile): fix Feed crash — hook called after conditional early return
FeedScreen's feedItems useMemo (interleaveTrending) sat after the
loading/error early returns instead of before them, violating the
Rules of Hooks: the loading-state render calls fewer hooks than the
loaded-state render, so React throws "Rendered fewer hooks than
expected" the moment the feed finishes loading — crashing the app on
every real device right after login. Moved the useMemo (and the plain
posts/trendingPosts derivations it depends on) above both early
returns so every render calls the same hooks in the same order.

Also add graphify-out to the root .easignore.
2026-09-06 21:39:28 +02:00
admin c04b69a11f fix(mobile): dark mode on auth screens + RepostCard, expand .easignore
Sign-in/sign-up and RepostCard used the static (light-only) color
tokens instead of useTheme() — in dark mode the login screen kept a
light background with light-theme-colored text baked in, and
RepostCard's text color was hardcoded independent of its (already
theme-aware) surrounding background, both landing on illegible
low-contrast text. Same bug class as earlier dark-mode fixes this
session, converted the same way (useTheme() + makeStyles(colors)).

Also add a root-level .easignore (EAS Build's archive root may resolve
above mobile/ for monorepo purposes) excluding backend/tooling
directories the mobile app never needs at build or runtime (.claude,
.impeccable, .planning, docker, prisma — the last is only a type-only
dependency via mobile's tRPC router import, erased before Metro
bundles anything).
2026-09-06 21:10:49 +02:00
admin 212cff942b chore(mobile): add .easignore to keep native folders out of EAS builds
An untracked local android/ folder (from an earlier expo run:android)
was inflating the build archive to 365MB and, more importantly, was
making EAS Build treat the project as "bare workflow" — building that
stale native folder as-is instead of regenerating it from app.json via
Continuous Native Generation. Deleted the folder locally and excluded
it (plus ios/, node_modules, IDE state) from future archives so a
stray prebuild output can't silently make app.json changes stop taking
effect.
2026-09-06 20:39:27 +02:00
admin 73158792d2 chore(mobile): commit google-services.json for EAS cloud builds
Was gitignored under the assumption it should be redownloaded per
clone, but a cloud EAS build clones from git and won't see a gitignored
file at all — the build would fail without it (app.json's
android.googleServicesFile references this path). Its contents (API
key, app/project IDs) aren't secret: Google restricts access by
package name and SHA fingerprint, not by hiding the file, same as most
public Firebase Android repos.
2026-09-06 20:25:45 +02:00
admin 4d1c566afa fix(mobile): correct dark-mode config, pin native builds to production
userInterfaceStyle was hardcoded to "light" in app.json — since the app
resolves its "Automatic" theme option via RN's useColorScheme(), which
Expo only wires up to the OS when userInterfaceStyle is "automatic",
the auto setting would have silently never followed the system theme
in a real native build (only worked in the dev client, which isn't
gated by this app.json field the same way).

Also pin the preview/production EAS build profiles' EXPO_PUBLIC_* env
vars explicitly in eas.json. .env is gitignored, so a cloud build has
no guarantee of seeing it (or seeing the right values) — this makes
the native build's API/Clerk/Supabase targets explicit and independent
of whatever's in the local .env at build time. Values are non-secret
(EXPO_PUBLIC_* is always inlined into the client bundle).
2026-09-06 20:20:28 +02:00
admin 82c9bb87b9 feat(mobile): add multi-image indicator to feed posts
Multi-photo posts gave no visual hint they were swipeable — a viewer
would only ever see the first image unless they already knew to swipe.
Adds a "1 / N" counter badge (top-right overlay) and a dot-page
indicator below the carousel, porting web's PostCard indicators.
2026-09-06 20:12:21 +02:00
admin 086b0e8900 docs(mobile): update found.md for notification/comments dark-mode fixes 2026-09-06 19:57:31 +02:00
admin 3d196b1528 fix(mobile): notification post link and actor-name link, comments dark mode
Notification taps for post-related types (REACTION/COMMENT/MENTION/
PAW_BACK) landed on a bare "no comments yet" screen with no sign of the
actual post. The comments screen now fetches the post via the existing
posts.getById and shows it (image/caption/header) via the shared
PostCard above the comment list.

The actor's name in each notification row is now its own tappable text
run that links to their profile, separate from tapping the rest of the
row (which still opens the notification's target) — ported from web's
notifications page, which does the same split between a Link and plain
text.

Also fixed: the comments screen used the static (light-only) color
tokens throughout, so embedding the theme-aware PostCard produced
near-invisible light text on its own light background in dark mode.
Converted the screen to useTheme() like the rest of the dark-mode-
converted screens.
2026-09-06 19:56:48 +02:00
admin 73ea97ac16 fix(mobile): notification separators/navigation, own-post delete option
Notifications: add a visible hairline separator between rows and make
each row tappable — it marks read and navigates to the relevant post
(comments screen) or pet profile, porting web's getHref()/getPostId()
routing logic.

Feed: the "..." menu on a post now opens a delete confirmation instead
of the report sheet when the post belongs to the currently active pet;
report sheet stays unchanged for posts from other pets. Reuses the
pre-existing posts.delete mutation, no backend changes needed.
2026-09-06 19:39:52 +02:00
admin 6b01046ded feat(mobile): mix trending posts into the Feed, update app icon assets
- explore.getTrending posts are now interleaved into the chronological
  Feed at semi-random intervals (src/lib/interleave-trending.ts),
  marked with a small "Trending" badge on PostCard — a lightweight
  stand-in for web's separate Explore "Trending" tab, which mobile
  wasn't going to get as its own screen. No backend change: reuses the
  existing explore.getTrending procedure as-is.
- update app icon / splash / favicon / Android adaptive-icon assets
  (user-provided)
- README: correct the now-stale Dark Mode "not yet converted" list
  (Explore/Notifications/pet profile/health were converted in the
  found.md batch) and document the report/date-format/pinch-zoom/
  legal-links fixes
2026-09-06 19:12:39 +02:00
admin 4a35fce20b fix(mobile): found.md batch — reports, dark mode, health form fixes
- new report feature: a "..." button on every post opens a reason-picker
  sheet (reports.create), matching web's ReportSheet reasons/copy
- pet profile, edit, followers/following, and the whole health screen
  (incl. consent gate) converted to the makeStyles(colors) dark-mode
  pattern
- fixed the invisible back button on every pushed (app)/_layout.tsx
  screen: headerTintColor was never set, so the native-stack default
  back chevron kept its platform tint instead of the theme color —
  black-on-black in dark mode looked like a missing button entirely
- health forms (weight/vet visit/vaccine) now take dates as DD-MM-YYYY
  instead of the backend's raw YYYY-MM-DD, converting internally
  (src/lib/date-format.ts); invalid dates now show an error instead of
  the mutation silently failing with no onError handler at all — this,
  not persistence, was the actual "Gesundheitsdaten werden nicht
  gespeichert" bug
- pinch-to-zoom on the full-screen image viewer via a plain
  PanResponder (no new native dependency)
- Pets tab: language switcher now uses flag emoji (🇩🇪/🇬🇧/🌐), and a
  new footer section links Impressum/Datenschutz/Nutzungsbedingungen
  plus the installed app version

All live-verified against the deployed backend except pinch-zoom
(two-finger gestures aren't simulatable over adb).
2026-09-06 18:55:12 +02:00
admin 462f295caa feat(mobile): add German/English i18n across the whole app
- i18next + react-i18next + expo-localization: device-locale detection,
  an MMKV-persisted DE/EN/Automatisch override (mirrors web's cookie-only
  locale, no backend field needed), and a language switcher on the Pets
  tab next to the theme toggle
- every screen and shared component converted from hardcoded German
  strings to translation keys; de.json/en.json kept in exact key-parity
  (218 keys each, verified programmatically)
- backend: src/trpc/init.ts now accepts an x-locale header as a fallback
  locale source (cookie still wins, web unaffected) since mobile has no
  cookie jar to set NEXT_LOCALE in; mobile's tRPC client sends the
  current language on every request
- fixes a latent bug: species/breed pickers were hardcoded to locale
  "de" while every other pet query resolved names via ctx.locale's
  default (English, since mobile never sent a locale cookie) — both now
  use the same current-language value
- expo-localization is a new native module (config plugin) and needs a
  native rebuild to actually link; deviceLocale() falls back to English
  instead of crashing when it isn't linked yet, so the app stays usable
  before that rebuild happens

Needs a NAS deploy (src/trpc/init.ts is shared backend code) before the
x-locale fallback and the species/breed locale fix take effect for mobile.
2026-09-06 17:31:41 +02:00
admin 0c6421c8de fix(mobile): dark mode on Explore/Notifications, breed dropdown overlay
- Explore and Notifications tabs now read colors from ThemeContext
  instead of the static light-only tokens
- OptionPicker's option list is position:absolute so it overlays
  following content instead of pushing it down, with zIndex on the
  component root (and FlatList's ListHeaderComponentStyle on Explore)
  so it actually paints above sibling content instead of underneath it
- check off found.md's resolved items, record the three newly reported ones
2026-09-06 16:30:02 +02:00
admin 0408be2063 feat(mobile): add onboarding flow, dark mode, and bugfixes
- 5-step onboarding (guidelines, upload consent, spider opt-in, pet
  creation, avatar) that gates first launch until a pet exists
- Add/delete pet flows on the Pets tab, with a shared OptionPicker
  (ScrollView-based, not FlatList, to avoid nested-VirtualizedList
  warnings inside onboarding's outer ScrollView)
- App-wide light/dark/auto theme via ThemeContext, synced with the
  existing owner.getThemePreference/setThemePreference backend
  procedures; core navigation chrome, Feed, Pets tab, and shared
  primitives (Button, TextField, Card, PetAvatar, PostCard, StoryTray)
  converted to the makeStyles(colors) pattern
- found.md fixes: safe-area insets on image/story viewers so controls
  clear the status bar, auto-mark-all-read on the notifications tab,
  and an Explore species/breed filter
2026-09-06 16:14:44 +02:00
adminandClaude Sonnet 5 330cfdeac2 feat(mobile): add sign-up screen
sign-in.tsx only ever covered login (per its own comment "sign-up screens
are follow-up work"). Adds the other half: email/password sign-up using
Clerk's Futures API (signUp.password() -> verifications.sendEmailCode()/
verifyEmailCode() -> finalize()), mirroring sign-in.tsx's two-step
credentials/verify shape. No invite-code step, since INVITE_REQUIRED is
globally off on the backend since launch.

Verified live on the Android emulator: real Clerk validation surfaces
correctly (breached-password rejection), and a valid submission correctly
sends a verification email and transitions to the code-entry step.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:49:13 +02:00
adminandClaude Sonnet 5 a890904b6c docs(mobile): document the full push-notification setup and its gotchas
Push notifications went from "wired but not deliverable" to fully working
end-to-end this session. Records the three separate one-time setup pieces
(EAS project id, FCM credentials baked at prebuild time, and the FCM V1
vs. Legacy service-account-key slot mixup that produced a confusing
"Unable to retrieve the FCM server key" error) so a future session doesn't
have to rediscover them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:28:03 +02:00
adminandClaude Sonnet 5 fcb5ae3eef chore(mobile): add eas.json build profile config
Minimal EAS Build config (development/preview/production profiles) —
needed by `eas credentials` to manage the FCM push key, no EAS Build
runs yet. Push notifications are now fully verified end-to-end: real
device token minted, registered with the backend, and a live push
delivered to the Android emulator's notification tray.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:27:13 +02:00
adminandClaude Sonnet 5 d3bf94799e fix: exclude mobile/ from the web app's TypeScript checking and Docker build
Next.js's production build type-checks the whole repo by tsconfig.json's
default include glob, which picked up mobile/'s .tsx files once the
Docker image's git checkout finally included mobile/ (first pull to
include it) — none of mobile's own dependencies (react-native, expo-router,
...) are installed in that container, so the build failed outright.
mobile/ is now excluded from tsconfig.json and .dockerignore; it's a
separate app with its own tsconfig/package.json and was never meant to be
type-checked or shipped as part of the web image.

Also completes the mobile EAS/FCM push setup (app.json's extra.eas.projectId
and googleServicesFile, google-services.json gitignored) and adds a 15s
timeout around getExpoPushTokenAsync so a device that can't reach FCM fails
visibly instead of hanging silently forever.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:07:27 +02:00
adminandClaude Sonnet 5 a3f19ff70f feat(mobile): add health tracking, milestones, messaging, and push registration
Health: consent gate (Art. 9 DSGVO) plus weight/vet-visit/vaccine log
sections, gated behind health.getConsentStatus like the web app.
Milestones: view a pet's milestone posts and create the 5 user-initiated
types with an optional photo. Messaging: chat detail/compose screen
(messages/[conversationId].tsx) polling while focused, reachable from the
conversations list and from a pet profile's new "Nachricht" entry point.
Push: usePushNotifications requests permission and registers the Expo
push token with owner.registerPushToken; real delivery still needs an EAS
project id (`eas init`), tracked in the README.

All four verified live on a real Android emulator: health CRUD (add/list/
delete a weight log), Health/Milestones/Nachricht entry points gated
correctly by own-pet vs. other-pet, and full chat history loading via an
existing conversation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 09:50:07 +02:00
adminandClaude Sonnet 5 0323e8d449 feat: add Expo push notification infrastructure
Owner.expoPushToken + owner.registerPushToken/clearPushToken, plus a
best-effort Expo push send wired into notify() alongside the existing
in-app Notification row. Missing/expired token or unreachable Expo push
service silently no-ops — push delivery must never break the underlying
action it's attached to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 09:49:02 +02:00
adminandClaude Sonnet 5 eda6d3b801 feat(mobile): add stories, video playback, and search
Story tray/creation/viewer with PawRing seen/unseen indicator, expo-video
playback for VIDEO posts (replacing the static placeholder), and a
pets/people/hashtags search screen reachable from the Explore tab header.
Extracts FollowButton from the pet-profile screen since search results
need the same follow/unfollow toggle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 08:53:07 +02:00
admin 8aa89e1011 docs(mobile): update README for repost creation 2026-09-05 15:44:05 +02:00
admin 925d121bb8 feat(mobile): add repost (Paw-Back) creation
PawBackButton toggles reposts.create/delete with an isReposted-backed
optimistic state, mirroring web's PawBackButton — replaces the static
repost count in PostCard's action row. RepostCard renders a REPOST
post as a read-only "Paw-Back von {name}" attribution wrapper around
the original post's pet header, image, and caption, ported from web's
RepostCard with no action row (matches web: only the original post is
reactable/commentable).
2026-09-05 15:43:48 +02:00
admin 257319e81e docs(mobile): update README for post creation and comments 2026-09-05 15:36:05 +02:00