Replaces the floating pill nav with persistent mobile chrome that
frames scrolling content the way iOS/Android native apps do.
New components:
- TopBar: brand left, contextual action right (Admin pill for admins,
bell for saved, Login button when logged out)
- BottomNav: 4-tab fixed nav (Search, Scan [elevated center FAB],
Saved, Profile). Saved/Profile disabled when logged out, tapping
opens LoginModal
- icons.jsx: 5 stroke-based SVG icons (Search, Scan, Bell, User, Cog)
plus Logo; replaces emoji in nav chrome
Behavior changes:
- App.jsx: tracks publicScreen ('home'|'scan'|'search') so BottomNav
can drive both top-level view + inner screen
- PublicView: screen state lifted to App via props (back-compat
defaults preserved so existing call sites don't break)
- App.css: old mobile .view-switcher block hidden (replaced by
BottomNav); .app padding bumped to clear the fixed bottom bar
Desktop (>768px) unchanged — existing centered pill nav still works,
new components hidden via display:none.
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause: html/body had no height/overflow constraint, so the
webview allowed rubber-band overscroll. .app used min-height: 100vh
which on iOS resolves to the larger viewport (behind URL bar), causing
layout to reflow when the bar collapses.
- index.css: html/body locked to 100% height, overflow hidden,
overscroll-behavior none; #root set to exact 100dvh
- App.css: .app height: 100dvh (was min-height: 100vh) with
overflow-y: auto + overscroll-behavior: contain so the .app
becomes the scroll container
- capacitor.config.json: ios.bounces false, contentInset never
Co-Authored-By: Claude <noreply@anthropic.com>
- Tag triggers split: ios-v* -> deploy_ios, android-v* -> deploy_android.
The blanket tag: "*" trigger that ran both platforms on every tag is gone.
- Add certificate-and-profile-installer@1 before xcode-archive@4 in
deploy_ios and combined deploy. Reads Bitrise's auto-injected
BITRISE_IOS_CODE_SIGNING_* env vars; no-op if not configured.
- Harden test_ios simulator destination to generic/platform=iOS Simulator
(was iPhone 15, OS=latest, which breaks when the runner ships a
different Xcode).
- Enable swift build cache on xcode-archive steps.
Co-Authored-By: Claude <noreply@anthropic.com>
GoogleMLKit/BarcodeScanning ~> 8.0.0 requires iOS 15.5 (per the Sept 2024
ML Kit release notes). pod install failed with "Specs satisfying the
dependency were found, but they required a higher minimum deployment
target" when the app was set to 15.0.
Co-Authored-By: Claude <noreply@anthropic.com>
- All four IPHONEOS_DEPLOYMENT_TARGET entries in project.pbxproj bumped
from 13.0 to 15.0 to match Podfile's 'platform :ios, 15.0' and
Capacitor 8's minimum. Mismatched target caused Swift compile errors
for iOS-15-only APIs in linked pods.
- Add CapacitorMlkitBarcodeScanning pod to Podfile and the package to
root package.json (already in frontend/package.json). Without this,
cap sync never linked the pod and the build failed with
'No such module CapacitorMLKitBarcodeScanning'.
Co-Authored-By: Claude <noreply@anthropic.com>
Users were wiped on container recreation because they shared the
backend_data volume with ephemeral pharmacy/medicine data. Postgres
gets its own named volume (postgres_data) that survives deploys.
- Add postgres:16-alpine service + postgres_data volume to compose
- Add pg + connect-pg-simple deps
- userDbGet/userDbRun helpers: PG when PG_URL set, SQLite fallback
- Sessions use connect-pg-simple when pgPool available
- create-admin.js: PG-aware, SQLite fallback for local dev
- push_subscriptions.user_id: plain INTEGER (cross-DB FK dropped)
- Tests unchanged — no PG_URL in test env = SQLite fallback
Set PG_PASSWORD in server .env before next deploy.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build context was ./backend so API/ was never copied into the image.
server.js imports ../API/index.js which resolves to /API/index.js at runtime.
Expand build context to project root and explicitly copy API/ to /API/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>