← Portal
Tech audit · Mobile Readiness 2026-05-19

Mobile Readiness

14 findings
4
Kritikus
4
Magas
4
Közepes
2
Alacsony

Below are all 14 findings recorded in this dimension during the audit, sorted by severity then launch priority. Each card carries the full anatomy: severity / priority / effort, code location, evidence, technical issue, business impact, plain-language explanation, fix steps, related dimensions, and references.

10

Findings — Mobile Readiness

Kritikus Launch előtt S MOB-001 · mobile-readiness
No Web App Manifest -- PWA install and baseline App Store icon requirements unmet
Kód-hely
public/ <directory>
Evidence
ls public/ returns only sw.js. No manifest link in __root.tsx head links array (links array contains only stylesheet, preconnect, and Google Fonts). No icon-*.png files in public/.
A probléma

There is no manifest.json or manifest.webmanifest in the public/ directory. The only file in public/ is sw.js. Without a manifest, the app cannot be installable via browser Add to Home Screen (PWA Path A), and there are no declared icons in any required size (192px, 512px, 1024px). For the wrapper path (Path B) the manifest is the canonical source of icons, name, short_name, and start_url used by Capacitor tooling to generate native splash screens and app icons.

Üzleti hatás

App Store submission requires icons at 1024x1024 (Apple) and 512x512 (Google). Play Store also requires a feature graphic. Without a manifest these must be manually injected into the native project, which is error-prone. Lighthouse PWA installability check will score 0.

Magyarázat

Right now the app has no digital identity card that tells a phone what it is when someone saves it to their home screen. This card is the foundation for making the app feel native -- it carries the app name, the icon shown on the phone home screen, and the colour shown in the status bar. Without it, users who try to add the app to their phone get a generic browser icon and a blank title. It also means the tools that package the app for the App Store and Play Store have no icon assets to work with -- those must be provided before any submission can proceed.

Javaslat

Path A/B: Create public/manifest.webmanifest with name, short_name, description, start_url, display:standalone, orientation:portrait, theme_color, background_color, and icons array covering 192x192, 512x512 masked, and 1024x1024. Add <link rel=manifest href=/manifest.webmanifest> in __root.tsx. Export icon assets from the existing design. Estimated effort: S (1 day including icon export). Path C: icons are generated directly in the native project; manifest not required but icons still must be produced.

Becsült munka

S — under ½ day

Deployment path

{'pwa': 'blocking', 'wrapper': 'blocking', 'native_rewrite': 'not_applicable'}

Kritikus Launch előtt L MOB-003 · mobile-readiness
Lovable OAuth redirect flow will break inside iOS WKWebView (Capacitor wrapper)
Kód-hely
src/integrations/lovable/index.ts:15-16 | src/routes/auth.tsx:84-85 | src/components/AuthGateOverlay.tsx:128-129
Evidence
src/integrations/lovable/index.ts line 22: if (result.redirected) return result -- no deep-link interception. src/routes/auth.tsx line 85: redirect_uri: window.location.origin -- no custom URL scheme. No capacitor.config.ts or capacitor.config.json present anywhere in repo.
A probléma

The OAuth flow uses @lovable.dev/cloud-auth-js which resolves to a redirect-based OAuth dance (result.redirected is checked at line 22). The redirect_uri is set to window.location.origin. iOS WKWebView (used by Capacitor) does not handle arbitrary URL redirects back to the app without Universal Links or a custom URL scheme configured. The Lovable AI Gateway OAuth result may open an external browser but the token callback to window.location.origin will fail unless Capacitor deep-link interception is wired. The result.redirected branch returns early without calling supabase.auth.setSession, meaning partial OAuth flows may leave the user in a broken state on native.

Üzleti hatás

If OAuth sign-in is broken, the significant portion of users who sign in with Google (typically 40-60% on mobile) cannot log in. App Store and Play Store reviewers test login flows; a broken sign-in results in automatic rejection.

Magyarázat

When the app is packaged for the App Store or Play Store, signing in with Google or Apple works differently than in a regular browser. The phone needs special instructions telling it to bring the user back to the app after they finish signing in. Right now those instructions do not exist, which means OAuth sign-in (Google, Apple, Microsoft) would silently fail for anyone using the native app. Setting this up requires about a week of native configuration work and testing.

Javaslat

Path B (Capacitor): Install @capacitor/browser and implement the Capacitor OAuth deep-link pattern. Configure a custom URL scheme (e.g. com.soni.app) in capacitor.config.ts. Update redirect_uri to use the custom scheme. Handle the URL callback in App.addListener('appUrlOpen'). Confirm with Lovable whether @lovable.dev/cloud-auth-js exposes a PKCE or custom-scheme mode. Estimated effort: L (5-10 days including Apple developer config, Android intent-filter, testing). Path C: Use a native OAuth library; the web bridge disappears entirely.

Becsült munka

L — 1–2 weeks

Deployment path

{'pwa': 'not_applicable', 'wrapper': 'blocking', 'native_rewrite': 'blocking'}

Kritikus Launch előtt M MOB-004 · mobile-readiness
No in-app account deletion -- Apple 5.1.1(v) and Google Play 2024 policy violation
Kód-hely
src/lib/full-reset.ts | src/routes/settings.tsx:585-617
Evidence
src/lib/full-reset.ts: 34-table wipe plus profile field nullification, but no supabase.auth.admin.deleteUser call and no supabase.auth.deleteUser call. No 'Delete account' translation key found in en.json. src/routes/settings.tsx lines 585-617: only 'Minden adat torlese' (delete all data) button visible in the danger zone.
A probléma

The Settings screen exposes a full data reset button (fullResetUserData) that deletes all user-generated rows from 34 tables and clears localStorage. However this function preserves the auth account itself (the profiles row keeps the user_id, and supabase.auth.deleteUser is never called). There is no UI button that deletes the Supabase auth account. Apple App Store guideline 5.1.1(v) and Google Play Account Deletion Policy (effective 2024) both require that apps allow users to request deletion of their account and associated data from within the app. A reset-data button does not satisfy either requirement.

Üzleti hatás

Automatic App Store and Play Store rejection until resolved. Also a GDPR right-to-erasure gap (cross-ref LEG findings).

Magyarázat

Both Apple and Google now require every app to have a button inside the app that lets a user permanently delete their account -- not just clear their data, but close the account entirely. Right now the app has a reset button that wipes the health data but leaves the account itself in place. That is not enough for Apple or Google to approve the app. Without adding a real delete-account button that removes the account from the system, the app will be rejected at review. This is a firm rejection criterion, not a suggestion.

Javaslat
  1. show a confirmation dialog warning the action is irreversible, (.
  2. call a server function that uses the Supabase service-role admin client to call supabase.auth.admin.deleteUser(userId) after running fullResetUserData, (.
  3. sign the user out locally. Server side already has SUPABASE_SERVICE_ROLE_KEY access in client.server.ts. Estimated effort: M (2-3 days for UI plus server function plus GDPR consideration).
Becsült munka

M — 1–3 days

Deployment path

{'pwa': 'not_applicable', 'wrapper': 'blocking', 'native_rewrite': 'blocking'}

Kapcsolódó dimenziók
Kritikus Launch előtt M MOB-005 · mobile-readiness
Privacy policy is plain text with no URL -- Apple 5.1.1 and Play Store policy violation
Kód-hely
src/i18n/locales/en.json:252 | src/routes/auth.tsx:265-267
Evidence
Grep for https://.*privacy and https://.*terms returns no matches across all src/ files. src/i18n/locales/en.json line 252: auth.legal is a plain text string with no URL. No anchor tag or Link component wrapping the legal text in auth.tsx or AuthGateOverlay.tsx.
A probléma

The auth screen displays the text 'By continuing you agree to our Terms and Privacy Policy.' (translation key auth.legal). There is no hyperlink to an actual Privacy Policy URL or Terms of Service URL anywhere in the codebase. Apple App Store guideline 5.1.1 requires a clearly visible, tappable privacy policy URL. The App Store Connect metadata submission form also requires a Privacy Policy URL before the app can be submitted. Google Play Data Safety also requires a linked policy.

Üzleti hatás

Hard block on App Store Connect submission form and Play Store listing creation. Also a GDPR requirement -- data processing disclosure must be accessible before data collection begins.

Magyarázat

The sign-in screen tells users they agree to the privacy policy, but there is no actual link to a privacy policy document -- just a sentence of plain text. Apple requires every app to include a tappable link to a real privacy policy before it will approve the app for the store, and this must be submitted as part of the app listing. Google Play requires the same. Without a published, linked privacy policy the app cannot be submitted to either store.

Javaslat

Path A/B/C: Publish a privacy policy and terms of service at stable URLs (e.g. soni.app/privacy and soni.app/terms). Update the auth.legal translation key to include hyperlinks to both documents. The privacy policy must cover all data categories collected (health data, biometrics, cycle logs, AI coaching conversations). Estimated effort: M (2-3 days for policy drafting plus linking; legal review time is external). This is also required for App Store Connect metadata even if the link is external to the app.

Becsült munka

M — 1–3 days

Deployment path

{'pwa': 'blocking', 'wrapper': 'blocking', 'native_rewrite': 'blocking'}

Kapcsolódó dimenziók
Magas Launch előtt M MOB-007 · mobile-readiness
Voice coach uses MediaRecorder with webm MIME priority -- breaks on iOS Safari and WKWebView
Kód-hely
src/components/CoachPage.tsx:862-868 | src/components/CoachChatSheet.tsx:543-548
Evidence
CoachPage.tsx lines 862-868: candidates = ['audio/webm;codecs=opus', 'audio/webm', 'audio/mp4;codecs=mp4a.40.2', 'audio/mp4']. CoachChatSheet.tsx lines 543-544: same priority order. No iOS UserAgent branch or platform detection before MediaRecorder construction.
A probléma

The voice coach uses navigator.mediaDevices.getUserMedia with audio, then creates a MediaRecorder with mime-type candidates prioritised as audio/webm;codecs=opus then audio/webm then audio/mp4;codecs=mp4a.40.2. iOS Safari and WKWebView (Capacitor) do not support audio/webm. MediaRecorder.isTypeSupported('audio/webm') returns false on iOS. The fallback chain reaches audio/mp4 which is correct for iOS, but the MediaRecorder constructor will throw a NotSupportedError when attempted with a webm type before the fallback is reached. The existing guard at line 846 (typeof MediaRecorder === 'undefined') will not prevent this failure on iOS 17+ which does have MediaRecorder for mp4.

Üzleti hatás

Voice coach is a premium differentiating feature. Silent failure on all iOS devices would surface immediately in App Store reviews.

Magyarázat

The app includes a voice coaching feature where users speak to their coach using the phone microphone. The audio recording technology used works well on Android and desktop browsers, but iPhones handle audio in a different format that requires a different approach. Without a fix, the voice coach button would silently fail or show an error on every iPhone -- which is a meaningful part of the target audience for a premium health app.

Javaslat

Path B (Capacitor): Use @capacitor/voice-recorder or @capacitor-community/speech-recognition which handle iOS audio encoding natively. For the web path, reorder MIME candidates to try audio/mp4;codecs=mp4a.40.2 first when on iOS (detect via navigator.userAgent or MediaRecorder.isTypeSupported check) and add an explicit try-catch around the MediaRecorder constructor with an iOS-specific fallback message. Estimated effort: M (2-3 days for Capacitor plugin integration plus cross-platform testing). Path A (PWA): same MIME reorder fix as wrapper.

Becsült munka

M — 1–3 days

Deployment path

{'pwa': 'blocking', 'wrapper': 'blocking', 'native_rewrite': 'relevant'}

Magas Első sprint M MOB-002 · mobile-readiness
Service worker deletes all caches on every update -- no offline support
Kód-hely
public/sw.js:9
Evidence
public/sw.js lines 7-14: activate handler runs caches.delete on every key unconditionally. No fetch event handler or cache-first strategy present. SW_VERSION is a static string literal '2026-05-07-skip-to-app'.
A probléma

The service worker at public/sw.js unconditionally deletes all caches on every activate event (line 9: Promise.all(keys.map((k) => caches.delete(k)))). This design means the app has zero offline capability: all assets and API responses are fetched fresh on every page load. On a mobile device with a poor or absent connection, the app will show a blank screen or browser error page. The SW_VERSION is also a hand-edited string constant rather than a build-hash, meaning version bumps require a manual source edit.

Üzleti hatás

Users in low-connectivity environments (gyms, basements, travel) will experience full app failure. For a PWA path, Lighthouse will penalise absence of an offline fallback. For wrapper path, offline resilience is a standard user expectation for a daily-use health app.

Magyarázat

The app uses a background script called a service worker that is typically used to make an app work even when the phone has no internet connection. Right now, that script is wired to throw away everything it has saved every time it updates -- which means if a user opens the app on a patchy mobile signal, they will see a blank screen or an error instead of even a basic cached version of the app. For a health and longevity product where users track their morning check-in and meals daily, this is a meaningful reliability gap.

Javaslat

Path A/B: Add a cache-first strategy for the app shell (HTML, CSS, JS) using a Workbox precache or a minimal custom fetch handler. Only clear old versioned caches, not all caches. Derive SW_VERSION from a build hash injected at build time via Vite plugin. Estimated effort: M (2-3 days for Workbox integration plus testing). Path C: Native frameworks handle caching natively; this is not applicable.

Becsült munka

M — 1–3 days

Deployment path

{'pwa': 'blocking', 'wrapper': 'relevant', 'native_rewrite': 'not_applicable'}

Magas Első sprint S Remix-context MOB-006 · mobile-readiness
VAPID public key hard-coded in client bundle -- impedes key rotation
Kód-hely
src/lib/push-client.ts:3-4
Evidence
src/lib/push-client.ts line 4: const VAPID_PUBLIC_KEY = 'BK3ijK1TsC...REDACTED' (87-character base64url literal). src/server/push-admin.server.ts line 7: process.env.VAPID_PUBLIC_KEY (correct env-var pattern).
A probléma

The VAPID public key is hard-coded as a string literal in src/lib/push-client.ts lines 3-4. While VAPID public keys are intended to be distributed to browser clients, hard-coding the value in source means rotating the key pair requires a code change and redeploy rather than an env-var update. For a native app in the App Store, a code change triggers a new review cycle. The server-side correctly reads VAPID_PUBLIC_KEY from process.env (push-admin.server.ts line 7).

Üzleti hatás

Operational brittleness on key rotation. Inconsistency with server-side env-var pattern creates confusion.

Magyarázat

The code that handles push notifications has one of its keys written directly into the app code rather than read from a secure configuration. This means if the keys ever need to be changed -- for example after a security incident -- the development team has to update the code and re-deploy the app rather than simply rotating a configuration value. For a native app that goes through App Store review, a code change triggers a new review cycle that takes days.

Javaslat

Move the VAPID public key to a Vite build-time env var: VITE_VAPID_PUBLIC_KEY. Reference it in push-client.ts as import.meta.env.VITE_VAPID_PUBLIC_KEY. This keeps the key out of source and allows rotation without code changes. S effort: under a day.

Becsült munka

S — under ½ day

Deployment path

{'pwa': 'relevant', 'wrapper': 'relevant', 'native_rewrite': 'not_applicable'}

Kapcsolódó dimenziók
Magas Első sprint M MOB-008 · mobile-readiness
Web-push (VAPID) notifications do not work in native Capacitor wrapper -- APNs and FCM setup required
Kód-hely
src/lib/push-client.ts | src/server/push-admin.server.ts | public/sw.js
Evidence
src/lib/push-client.ts: uses navigator.serviceWorker plus PushManager -- web-push only. public/sw.js push handler: standard web-push format. src/server/push-admin.server.ts uses web-push npm package with VAPID keys. No @capacitor/push-notifications in package.json. No GoogleService-Info.plist or google-services.json in the repo.
A probléma

The app implements web-push notifications using the VAPID protocol (web-push npm package, PushManager.subscribe). Web Push on iOS requires iOS 16.4+ and the app to be installed as a PWA from the home screen. For the Capacitor wrapper path, web-push browser endpoints stored in push_subscriptions will not work for the native app shell; native APNs (iOS) and FCM (Android) must be used instead, requiring @capacitor/push-notifications and Firebase or APNs setup that does not currently exist. The current push infrastructure is 100% web-push only with no native fallback.

Üzleti hatás

Notification-based re-engagement is a key retention driver for a daily-use health product. iOS users represent 50-70% of the premium health app market. If they do not receive push notifications, daily active usage and retention will be lower.

Magyarázat

Push notifications -- the reminders that pop up even when the app is closed -- work differently on iPhones compared to Android and desktop. The app currently uses a web-only notification system. On iPhone, this only works if the user has saved the app to their home screen, and only on iOS 16.4 or later. When the app is packaged for the App Store, the web-based notification system stops working entirely and must be replaced with Apple own notification service. This is a planned piece of integration work that will take 2-3 days to set up.

Javaslat

Path A (PWA): Document the iOS 16.4+ PWA install requirement in onboarding. Add an iOS PWA install prompt at a natural moment. Path B (Capacitor): Integrate @capacitor/push-notifications. Set up Firebase Cloud Messaging (FCM handles both Android push and relays to APNs). Update push-admin.server.ts to use FCM HTTP v1 API for native subscribers and retain web-push for browser subscribers. Add device_type discriminator to push_subscriptions table. Estimated effort: M (3 days for Capacitor plugin plus FCM and APNs provisioning plus server dispatch update). Path C: same FCM and APNs setup.

Becsült munka

M — 1–3 days

Deployment path

{'pwa': 'relevant', 'wrapper': 'blocking', 'native_rewrite': 'blocking'}

Kapcsolódó dimenziók
Közepes Launch előtt S MOB-010 · mobile-readiness
No age rating assessment -- health and mental-health content likely requires 12+ or 17+ rating
Kód-hely
Repo-wide (no single file)
Evidence
src/integrations/supabase/types.ts: cycle_logs, cycle_settings, safety_events tables present. src/server/_shared/safety-check.ts and mental-health-risk.ts handle mental health signals including emergency classification. No date_of_birth, age_gate, or minimum_age field in profiles table. No age verification in auth.tsx or onboarding flow.
A probléma

The app collects cycle logs (menstrual data, biological_sex), biometrics, mental health signals via safety_events (including mental_health and emergency classifications), and generates AI health coaching. Apple App Store requires every app to receive an age rating. Apps handling health data and AI-generated advice relevant to mental health or body composition typically receive 12+ or 17+. No age gate, no minimum age declaration in onboarding, and no age-appropriate design review has been performed. Google Play requires IARC Content Rating Questionnaire completion. The lack of any minimum-age UX means minors can sign up, triggering GDPR Article 8 obligations in most EU member states (parental consent required for users under 16).

Üzleti hatás

Incorrect age rating leads to App Store rejection or post-launch removal. Missing age gate triggers GDPR Article 8 compliance gap for EU users.

Magyarázat

Apple and Google require every app to declare who it is for in terms of age, similar to how a film gets a rating. This app deals with sensitive personal health topics including body image, menstrual cycles, and mental wellbeing, which means it will likely receive a 12 or 17 and over rating. There is currently no check in the sign-up process to ask how old the user is, which creates a legal issue in Europe where apps must have parental consent before collecting personal data from children under 16. This needs to be assessed before App Store submission.

Javaslat

Path A/B/C: Complete the App Store Connect age rating questionnaire honestly (likely 12+ for health and fitness plus AI content; potentially 17+ for mental health themes). Add a date-of-birth field during onboarding and block users under 16 in EU jurisdictions or require parental consent flow. Document the decision and retain legal review evidence. Estimated effort: S (1 day for UX; legal review is external).

Becsült munka

S — under ½ day

Deployment path

{'pwa': 'not_applicable', 'wrapper': 'blocking', 'native_rewrite': 'blocking'}

Kapcsolódó dimenziók
Közepes Első sprint S MOB-009 · mobile-readiness
localStorage session storage may be cleared by iOS ITP -- unexpected logouts on mobile
Kód-hely
src/integrations/supabase/client.ts:23
Evidence
src/integrations/supabase/client.ts line 23: storage: typeof window !== 'undefined' ? localStorage : undefined. useAuth.tsx has a 5000ms session polling fallback but no secure native storage fallback. No @capacitor/preferences in package.json.
A probléma

Supabase auth is configured with storage: localStorage (line 23). iOS WKWebView restricts localStorage under ITP (Intelligent Tracking Prevention): storage quota may be reduced and the session can be cleared when the user clears Safari website data, logging the user out silently. The useAuth hook includes a 5-second session recovery polling fallback which partially mitigates this, but a Capacitor-specific secure session store (@capacitor/preferences) would be more robust for the native wrapper path.

Üzleti hatás

Unexpected logouts on mobile are a top-3 cause of negative App Store reviews for health and productivity apps.

Magyarázat

The app stores the user sign-in session in the browser local memory. On iPhones running inside the app packaging layer, this memory can be cleared without warning under certain privacy settings -- logging the user out unexpectedly. For a daily-use health app where users build streaks and rely on continuity, unexpected logouts are a friction point that damages trust.

Javaslat

Path B (Capacitor): Replace the localStorage storage adapter with a custom Capacitor Preferences adapter. Supabase JS supports a custom storage option (any object implementing getItem/setItem/removeItem). Install @capacitor/preferences and create a 20-line adapter. Estimated effort: S (under 1 day). Path A (PWA): Current localStorage behaviour is acceptable; add a UI nudge to avoid private browsing mode.

Becsült munka

S — under ½ day

Deployment path

{'pwa': 'relevant', 'wrapper': 'relevant', 'native_rewrite': 'not_applicable'}

Közepes Első sprint M MOB-011 · mobile-readiness
No Universal Links or Android App Links -- notification taps open browser instead of app
Kód-hely
Repo-wide (no single file)
Evidence
ls public/ shows only sw.js -- no .well-known/ directory. public/sw.js line 37: const url = event.notification.data.url || '/'. No deep-link route registration in vite.config.ts or wrangler.jsonc.
A probléma

There are no Universal Link (iOS) or Android App Link configuration files -- no apple-app-site-association (AASA) and no assetlinks.json under .well-known/. The push notification click handler in sw.js navigates to event.notification.data.url (line 37). In a native wrapper context, this needs to resolve to the native app, not the browser. Without Universal and App Links, push notification taps open the system browser instead of the app. Shared links (weekly report, meal summary) sent via SMS or email will also not open the native app when installed.

Üzleti hatás

Every push notification tap that opens a browser instead of the app is a friction event. Users who experience this will uninstall. App Store reviewers test notification tap behaviour.

Magyarázat

When a user gets a push notification on their phone and taps it, the phone needs to know to open the SO:NI app rather than a browser window. Similarly, if someone shares a link from the app in a text message, tapping that link should open the app directly. This configuration does not yet exist, which means push notification taps and any shared links would open the phone default browser instead -- breaking the seamless native experience users expect from an App Store app.

Javaslat

Path B (Capacitor): Serve apple-app-site-association and assetlinks.json from the Cloudflare Worker at /.well-known/. Configure the Capacitor app bundle ID consistently across both files. Register @capacitor/app appUrlOpen listener to handle incoming deep links. Estimated effort: M (1-2 days for file creation plus Worker routing plus Capacitor listener). Path C: Same files required plus native URL scheme registration.

Becsült munka

M — 1–3 days

Deployment path

{'pwa': 'not_applicable', 'wrapper': 'relevant', 'native_rewrite': 'relevant'}

Közepes Backlog M MOB-012 · mobile-readiness
Framer Motion used across 105 files -- animation jank risk on low-end Android
Kód-hely
src/ <repo-wide>
Evidence
Grep for framer-motion import across src/ returns 105 files. 669 occurrences of motion. or AnimatePresence. package.json: framer-motion ^12.38.0. vite.config.ts codeSplittingOptions only excludes root route.
A probléma

Framer Motion 12.38.0 is used across 105 files with 669 animation-related occurrences. On low-end Android devices (2-3GB RAM, MediaTek or Snapdragon 4-series chips -- common in EU markets Hungary, Germany, Italy) Framer Motion spring animations can cause visible frame drops below 60fps, particularly during route transitions and the heavy dashboard featuring DnD-kit sortable, multiple Recharts instances, and animated micro-practice overlays. The bundle contribution of framer-motion is approximately 100-150KB gzipped, adding to cold-start time. The Vite config only exempts the root route from code splitting, meaning framer-motion is included in all route bundles.

Üzleti hatás

Poor animation performance on entry-level Android devices drives negative reviews and hurts Play Store ranking. EU market has significant affordable-Android penetration.

Magyarázat

The app uses a popular animation library throughout the interface to create smooth, polished transitions and movement. On high-end phones this works beautifully, but on more affordable Android phones that are common in the European markets SO:NI is targeting, these animations can make the interface feel sluggish. This is not a blocker for App Store approval, but it is the kind of thing that generates one-star reviews about the app being slow.

Javaslat

Path A/B: Audit which animations are essential vs cosmetic. Disable or simplify spring animations using prefers-reduced-motion media query. Use Framer Motion useReducedMotion hook to respect system accessibility settings. Replace route-level AnimatePresence transitions with CSS transitions (significantly cheaper). Estimated effort: M (2-3 days for audit plus selective reduction). Path C: native transitions are hardware-accelerated and this issue does not apply.

Becsült munka

M — 1–3 days

Deployment path

{'pwa': 'relevant', 'wrapper': 'relevant', 'native_rewrite': 'not_applicable'}

Alacsony Backlog L MOB-013 · mobile-readiness
Wearable data ingested via screenshot OCR only -- HealthKit and Health Connect not available
Kód-hely
src/lib/wearable-screenshot-api.ts | src/server/wearable-screenshot.ts
Evidence
src/lib/wearable-screenshot-api.ts: files are compressed and sent to AI for OCR via extractFromScreenshots. src/server/wearable-screenshot.ts: AI extracts ExtractedMetrics from image base64. No HealthKit or Health Connect capability declarations. No health-related Capacitor community plugin in package.json.
A probléma

Wearable fitness data (steps, HRV, recovery score, sleep hours) is ingested exclusively via screenshot OCR using the AI gateway. The app has no native HealthKit (iOS) or Health Connect (Android) integration. For a health and longevity app targeting the App Store and Play Store, users strongly expect seamless wearable data sync. This is not an App Store rejection criterion but it is a notable user expectation gap that will affect retention and ratings.

Üzleti hatás

Premium health apps all offer direct health platform integration. Absence of native health integration will be mentioned in App Store reviews and affects premium positioning.

Magyarázat

Currently the app reads fitness data from wearables by asking users to take a screenshot of their Oura ring or Garmin app and upload it, then the AI reads the numbers from the image. This is clever but it creates friction for daily use. When the app is available in the App Store, users will expect it to connect directly to their Apple Watch or health app. This is a longer-term integration rather than a launch requirement, but it should be on the roadmap.

Javaslat

Path B (Capacitor): Evaluate @capacitor-community/health-kit for iOS and @capacitor-community/health-connect for Android. Add HealthKit entitlement to the Apple developer account. The data model already supports the metrics (lifestyle_logs with wearable_source field). Estimated effort: L (1-2 weeks for iOS HealthKit plus Android Health Connect integration). This is a v2 milestone, not a launch requirement.

Becsült munka

L — 1–2 weeks

Deployment path

{'pwa': 'not_applicable', 'wrapper': 'relevant', 'native_rewrite': 'relevant'}

Alacsony Backlog S MOB-014 · mobile-readiness
Lovable preview-token guard shipped in production HTML -- dead code in native app build
Kód-hely
src/routes/__root.tsx:90-94 | src/lib/preserve-preview-url.ts
Evidence
src/routes/__root.tsx line 92: dangerouslySetInnerHTML injecting __lovable_token preservation script (~900 character minified inline JS). src/lib/preserve-preview-url.ts: assignPreservingLovablePreviewToken and startLovablePreviewTokenGuard functions imported in settings.tsx and __root.tsx.
A probléma

The RootShell component injects a large inline script that patches window.history.pushState, window.history.replaceState, and URL construction to preserve a Lovable preview token (__lovable_token) across navigation. This is Lovable platform scaffolding for their live-preview feature. In a production native app build, this token guard is dead code that adds ~1KB to every page render and monkey-patches the history API unnecessarily. Apple App Store guideline 4.0 (Design) mentions apps should not include non-functional development artefacts.

Üzleti hatás

Minor quality signal risk during App Store review. Slightly increases JS parse time on every page load. Not a blocking issue.

Magyarázat

The app contains a piece of setup code that was added by the Lovable development platform to help preview the app while building it. This code will still run when the app is in the App Store, even though it serves no purpose there. It is harmless but it is the equivalent of leaving scaffolding visible on a finished building -- it is a sign that the app has not been fully prepared for production.

Javaslat

Gate the preview-token script and preserve-preview-url imports behind import.meta.env.DEV or a VITE_LOVABLE_PREVIEW build flag. In production builds, exclude the script and the imports via Vite dead-code elimination. S effort: under a day. Coordinate with Lovable platform team to confirm the token mechanism is not required in production.

Becsült munka

S — under ½ day

Deployment path

{'pwa': 'not_applicable', 'wrapper': 'relevant', 'native_rewrite': 'not_applicable'}

AI Project Audit · Tech report · Mobile Readiness Charter v0.4 · 2026-05-19