The lifted screen-state refactor in PublicView broke App.test.jsx (5
failures): when no `onScreenChange` prop was passed, the click handler
called a no-op, so the screen never advanced from 'home' to 'search'
and the search input was never rendered.
Fix: make screen state uncontrolled-by-default. PublicView owns its
own `useState('home')` and uses the lifted props only when App.jsx
provides them. Same back-compat shape as before, BottomNav still
drives the screen via controlled props in the real app.
Also: vitest defaults to watch mode, which hangs the CI test step
forever. Updated docker.yaml to pass `--run --reporter=basic` so the
job exits with a real pass/fail signal.
Local verification: `npm test -- --run` → 6/6 passing.
Co-Authored-By: Claude <noreply@anthropic.com>
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>