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>
- 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>
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>
- 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).
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.
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).
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.
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).
- 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.
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>
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>
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>
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.
Fixes from user testing on a real device:
- Feed: replaced an invisible spacing-only separator with an actual
hairline divider between posts.
- Android launcher icon showed Expo's default placeholder (a blue arrow)
because the app icon and the Android adaptive-icon layers
(foreground/background/monochrome) are two separate asset sets — only
icon.png/favicon.png had been replaced. Added scripts/derive-adaptive-
icon.js to crop the paw glyph out of icon.png (detected by its marigold
color) and generate all three adaptive-icon layers plus the splash icon;
this is an explicit placeholder per user's own call, not final art.
New: full pet profile (app/(app)/pets/[petId]/), matching web's
src/app/(app)/pets/[petId]/page.tsx:
- View: identity, species, bio/adoption story, follower/following counts
(tappable → list screens), the pet's own posts below.
- Follow/unfollow with real initial state (follows.isFollowing) and
optimistic toggle — unlike feed reactions, this endpoint actually
exists, so no need to fake an initial state.
- Edit screen (name/nickname/bio/adoption story via pets.update) for the
owner's own pets.
- Tapping a pet (feed header, Explore card, Pets-tab row) now opens this
profile instead of nowhere; the Pets tab's active-pet switch is now a
separate checkmark control instead of overloading the whole row tap.
PostCard's post-shape prop is now structural rather than tied to
feed.getFeed's output type, since posts.byPetId selects `pet` via the
narrower petIdentitySelect (no isVerified/owner) — both need to satisfy
the same component.
Verified end-to-end on-device: feed separator visible, own-pet profile
shows a working Bearbeiten button whose form is correctly prefilled (a
stray edit was made to Bianca's nickname field by mistake during testing
and was discarded via back-navigation without saving — never sent to the
server), someone else's pet profile shows a working Follow/Unfollow
toggle, followers list navigates correctly, and the home-screen launcher
icon now shows the paw instead of the default Expo icon.
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.
- Add design tokens (colors, radii, typography) mirroring DESIGN.md's
"Spotlight Porch" system, plus Button/TextField/Card components built
on them. Restyle the sign-in and placeholder home screens to match.
- Load Inter via @expo-google-fonts/inter, gate rendering on fonts +
Clerk being ready instead of a blank screen.
- Pin react-dom to match react's version — Metro/Hermes hard-require
exact equality, and react-dom wasn't pinned anywhere before.
- Handle Clerk's `needs_client_trust` status (Device Trust, tied to the
dashboard's Native Applications API): send/verify an email code
before finalizing sign-in.
Verified end-to-end in the Android emulator against the live backend:
sign-in, device-trust code verification, and the home screen showing
real stats.getPublicStats 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.