Home · Docs · Roadmap

Mobile Field Service — Roadmap

Field Value
Title Product and engineering roadmap
Repo Fujio-Turner/mobile_field_service
Author Fujio-Turner / mobile_field_service
Date 2026-09-06
Status S01–S16 except S15 (vector) implemented. Demo three modes on iOS.
Architecture DESIGN.md
Use cases DAY_IN_LIFE.md

This is a Fujio-Turner offline-first field app (Expo + cbl-reactnative fork, CBL 4.x EE target + vector index). Repo: https://github.com/Fujio-Turner/mobile_field_service. Walk a mode day before implementing screens: assets, customer, sales. Auth: AUTH.md. Settings: guides/SETTINGS.md.

How to read checkboxes:

Mark Meaning
[x] Done in this repo
[ ] Not done

PRs 00–05 are a linear spine. After that, photos / tasks / map / inventory / chat can overlap; the replicator PR waits until outbound + children + messages exist so push filters are real. “Independently mergeable” means each PR leaves the app building; it does not mean 06–14 can land in any order.


Phase 0 — Docs and constraints

Exit: an engineer can implement without inventing field names, prefixes, or SQL++.


Phase 1 — App shell and session UI

Exit: installable iOS/Android binary; demo login navigates to Today (seed jobs on a development build).


Phase 2 — Encrypted database, collections, seed

Exit: cblite / VSCode CBL inspector shows field.workordersin seed docs with audit stamps.

Load: seed ≤ 20 jobs, ≤ 200 assets, ≤ 50 products — small enough for first-run demo, not a district dump.


Phase 3 — Today list + KV detail

Exit: scrolling 40+ seed jobs stays on the indexed plan; tap does not re-query the list.

Latency: today list p95 < 50 ms local; KV p95 < 10 ms.


Phase 4 — Copy-on-write

Exit: double-tap Start opens one outbound id; dispatch inbound JSON unchanged; field-created inbound pushes; Today tap on a started job KV-gets the out doc.


Phase 5 — Outbound editor, status, Submit (no camera yet)

Exit: a tech can start, edit ops, complete, freeze, submit, and open a follow-up paper fully offline (without photos).


Phase 6 — Photos and local.tmp

Exit: 10 photos on a job survive process death; local.tmp staging expires.

Storage: 10 photos × 400 KB ≈ 4 MB/job; 15 jobs/day ≈ 60 MB/day photos. v1 cap is the only growth control.


Phase 7 — Tasks and notes

Exit: CompleteWork refuses a job with an open required task; notes cannot land on a frozen WO.


Phase 7b — Chat

Exit: airplane-mode send appears after radio returns; completing a WO does not freeze the thread.


Phase 8 — Assets map

Exit: map shows seed pumps/sites; pin opens KV detail; airplane mode still shows pins.


Phase 8b — Location crumbs (tracking)

Exit: moving ~100 m+ writes a point; last 7 constructed ids KV-get; still docs do not dump crumbs.


Phase 9 — Products and inventory

Exit: consuming a valve on the job writes invtx: and a materials line; van list shows snapshot + txs newer than snapshot.audit.up.dt; crash between tx and materials is repaired via appliedToWo only.


Phase 9b — Orders, rates, taxes, field customers

Exit: sales-mode Today lists an inbound order; copy + complete does not change inbound JSON; walk-up creates cus: + ord:.


Phase 10 — Sync

Exit: lab SG round-trip: pull inbound, push submitted outbound + blobs + txs.


Phase 11 — Search, polish, observability


Phase EE — Vector similarity (gated)

Binding: Fujio-Turner/cbl-reactnative feat/vector-search-support (VectorIndexConfiguration). Official @couchbase/couchbase-lite-react-native 1.1 does not expose vector search — do not use it.

Still needed: native CBL 4.x bump on that fork if not already, and on-device MobileCLIP runtime (model size, NNAPI/CoreML). Lab/testing does not require an EE license.


Phase future — POD signature


Non-goals on this roadmap


PR Plan

Ordered, independently reviewable PRs. Each PR should build, typecheck, and leave the app runnable (stub screens allowed until their PR). 00→05 must land in order. After 05, 07/08/09/10 can overlap; 11 (replicator) waits for 07 and 10 so notes/tasks/tx filters exist. Completeness of push filters is extended in 07/10 if 11 were started early — do not start 11 early.

PR-00 — Docs

Title docs: field-service architecture, day-in-the-life, and roadmap
Files docs/DESIGN.md, docs/ROADMAP.md, docs/DAY_IN_LIFE*.md, docs/schema/*, guides/*, AGENT.md, README.md
Deps none
Description Fujio-Turner architecture on https://github.com/Fujio-Turner/mobile_field_service: fourteen field collections (including tracking), history[] audit trail, three modes, field-created inbound WOs, cbl-reactnative fork + vector, auth session TTL. No application code.

PR-01 — Expo app shell + login UI

Title feat: Expo SDK 52 shell, navigation, and login screen
Files package.json (Expo 52, react-native 0.76.9, Node engines ≥ 20), app.json (newArchEnabled, iOS 15.1, camera/location usage strings), app/_layout.tsx, app/login.tsx, app/(tabs)/*, src/theme.ts, src/session/AuthContext.tsx (HTTP stub), plugin.config.js, jest.config.js (or equivalent), .env.example
Deps PR-00
Description Development-build Expo app, New Architecture on, phone-first tabs. Login per AUTH.md (default basic → Keychain session). Demo strategy skips SG. README: EE license, no Expo Go, Fujio-Turner/cbl-reactnative. Test runner wired with a smoke test.

PR-02 — CBL open, collections, audit, seed

Title feat: encrypted CBL database, field collections, local.tmp, seed
Files src/db/engine.ts, src/db/database.ts, src/db/collections.ts, src/db/indexes.ts, src/db/seed.ts, src/ids.ts, src/audit.ts, src/session/dbKey.ts
Deps PR-01
Description Singleton engine, per-employee encrypted DB (mfs_<safe>_<hash8>), setDirectory(FileSystem.getDefaultPath()), string setEncryptionKey, fourteen field.* collections (including messages, orders, rates, taxes, tracking) + local.tmp, value/FTS indexes, ULID helpers, audit + stampHistory. Seed users with employeeId/email/workModes. Optional seed of today’s jobs + inbound order. Guard if native module missing.

PR-03 — Today list query + pagination

Title feat: today’s work list with LIMIT/OFFSET, filters, and live query
Files src/ops/listTodayWork.ts, src/ops/findOutboundForSources.ts, app/(tabs)/index.tsx, src/features/today/*
Deps PR-02
Description SQL++ today list keyed by assignedTo.employeeId (idx_woin_today) excluding cancelled/superseded via != (not IN), page size 20, numeric LIMIT/OFFSET. Page 0 merge of active outbound (OR of statuses), collapse per source.id. Reassigned badge. Live query inbound + outbound; coalesce. openId/openCollection via batched OR lookup.

PR-04 — KV inbound detail

Title feat: work-order inbound detail via KV get
Files src/ops/getWorkOrderIn.ts, app/wo/in/[id].tsx
Deps PR-03
Description Inbound route uses workordersin.document(id) only. Read-only site, schedule, ops, materials, asset refs. Started jobs are not this route (see PR-05).

PR-05 — Copy-on-write StartWork + Today routing

Title feat: copy-on-write start work and route Today to outbound editor
Files src/ops/startWork.ts, src/ops/getWorkOrderOut.ts, app/wo/out/[id].tsx (shell), app/(tabs)/index.tsx (tap → openCollection), tests for idempotency
Deps PR-04
Description Copy inbound JSON to new woout:<ulid> (role: primary, owner: technician) with source.* full snapshot; clone task templates; idempotent by employeeId + source.id + role=primary. Reject if inbound not assigned to session. Never writes inbound. Today tap KV-gets openCollection.document(openId) and navigates to in vs out. Metric counter.

PR-06 — Outbound editor + status + Submit

Title feat: outbound editor, status machine, and submit
Files app/wo/out/[id].tsx, src/ops/updateWorkOrderOut.ts, src/ops/transitionStatus.ts, src/ops/submitWork.ts
Deps PR-05
Description Editor for operations/checklist; status transitions including tech cancel; CompleteWork ops+checklist gates; Complete/Cancel freeze body and set owner: backend; CreateAmendment for forgotten info; history[] path/from/to + geo/time; Submit only after complete/cancel via SetSyncState. No camera. CompleteWork task gate is a documented hook for PR-08.

PR-07 — Photos + local.tmp

Title feat: photo blobs on stable keys and tmp staging
Files src/ops/photos.ts, src/ops/tmp.ts, camera permission flow in app/wo/out/[id].tsx
Deps PR-06
Description Stage in local.tmp with expiration; commit top-level photo:<id> / :thumb blobs; cap 20; JPEG budget; delete + compact. No CLIP embed.

PR-08 — Tasks and notes

Title feat: job tasks and notes collections
Files src/ops/tasks.ts, src/ops/notes.ts, app/(tabs)/notes.tsx, app/note/[id].tsx, src/ops/transitionStatus.ts (required-task hook)
Deps PR-06 (CompleteWork hook); photos not required
Description tasks instances + templates; notes job/general; FTS on notes. CompleteWork honors required tasks. Post-submit children inherit readyToPush.

PR-09 — Assets map

Title feat: MapLibre asset map and KV asset detail
Files app/(tabs)/map.tsx, app/asset/[id].tsx, src/ops/assets.ts
Deps PR-05 (link-to-job needs woout); PR-02 is not sufficient
Description OpenFreeMap when online + MapLibre; bbox query; cluster; tap KV; link asset to open woout. Document offline pins vs online basemap. Location permission.

PR-16 — Tracking crumbs

Title feat: per-day tracking collection and RecordTrackPoint
Files src/ops/tracking.ts, src/geo/haversine.ts, location watch in app shell
Deps PR-02 (collection); PR-09 (location permission). Replicator allow-list in PR-11.
Description field.tracking, id track:{YYYY-MM-DD}:{employeeId}. Map keyed by unix seconds → [lat, lon]. Write when moved ≥ EXPO_PUBLIC_TRACK_MIN_MOVE_M (default 100 m). GetTrackingLastNDays = N KV gets. Cap 4000/day. Never log the map. Foreground / while-using only.

PR-10 — Inventory and products

Title feat: product catalog, van stock, consume-on-job, rebuild
Files app/(tabs)/inventory.tsx, src/ops/products.ts, src/ops/inventory.ts
Deps PR-06
Description FTS catalog. Display qty = snapshot qtyOnHand + SUM(qtyDelta WHERE tx.audit.cr.dt > snapshot.audit.up.dt). Consume writes only inventory_tx + materials — never save stock. RebuildStock is a read model with that cutoff. Movements-only push. Role-gated allowNegative.

PR-11 — Replicator and sync UI

Title feat: collection replicator, RN push filters, and sync status
Files src/sync/replicator.ts, src/sync/filters.ts, app/(tabs)/profile.tsx, src/ops/syncSnapshot.ts
Deps PR-07, PR-08, PR-10, PR-14 (woout + photos + notes/tasks/tx + messages filters). Do not merge before those filters exist.
Description Session auth, Replicator.create + addCollection, explicit allow-list of fourteen field collections (including tracking), omit local.tmp, "show source" push filters, optional per-collection channels: string[] (default empty), emp:{employeeId} on SG, document listener calls SetSyncState for pushed/push_error, pending-count fallback, foreground restart, duplicate-outbound reconcile (primaries only). Profile Settings / debug. Lab wss URL via env. Lab SG collection list lives in DESIGN.md.

PR-12 — Observability and FTS search chrome

Title feat: structured logs, metrics, and FTS search
Files src/log/logger.ts, src/metrics/index.ts, app/search/index.tsx
Deps PR-11
Description JSON logs without PII; latency histograms; FTS across notes/products/assets.

PR-14 — Chat / messages

Title feat: messages collection and job/direct chat
Files src/ops/messages.ts, app/(tabs)/chat.tsx, app/chat/[threadId].tsx
Deps PR-02 (collection); better after PR-05 so job threads have a woin
Description field.messages, msg:<ulid>, SendMessage with readyToPush: true and history[]. Job thr:wo:{woinId} and DM threads. Completing a WO does not freeze chat.

PR-15 — Orders, rates, taxes, field customers

Title feat: orders copy-on-write, rates/taxes catalogs, field customers
Files src/ops/orders.ts, src/ops/pricing.ts, src/ops/customers.ts, app/order/**
Deps PR-02; better after PR-06 so freeze/amendment UX is reused
Description Inbound orders pull-only; StartOrder / CreateOrder; PriceLines snapshots cents; freeze + amendment; CreateCustomer origin field. Do not mutate inbound orders or dispatch customers.

PR-13 — EE vector similarity (later)

Title feat: mobile-CLIP embeddings and gated vector search
Files src/embed/clip.ts, src/ops/similar.ts, app/search/similar.tsx, native module if RN plugin still lacks vector indexes
Deps PR-07, PR-12; blocked on vector API and native CLIP runtime
Description Persist embedding.clip512 (512 floats, never []) on commit photo when the model exists. Create vector index only when the API exists. Similarity UI behind VECTOR_SEARCH_ENABLED && nativeVectorApi. Do not fake ANN.

Merge notes