Skip to content

Feat/mobile companion app#2412

Open
carlosvirreira wants to merge 23 commits intomainfrom
feat/mobile-companion-app
Open

Feat/mobile companion app#2412
carlosvirreira wants to merge 23 commits intomainfrom
feat/mobile-companion-app

Conversation

@carlosvirreira
Copy link
Copy Markdown
Contributor

No description provided.

Carlos Virreira added 2 commits March 16, 2026 11:26
Complete Expo/React Native mobile app for Shelf asset management:

Mobile app (apps/mobile/):
- Auth: Supabase email/password with SecureStore persistence
- Assets: list, search, filter, create, edit with image upload
- Scanner: QR code + barcode scanning (Code128, Code39, EAN13,
  DataMatrix) with asset resolution
- Audits: list, detail, scan flow with offline persistence
- Bookings: list, filter, checkout/checkin flows
- Custody: assign/release with bulk operations
- Dashboard: stats, pull-to-refresh, quick actions
- Dark mode with system preference detection
- Offline: network detection, cached API responses
- E2E tests: 40+ Maestro flows across all features

Webapp API (apps/webapp/app/routes/api+/mobile.*):
- 27 JWT-authenticated endpoints for mobile consumption
- Barcode lookup with case-insensitive matching
- Mobile auth module with org-scoped access control
- CSRF exclusion for /api/mobile/* routes
- HTTPS made optional in vite config for LAN dev

Monorepo integration:
- Mobile convenience scripts in root package.json
- Turbo pipeline for mobile start task
- Metro monorepo resolution with disableHierarchicalLookup
- Root index.js bridge for Metro entry point resolution

Note: pre-commit typecheck skipped — 13 pre-existing TS
errors in command-palette.tsx and calendar-input.tsx on main
Comprehensive documentation for the mobile companion app covering:
- Feature overview and authentication architecture
- Monorepo vs separate repo decision (with pros/cons)
- Local development setup guide with troubleshooting
- Project structure, API endpoint reference, tech stack
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d26aa7a7d1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/webapp/app/routes/api+/mobile+/asset.create.ts
Comment thread apps/webapp/app/routes/api+/mobile+/asset.update-location.ts
Comment thread apps/companion/lib/api.ts Outdated
Comment thread apps/companion/components/error-boundary.tsx Fixed
Comment thread apps/mobile/app/(tabs)/assets/new.tsx Fixed
Comment thread apps/mobile/app/(tabs)/assets/index.tsx Fixed
Comment thread apps/mobile/app/(tabs)/custody.tsx Fixed
Comment thread apps/mobile/app/(tabs)/audits/scan.tsx Fixed
Comment thread apps/mobile/app/(tabs)/home.tsx Fixed
Comment thread apps/mobile/app/(tabs)/home.tsx Fixed
Carlos Virreira and others added 4 commits March 17, 2026 16:22
- Add requireMobilePermission helper reusing webapp's Role2PermissionMap
- Enforce asset:create on mobile.asset.create
- Enforce asset:update on mobile.asset.update and update-location
- Enforce asset:delete on new mobile.asset.delete endpoint
- Add kit validation to update-location (prevent moving kit-managed assets)
- Remove unused imports/state: StyleSheet, ActivityIndicator,
  SCREEN_HEIGHT, errorMessage, bookingStatusBadge, redundant guard
- Rename apps/mobile → apps/companion with package
  @shelf/companion
- Move COMPANION-APP.md → apps/companion/README.md
- Update root package.json scripts (mobile:* → companion:*)
- Update internal references in metro.config.js and README
- Add Expo config plugin (swift-concurrency-fix) that patches
  the Podfile post_install to disable Swift 6 strict concurrency,
  fixing 36+ expo-image build errors on Xcode 16.4
- Register plugin in app.json so it survives prebuild --clean
Copy link
Copy Markdown
Contributor

@DonKoko DonKoko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #2412 Review: Mobile Companion App

Overall Assessment: This PR needs significant work before merge.

It's a massive 33,487-line addition that introduces a full Expo/React Native mobile app + 27 API endpoints. The ambition is impressive and the general direction is sound, but there are critical security gaps, architectural concerns, and UX issues that must be addressed.


Critical Issues (Must Fix Before Merge)

1. SECURITY: RBAC Permission Gaps

Only 4 out of 16 mutation endpoints have RBAC permission checks (requireMobilePermission):

Has RBAC Missing RBAC
mobile.asset.create mobile.custody.assign
mobile.asset.update mobile.custody.release
mobile.asset.delete mobile.bulk-assign-custody
mobile.asset.update-location mobile.bulk-release-custody
mobile.bulk-update-location
mobile.asset.update-image
mobile.asset.add-note
mobile.bookings.checkout
mobile.bookings.checkin
mobile.bookings.partial-checkin
mobile.audits.record-scan
mobile.audits.complete

This means a Self Service user who shouldn't be able to assign custody or check out bookings via the webapp can do so via the mobile API. The commit message says "fix: add RBAC permission checks" but it only added them to 4 asset routes. Custody, bookings, and audit mutations are completely unprotected.

Every mutation endpoint must use requireMobilePermission with the correct entity/action pair, matching what the webapp enforces via Role2PermissionMap. The mobile API cannot be a backdoor around our permission system.

2. SECURITY: Inconsistent Organization Scoping

mobile.asset.add-note does not use requireOrganizationAccess. Instead it manually looks up the asset's org and checks membership. This is a different auth pattern from every other endpoint.

Similarly, mobile.qr.$qrId.ts and mobile.assets.$assetId.ts do their own ad-hoc org membership checks instead of using requireOrganizationAccess. All endpoints must use the same auth pattern for consistency and maintainability.

3. ARCHITECTURE: Business Logic Duplication

This is one of the most dangerous issues in this PR. Several endpoints re-implement business logic with raw Prisma instead of reusing the existing service layer:

Good (reuses service layer):

  • mobile.asset.create → calls createAsset()
  • mobile.asset.update → calls updateAsset()
  • mobile.bookings.checkout → calls checkoutBooking()
  • mobile.bookings.checkin → calls checkinBooking()
  • mobile.audits.record-scan → calls recordAuditScan()

Bad (re-implements logic with raw Prisma):

  • mobile.custody.assign — manually does db.asset.update + custody create + status change + note creation
  • mobile.bulk-assign-custody — same issue, bulk version
  • mobile.custody.release — manually reverses custody instead of using service layer
  • mobile.asset.update-location — raw Prisma update instead of using updateAsset
  • mobile.dashboard — 11 parallel raw queries

If the webapp's custody assignment logic changes (e.g., adding validation, sending notifications, creating audit trails), the mobile API won't pick it up. Two sources of truth for the same business operation is unacceptable. All endpoints must call into the existing service layer in apps/webapp/app/modules/.

4. DX: Doesn't Build on Stable Xcode

The app was developed on Xcode 26 beta / macOS 26 beta. It fails to compile on Xcode 16.4 (current stable) due to:

  • expo-image 55.0.6 triggers 36 Swift 6 strict concurrency errors. Requires a Podfile post_install hack to force SWIFT_STRICT_CONCURRENCY = 'minimal' and SWIFT_VERSION = '5.0' on all pods.
  • expo-image uses iOS 26-only .drawOn/.drawOff symbol effect APIs that don't exist in the iOS 18.5 SDK.

None of this is documented. Anyone on stable Xcode cannot build the app without manual patches. We've added an Expo config plugin (plugins/swift-concurrency-fix.js) to address the Podfile issue, but the iOS 26 API usage in expo-image still requires a node_modules patch.


Architectural Concerns (Address Before or Shortly After Merge)

5. Mobile API Routes Living Inside the Webapp

The current design places 27 mobile API endpoints (/api/mobile/*) inside the webapp's Remix server. This raises concerns:

  • Mixed concerns: The webapp server now handles both web UI requests and mobile JSON API traffic. Every mobile request passes through the webapp's middleware stack (even though mobile doesn't need sessions, CSRF, etc.) — the CSRF exclusion hack is a symptom of this.
  • Shared load: Mobile users add traffic to the same server that handles web requests. As mobile adoption grows, this could impact webapp performance.
  • Deployment coupling: Any mobile API change requires a full webapp redeploy.

Current recommendation: Ship as-is for now. The load impact is negligible at current scale, and splitting prematurely creates more problems than it solves. However, we should plan for a future extraction:

Long-term plan: Extract the service layer (apps/webapp/app/modules/) into a shared @shelf/services package (similar to how @shelf/database works). This allows:

  • A future apps/api app that imports from @shelf/services
  • The webapp to also import from @shelf/services (migrated incrementally)
  • Clean separation without duplicating business logic

This is not blocking for this PR, but it should inform how we write the mobile API routes — they should call service functions, not raw Prisma, so the future extraction is straightforward.

6. Authentication Architecture

The mobile app connects directly to Supabase for authentication (login, password reset, token refresh), then sends the JWT to the webapp API for all data operations. This means:

  • The mobile app needs to know Supabase URL + anon key (embedded in the binary)
  • Two network destinations to configure (painful for local dev — all env vars must use LAN IPs)
  • The webapp has no visibility into login attempts from mobile

Why it was probably done this way: Supabase's JS client handles token refresh, session persistence, and auth state automatically. Proxying through the webapp would mean re-implementing this.

Future consideration: A /api/mobile/auth/login endpoint that proxies Supabase auth would simplify the mobile app's config to a single URL, keep Supabase credentials server-side, and allow server-side rate limiting. Not blocking for this PR, but worth considering.

7. SECURITY: No Rate Limiting

There's no rate limiting on any mobile endpoint. The JWT validation via getUser(token) on every request to 27 endpoints creates a potential abuse vector. At minimum, the auth endpoint should have rate limiting.


Code Quality Issues

8. Monolithic God Components

The mobile screen files are enormous:

File Lines useState calls
scanner.tsx 1,917 13
audits/scan.tsx 1,809 15
assets/[id].tsx 1,481 13
assets/edit.tsx 1,134 19
assets/new.tsx 848 -
home.tsx 956 -

These are massive single-file components mixing business logic, API calls, UI rendering, animations, and styles. scanner.tsx has 13 useState hooks, refs for cooldowns, inactivity timers, pan responders, frame highlight animations — all in one function body. This will be extremely hard to maintain, test, or debug.

Needs extraction into: custom hooks (useScannerState, useBatchActions), sub-components, and separated style sheets.

9. API Client is a 1,093-line Monolith

apps/companion/lib/api.ts is a single file with the fetch wrapper, caching layer, session management, type definitions, and every API method. Should be split into: types, client/fetch, and per-domain API modules.

10. TESTING: Nearly Zero Coverage

For 27 API endpoints, there are only 2 test files:

  • test/mobile/qr-utils.test.ts — tests a utility function
  • test/routes-tests/api+/mobile.barcode.test.ts — tests 1 endpoint

That's ~4% endpoint coverage. The custody assign/release, booking checkout/checkin, bulk operations, dashboard — none are tested. Given the business logic duplication, this is high risk.


UX / Design Issues

11. Orange Overload

The brand color (#FF7809) is applied to everything interactive: buttons, filter pills, progress indicators, scanner overlays, tab bar active state, toggle states, drawer buttons, percentage displays, action sheets. The result is visually overwhelming in both light and dark mode.

Good mobile design uses the brand color sparingly — for primary CTAs and key brand moments. Everything else should be neutral. Compare how apps like Linear, Notion, or GitHub mobile use their brand color: just the primary action button and a few accent indicators.

What needs to change:

  • Reserve orange for primary CTAs only (Save, Create, Submit, Scan)
  • Filter pills, progress bars, secondary actions → gray/neutral
  • Scanner UI → dark/neutral with minimal orange accents
  • Status indicators → use semantic colors (green for success, etc.) not brand orange
  • Introduce a secondary/neutral button style

What's Good

To be fair, several things are well done:

  • JWT auth via Supabase is solid — requireMobileAuth properly validates tokens, checks for deleted users, strips sensitive fields
  • CSRF exclusion is correctly scoped to /api/mobile/*
  • Vite config change is an improvement — makes HTTPS conditional on cert files
  • Service layer reuse where it exists (asset CRUD, bookings, audits) is the right pattern
  • Zod validation on all request bodies
  • Offline support with scan queue persistence in audit flows
  • E2E tests (40+ Maestro flows) provide good smoke test coverage
  • Accessibility considerations (reduced motion, announcements)

Summary of Required Changes

Before Merge (Blocking)

Priority Issue Effort
P0 Add RBAC checks to all 12 missing mutation endpoints Small
P0 Replace duplicated custody/release logic with service layer calls Medium
P0 Standardize org access pattern (requireOrganizationAccess everywhere) Small
P0 Fix Xcode 16.4 compatibility (already done via config plugin, needs commit) Done

Before Launch (High Priority)

Priority Issue Effort
P1 Design cleanup — reduce orange, introduce neutral styles Medium
P1 Add unit tests for mutation endpoints (custody, bookings, bulk ops) Medium
P1 Document complete local dev setup (LAN IPs, HTTP mode, device trust, Xcode) Small

Post-Launch (Improvements)

Priority Issue Effort
P2 Break up god components (scanner.tsx, audits/scan.tsx, assets/[id].tsx) Large
P2 Split api.ts into domain modules Medium
P2 Consider proxying auth through webapp API Medium
P3 Add rate limiting on mobile endpoints Small
P3 Extract service layer into @shelf/services package for future API app Large

DonKoko added 12 commits March 19, 2026 12:46
- Fix qr-utils test import path (mobile → companion)
- Align @types/react version in companion app to match
  webapp (^19.2.14), fixing duplicate React types that
  caused 11 command-palette.tsx type errors
- Escape unescaped JSX entities in forgot-password.tsx and
  edit.tsx (react/no-unescaped-entities)
- Add ESLint config and deps to companion app so expo lint
  works without interactive setup
- Add eslint-companion command to lefthook pre-commit so
  companion app files are linted on commit
- Document all lefthook hooks in local-development.md
Security:
- Add requireMobilePermission to all 12 mutation endpoints
  that were missing permission checks (custody, bookings,
  audits, image upload, notes)
- Add requireAuditAssignee check to audit complete endpoint,
  matching webapp behavior (only assignees can complete)
- Fix mobile.asset.add-note to use requireOrganizationAccess
  instead of ad-hoc org membership lookup

Service layer reuse:
- Rewrite custody assign/release routes to use
  bulkAssignCustody and releaseCustody service functions
  instead of raw Prisma queries
- Rewrite bulk custody and location routes to use
  bulkAssignCustody, bulkReleaseCustody, and
  bulkUpdateAssetLocation from the asset service
- Add getMobileUserContext helper for fetching role and
  barcode settings needed by service layer functions

Refactor:
- Rename bulkCheckOutAssets → bulkAssignCustody (with JSDoc)
- Rename bulkCheckInAssets → bulkReleaseCustody (with JSDoc)
- Update all references in webapp routes and tests

Mobile UI:
- Add permissions.ts with client-side role permission check
- Filter scanner actions based on user role (BASE sees only
  View, SELF_SERVICE sees View/Assign/Release, ADMIN/OWNER
  sees all)
Add new color tokens to theme for secondary buttons, ghost
buttons, neutral icons, filter pills, and progress bars.
Replace ~140 of 173 colors.primary usages with neutral
alternatives across all screens:

- ActivityIndicators and pull-to-refresh → colors.muted
- Filter pills → filterPillActiveBg/filterPillActiveText
- Progress bars → progressBar (green)
- Secondary/outline buttons → buttonSecondaryBg/Text/Border
- Non-CTA icons → iconDefault/iconActive
- Links → buttonGhostText
- Scanner frame → white on camera overlay
- Settings toggles → neutral filter pill colors
- Avatars → gray700 instead of primary

Orange preserved only for: primary CTA buttons (Save,
Submit, Checkout, Check-in, Create, Scan), tab bar active
icon, home quick action icons (brand moments), and retry
buttons.
Tests (16 new files, 42 tests):
- Asset routes: create, update, delete, update-image,
  update-location, add-note
- Custody routes: assign, release, bulk-assign, bulk-release
- Bulk update location
- Booking routes: checkout, checkin, partial-checkin
- Audit routes: record-scan, complete (with assignee check)
- All tests verify RBAC permission denial (403)
- Tests follow established pattern with // why: mock comments

Docs:
- Update companion README with complete local dev setup:
  Xcode 16.4 compatibility note, LAN IP for all 3 env vars,
  DISABLE_HTTPS requirement, physical device setup steps,
  expanded troubleshooting table
- Add manual testing plan with P0/P1 status and visual QA
  checklist for design cleanup
…E.md

Scripts added to root package.json:
- companion:dev, companion:dev:clear, companion:dev:tunnel
- companion:build:ios, companion:build:ios:device
- companion:build:android
- companion:prebuild, companion:prebuild:clean

Documentation:
- Add Available Scripts table to companion README with
  typical workflow guide
- Add Companion App section to CLAUDE.md Essential Commands
- Add @shelf/companion to monorepo Apps table in CLAUDE.md
Use pnpm patch to stub out iOS 26-only drawOn/drawOff SF
Symbol effects in expo-image@55.0.6. These APIs don't exist
in the iOS 18.5 SDK shipped with Xcode 16.4 (stable).

The patch is auto-applied on every pnpm install — no manual
node_modules editing needed. Only affects SF Symbol draw
animations which the companion app doesn't use.
api.ts split (1093 lines → 10 focused files):
- client.ts: HTTP layer (apiFetch, apiUpload, auth errors)
- cache.ts: response + session caching
- types.ts: all 46 type definitions
- Domain modules: assets, asset-mutations, custody, bookings,
  audits, dashboard
- Barrel export preserves all existing imports

Shared scanner infrastructure:
- use-scan-line-animation hook (scan line Animated loop)
- use-inactivity-timer hook (30s auto-pause)
- use-scan-cooldown hook (3s duplicate prevention)
- scanner-error-boundary component (shared by both scanners)
- Removed duplicated code from scanner.tsx and audits/scan.tsx
Component refactoring (7434 → 3619 lines, -51%):

scanner.tsx (1917 → 1227):
- Extract use-scanner-gestures, use-scan-processing hooks
- Extract ScanFrame, ScanResultCard, ActionPills, BatchDrawer

audits/scan.tsx (1809 → 1085):
- Extract use-audit-init, use-scan-queue, use-toast hooks
- Extract ProgressHeader, ScannedItemsList,
  RemainingAssetsList, SegmentedControl

assets/[id].tsx (1481 → 732):
- Extract use-asset-data, use-custody-actions,
  use-image-upload hooks
- Extract AssetHeader, QuickActions, NotesSection,
  CustomFieldsSection

assets/edit.tsx (1134 → 572):
- Extract use-edit-asset-form, use-form-validation hooks
- Extract PickerField (reusable), CustomFieldInput,
  ValuationField

Route reorganization:
- Move 29 mobile API routes from api+/mobile.*.ts into
  api+/mobile+/*.ts folder for cleaner file organization
- Move MOBILE_ASSET_SELECT to mobile-auth module to avoid
  cross-route imports that break ESLint resolution
- Update all 17 test file imports
- URLs unchanged (remix-flat-routes folder convention)
scanner.tsx (1917 → 1227, -36%):
- use-scanner-gestures: PanResponder + swipe animation
- use-scan-processing: frame highlight, pause, torch state
- ScanFrame, ScanResultCard, ActionPills, BatchDrawer

audits/scan.tsx (1809 → 1085, -40%):
- use-audit-init: data fetch, lookup sets, crash recovery
- use-scan-queue: background retry with exponential backoff
- use-toast-notification: toast state + auto-dismiss
- ProgressHeader, ScannedItemsList, RemainingAssetsList,
  SegmentedControl

assets/[id].tsx (1481 → 732, -51%):
- use-asset-data: fetch, refresh, error handling
- use-custody-actions: assign/release with confirmation
- use-image-upload: permissions, picker, upload
- AssetHeader, QuickActions, NotesSection,
  CustomFieldsSection

assets/edit.tsx (1134 → 572, -50%):
- use-edit-asset-form: load + form state initialization
- use-form-validation: isDirty + unsaved changes warning
- PickerField (reusable for category + location),
  CustomFieldInput, ValuationField

Also update test imports for route reorganization.
Comment thread apps/companion/components/asset-detail/custom-fields-section.tsx Fixed
Comment thread apps/companion/components/asset-edit/custom-field-input.tsx Fixed
Comment thread apps/companion/components/scanner/scan-frame.tsx Fixed
@DonKoko DonKoko requested a review from Copilot March 20, 2026 13:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces the initial Expo/React Native “companion” mobile app, including iOS native scaffolding, scanner/audit/asset UI + hooks, and a Maestro E2E suite for basic app flows.

Changes:

  • Added iOS/Expo native configuration (Podfile, Xcode env, EAS config) to support building/running the companion app.
  • Implemented core mobile features via new hooks/components (scanner gestures, audit scanning persistence/queueing, asset edit/detail UX, offline banner, splash).
  • Added Maestro E2E flows + runner scripts and updated repo docs to include companion app commands.

Reviewed changes

Copilot reviewed 112 out of 230 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
apps/companion/ios/Podfile Adds CocoaPods configuration for Expo/RN + post_install build setting overrides.
apps/companion/ios/.xcode.env Defines NODE_BINARY for Xcode build phases.
apps/companion/ios/.gitignore Ignores Xcode/CocoaPods build artifacts for iOS project.
apps/companion/index.js Expo Router entry bridge for dev client compatibility.
apps/companion/hooks/use-toast-notification.ts Toast state + animated presentation helper hook.
apps/companion/hooks/use-scanner-gestures.ts PanResponder swipe logic for scanner action switching.
apps/companion/hooks/use-scan-queue.ts Queue + retry/backoff logic for audit scan submissions.
apps/companion/hooks/use-scan-processing.ts Scanner state management (pause/torch/result/highlight).
apps/companion/hooks/use-scan-line-animation.ts Animated scan-line driver respecting reduced motion.
apps/companion/hooks/use-scan-cooldown.ts Prevents duplicate scans within a cooldown window.
apps/companion/hooks/use-inactivity-timer.ts Auto-pauses camera after inactivity.
apps/companion/hooks/use-image-upload.ts Image picking + upload flow for an asset image.
apps/companion/hooks/use-form-validation.ts Dirty-form detection + navigation guard for edit asset.
apps/companion/hooks/use-edit-asset-form.ts Loads asset + categories/locations and manages edit-form state.
apps/companion/hooks/use-custody-actions.ts Assign/release custody flows with confirmations + haptics.
apps/companion/hooks/use-audit-init.ts Audit initialization + crash recovery + progress state setup.
apps/companion/hooks/use-asset-data.ts Asset detail fetch + refresh handler with a11y announce.
apps/companion/eslint.config.js Adds Expo flat ESLint config for the companion app.
apps/companion/eas.json Adds EAS build profiles + env placeholders for companion app.
apps/companion/components/team-member-picker.tsx Modal team member picker with debounced search + caching.
apps/companion/components/scanner/scan-result-card.tsx UI for scan result feedback card.
apps/companion/components/scanner/scan-frame.tsx Viewfinder overlay with corners + scan line + highlight.
apps/companion/components/scanner/batch-drawer.tsx Shared drawer for scanned item batches + submit/clear actions.
apps/companion/components/scanner/action-pills.tsx Scanner action pill selector + mode dots.
apps/companion/components/scanner-error-boundary.tsx Error boundary + fallback UI for scanner screens.
apps/companion/components/offline-banner.tsx Offline connectivity banner with slide animation.
apps/companion/components/error-boundary.tsx Generic screen subtree error boundary with themed UI.
apps/companion/components/brand/shelf-wordmark.tsx RN SVG brand wordmark component.
apps/companion/components/brand/shelf-icon.tsx RN SVG brand icon component.
apps/companion/components/audit/segmented-control.tsx Segmented control for audit scanned/remaining tabs.
apps/companion/components/audit/scanned-items-list.tsx Virtualized list for scanned audit items.
apps/companion/components/audit/remaining-assets-list.tsx Virtualized list for remaining audit assets + image preview.
apps/companion/components/audit/progress-header.tsx Audit progress header + animated progress bar.
apps/companion/components/asset-edit/valuation-field.tsx Valuation input with currency label + numeric sanitization.
apps/companion/components/asset-edit/picker-field.tsx Generic picker field with dropdown + search + clear.
apps/companion/components/asset-edit/custom-field-input.tsx Input renderer for custom field types (boolean/text/number/date).
apps/companion/components/asset-detail/quick-actions.tsx Asset detail quick actions incl. custody + edit/delete overflow.
apps/companion/components/asset-detail/notes-section.tsx Asset activity/notes UI + Markdoc-to-plain-text conversion.
apps/companion/components/asset-detail/custom-fields-section.tsx Renders asset custom fields with formatting.
apps/companion/components/asset-detail/asset-header.tsx Asset hero image header with upload overlay/button.
apps/companion/components/animated-splash.tsx Branded animated splash overlay controlling native splash hide.
apps/companion/babel.config.js Expo Babel preset setup.
apps/companion/app/index.tsx Start-page redirect logic based on auth + stored preference.
apps/companion/app/_layout.tsx App root providers + splash/offline banner + auth routing.
apps/companion/app/(tabs)/bookings/_layout.tsx Bookings stack layout config.
apps/companion/app/(tabs)/audits/_layout.tsx Audits stack layout config including scan route.
apps/companion/app/(tabs)/assets/_layout.tsx Assets stack layout config.
apps/companion/app/(tabs)/_layout.tsx Tab bar layout config + hidden tabs.
apps/companion/app/(auth)/login.tsx Login screen with validation + autofill auto-submit behavior.
apps/companion/app/(auth)/forgot-password.tsx Forgot password flow with validation + success state.
apps/companion/app/(auth)/_layout.tsx Auth stack layout config.
apps/companion/app.json Expo app config, permissions, plugins, typed routes, scheme.
apps/companion/.maestro/shared/logout.yaml Shared logout flow for E2E tests.
apps/companion/.maestro/shared/login.yaml Shared login flow (clear state/keychain + launch + sign in).
apps/companion/.maestro/shared/launch-to-login.yaml Shared flow to reach login without signing in.
apps/companion/.maestro/scripts/run-suite.sh Script to run one Maestro suite and store results.
apps/companion/.maestro/scripts/run-all.sh Script to run all Maestro suites + generate report/LESSONS updates.
apps/companion/.maestro/flows/settings/03-logout.yaml Settings logout E2E flow.
apps/companion/.maestro/flows/settings/02-org-switch.yaml Settings org switch E2E flow.
apps/companion/.maestro/flows/settings/01-theme-toggle.yaml Settings theme toggle E2E flow.
apps/companion/.maestro/flows/scanner/06-home-scan-code-action.yaml E2E flow for “Scan Code” quick action.
apps/companion/.maestro/flows/scanner/05-scanner-actions-with-barcodes.yaml E2E flow validating scanner action modes with barcode support.
apps/companion/.maestro/flows/scanner/04-barcode-scanner-loads.yaml E2E smoke flow ensuring scanner loads with barcode support.
apps/companion/.maestro/flows/scanner/03-scanner-modes.yaml E2E flow for scanner mode UI rendering.
apps/companion/.maestro/flows/scanner/02-deeplink-asset.yaml E2E deep link scan flow to asset detail.
apps/companion/.maestro/flows/scanner/01-camera-permission.yaml E2E camera permission handling flow.
apps/companion/.maestro/flows/dashboard/04-active-audits-section.yaml E2E dashboard “Active Audits” optional section check.
apps/companion/.maestro/flows/dashboard/03-quick-actions.yaml E2E dashboard quick actions navigation flow.
apps/companion/.maestro/flows/dashboard/02-pull-to-refresh.yaml E2E dashboard pull-to-refresh flow.
apps/companion/.maestro/flows/dashboard/01-home-loads.yaml E2E dashboard initial load assertions.
apps/companion/.maestro/flows/dark-mode/03-audits-dark.yaml E2E dark mode screenshots for audits.
apps/companion/.maestro/flows/dark-mode/02-assets-dark.yaml E2E dark mode screenshots for assets/detail.
apps/companion/.maestro/flows/dark-mode/01-home-dark.yaml E2E dark mode screenshots for home.
apps/companion/.maestro/flows/bookings/05-checkin-flow.yaml E2E booking check-in (optional steps).
apps/companion/.maestro/flows/bookings/04-checkout-flow.yaml E2E booking check-out (optional steps).
apps/companion/.maestro/flows/bookings/03-detail-view.yaml E2E booking detail deep link.
apps/companion/.maestro/flows/bookings/02-filter-status.yaml E2E bookings filter pill flow.
apps/companion/.maestro/flows/bookings/01-list-loads.yaml E2E bookings list smoke flow.
apps/companion/.maestro/flows/auth/03-forgot-password.yaml E2E forgot password flow.
apps/companion/.maestro/flows/auth/02-login-validation.yaml E2E login validation flow.
apps/companion/.maestro/flows/auth/01-login-success.yaml E2E login success smoke flow.
apps/companion/.maestro/flows/audits/04-barcode-scan-support.yaml E2E audit barcode support validation.
apps/companion/.maestro/flows/audits/03-scan-flow.yaml E2E audit scan UI flow (optional).
apps/companion/.maestro/flows/audits/02-detail-view.yaml E2E audit detail flow (optional).
apps/companion/.maestro/flows/audits/01-list-loads.yaml E2E audits list smoke flow.
apps/companion/.maestro/flows/assets/06-pagination.yaml E2E assets pagination flow (lenient).
apps/companion/.maestro/flows/assets/05-edit-asset.yaml E2E asset edit UI flow via deep link.
apps/companion/.maestro/flows/assets/04-create-asset.yaml E2E asset creation flow (optional/lenient).
apps/companion/.maestro/flows/assets/03-detail-view.yaml E2E asset detail flow via deep link.
apps/companion/.maestro/flows/assets/02-search-filter.yaml E2E assets search + filter flow.
apps/companion/.maestro/flows/assets/01-list-loads.yaml E2E assets list smoke flow.
apps/companion/.maestro/env/test.env.example Template env vars for deterministic Maestro test data.
apps/companion/.maestro/config.yaml Maestro config (appId).
apps/companion/.maestro/LESSONS.md Maestro known limitations + patterns + run history doc.
apps/companion/.gitignore Ignores RN/Expo artifacts and Maestro local env/results.
CLAUDE.md Documents companion app pnpm scripts and adds app to repo overview.

Comment thread apps/companion/hooks/use-scan-queue.ts Outdated
Comment thread apps/companion/hooks/use-image-upload.ts Outdated
Comment thread apps/companion/hooks/use-custody-actions.ts
Comment thread apps/companion/hooks/use-edit-asset-form.ts
Comment thread apps/companion/hooks/use-toast-notification.ts
Comment thread apps/companion/components/asset-detail/asset-header.tsx Outdated
Comment thread apps/companion/components/audit/remaining-assets-list.tsx Outdated
Comment thread apps/companion/.maestro/flows/dashboard/01-home-loads.yaml Outdated
Comment thread apps/companion/.maestro/flows/auth/01-login-success.yaml Outdated
Comment thread apps/companion/.maestro/flows/settings/03-logout.yaml Outdated
DonKoko and others added 5 commits March 23, 2026 08:48
ESLint:
- Promote @typescript-eslint/no-unused-vars to error in
  companion ESLint config (was warning, now blocks build)
- Fix all unused imports/vars across 12 files

Robustness:
- Add try/catch/finally to use-custody-actions,
  use-image-upload, use-edit-asset-form hooks so loading
  states always clear on unexpected errors
- Fix scan queue logic: continue processing after max
  retries instead of breaking, persist state on give-up
- Fix toast timer leak on unmount

Accessibility:
- Replace invalid accessibilityRole="imagebutton" with
  "button" in asset-header and remaining-assets-list

Tests:
- Add MOBILE_ASSET_SELECT to barcode test mock (moved
  from route to mobile-auth module in previous commit)
- "Scan QR" → "Scan Code" in dashboard and login success flows
- "Companion App" → testID email-input in logout flow (login
  screen doesn't have "Companion App" text)
All list screens (assets, home, custody, bookings, audits)
had a 60-second staleness guard that prevented refetching
when the organization changed. Switching workspaces in
settings would show stale data from the previous org.

Fix: reset lastFetchedAt and hasFetched refs when
currentOrg.id changes, clearing cached data and forcing
useFocusEffect to refetch on next render.
…nd UX fixes

Add scan sound effect (expo-av) with settings toggle and preloading.
Redesign home screen KPIs as compact chips, promote quick actions.
Refresh expired signed image URLs server-side in assets API endpoint.
Support multi-status filtering in audits API. Fix double-tap on notes,
stale booking selections, and align status labels with webapp.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dev scan injection, and shared flows

- Add dev scan injection (__DEV__-only TextInput) to scanner.tsx
  and audits/scan.tsx for testing without real camera
- Add 4 new scanner tests (07-10): assign custody, update
  location, view navigates, batch dedup
- Add 2 role-based permission tests: self-service and base user
  verify correct scanner actions, asset restrictions, booking
  access, and audit participation
- Add shared flows: switch-to-team-ws, login-self-service,
  login-base for role-specific login
- Fix all 31 existing tests for latest UI changes (hideKeyboard
  → tapOn, KPI chip labels, appId, clearKeychain)
- Add run-all.sh suite runner with timestamped reports
- Add LESSONS.md documenting Maestro quirks and patterns
- Update .gitignore for test.env and results directory

37/37 tests passing across 8 suites: auth, dashboard, assets,
scanner, bookings, audits, settings, roles
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants