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.
- 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
- 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.
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>
Post creation: gallery/camera picker (expo-image-picker) uploads each
image straight to Supabase Storage via a presigned PUT
(posts.getPresignedUrl + expo-file-system), then posts.create with the
resulting storage keys — reachable via a new "+" header button on the
Feed tab. No client-side blurhash (browser Canvas API, no RN
equivalent) or AI-disclosure/mention support yet, matching the rest of
mobile's plain-text captions.
Comments: a dedicated screen (posts/[postId]/comments) for reading,
posting, and deleting one's own comments, reachable by tapping the
comment icon on a PostCard. Ported from web's PostDetailDialog comment
panel, scoped down to just that panel since mobile's image full-view
already has its own route.
Moves the mobile app from a connectivity scaffold to a real Phase 1 app:
- Migrate off Expo Go onto a local custom dev client (expo-dev-client,
built via expo prebuild + expo run:android against the local Android
SDK — no EAS account needed). Needed because react-native-mmkv requires
native code Expo Go doesn't ship.
- Persisted, MMKV-backed TanStack Query cache (PersistQueryClientProvider)
plus expo-image, so a relaunch renders the last-known feed/pets/
notifications instantly instead of a blank screen while refetching.
- ActivePetContext: every pet-scoped procedure requires an explicit petId
server-side (no server-side "current pet"), ported from web's
ActivePetContext, MMKV-backed instead of localStorage.
- Bottom Tabs (Feed/Explore/Notifications/Pets) mirroring the web app's
actual mobile nav, with Messages as a header button rather than a tab
(matches web). Feed, PostCard, PawButton reactions, pet discovery grid,
notifications list, and a conversations list are all wired to the real
backend and verified against the live database.
- Design tokens/components extended with PostCard/PawButton/PetAvatar/
PetIdentityBadges, all styled from the existing src/theme/tokens.ts.
- Fixed a react/react-dom version mismatch surfaced along the way, and
handle Clerk's needs_client_trust (Device Trust) sign-in status with an
email-code step.
Verified end-to-end in the Android emulator against pawfeed.org: feed
scrolls and paginates with real posts/images, paw reactions toggle
optimistically and persist, pet switching updates every screen, and
notifications/explore show live data.
Connectivity + auth scaffold only: Expo Router, Clerk session auth via
expo-secure-store, and a type-only tRPC AppRouter import from the web
app's router — no backend changes needed. See mobile/README.md.