Skip to content

TMS v2 — system overview ​

One picture of TMS v2 as it stands on 11 Nov 2026: what the system does, its parts, which module owns what, and how far the build has come. The code facts come from bigc-tms-core-v2 branch main-v2-prototype at commit 3d70475a. The design facts come from the seven module designs in the discovery workspace. For the per-feature status, see 01-feature-list.md.

What the system does ​

TMS (transport management system) delivers BigC customer orders from a store to the customer's door.

  1. BigC's order system (OMS) sends each order over Kafka; TMS turns it into a delivery order (DO) for the store that ships it.
  2. Each day an ops admin plans one store's waiting orders into vehicle routes with Google Route Optimization, adjusts them by hand, and turns each route into a driver task.
  3. The driver runs the task in the driver app: load at the store, deliver stop by stop with proof of delivery, collect cash on delivery (COD), report failed attempts, return undelivered goods.
  4. The store takes the driver's cash per task; ops follow open cash, holds and overdue tasks.
  5. Every DO change is sent back to OMS and to BigC's staff app over Kafka, and every change is kept as history.
  6. v2 is a ground-up NestJS rewrite of v1 (which was built on the internal cc-core-lib framework). Stores will move from v1 to v2 one at a time.

Components ​

componentwhat it isstate
core-v2 (bigc-tms-core-v2)NestJS backend: REST API, Kafka consumer and producer, job workers, schedule tick. Every pod runs all of themprototype on main-v2-prototype; 28 modules, 26 with code that runs
store-v2 (bigc-tms-store-v2)Next.js admin. Its own API routes (login, revoke, entity CRUD, settings, template preview, Kafka test) proxy to core-v2, so the browser never calls core directlyprototype; built alongside core
Driver app v2Mobile app for driversnot started; v1 driver app is the reference; the backend endpoints it needs are designed, not built
MongoDBOne database for every v2 stack; business writes use transactions so a change, its history row and its outbound event commit togetherin use
RedisLogin sessions (one key per token) and the Bull queue for jobs that may be lostin use
Kafka / OMSInbound orders from OMS; outbound DO updates to OMS and the staff app, routed by sales channelin use (one inbound topic, two outbound topics)
GoogleRoute Optimization API for planning; Maps key handed to the adminin use
S3Files and photos, uploaded straight from the client with a presigned URL; a sweeper removes unconfirmed uploadsin use

Module map ​

Each core-v2 module owns the collections it writes; others call its service. Calls go one way: business modules call platform modules, platform modules call common. One known wrong-way link remains: the login guard in common uses the application module; it is left for the auth work.

Business modules

moduleowns (collections)talks tostate
delivery_orderdelivery_order, delivery_order_version (outbound version counter)store, activity_log, jobs (outbox), kafka (consumer registration), script_runnerprototype
delivery_order_itemdelivery_order_itemdelivery_order, script_runnerprototype
delivery_order_revisiondelivery_order_revision (reschedule trail)none yetschema and service only, not called
planplan (with routes, stops and unassigned list inside)delivery_order, plan_template, store, vehicle_type, plan_history, google, script_runnerprototype
plan_historyplan_historyactivity_logprototype
plan_templateplan_templatenoneprototype
tasktask (number only)nonestub
storestorescript_runnerprototype
vehiclevehiclevehicle_type, script_runnerprototype
vehicle_typevehicle_typenoneprototype
useruseractivity_log, script_runnerprototype
authsessions in Redis (no collection)application, device, user, settingsprototype; security fixes open
applicationapplication (API clients)noneprototype
devicedevicenoneprototype

Platform modules

moduleowns (collections)talks tostate
jobsjobs, job_partitions, job workers, job countersRedis (Bull) for the lossy lanebuilt
schedulesschedulesjobsbuilt; no business schedule declared
kafkakafka_consumed (7-day dedupe), kafka consume dead letters, kafka_logjobs, log, settingsbuilt
settingssettingsnone (others read it)built
storage_settingan encrypted entry in settingssettingsbuilt
logthe log base: expiry indexes, retention setting, writerssettingsbuilt
activity_logactivity_logs (history of every record)log, settingsbuilt
attachmentattachmentstorage_setting, S3built
googlegoogle_loglog, settings, Google APIsbuilt
script_runnernone (sandboxed data scripts; a registry of entities scripts may read)settingsbuilt
template, template_enginetemplatescript_runnerbuilt
export_config, field_catalogexport_config; field catalog has no collectionscript_runnerbuilt; running an export is not

Designed modules with no code yet (from the module designs)

modulewill ownwill talk to
intake (on top of delivery_order)intake_message (parked orders), ops_follow_up, channel, Kafka mapping versionsdelivery_order, store, channel, platform versioned config
executiontask (full), stop, visit record per task and DO, proof of delivery, attempt, hold, GPS points, failure reasonsplan, delivery_order, workforce, cod-payment, attachment, jobs
cod-paymentCOD fields on the DO, cash handover, handover adjustment, short-handover reasonsexecution, staff PIN, store settings
workforcedriver, partner, booking, duty record, leave, break reasonsuser, vehicle, planning
admin-reportingexport runs, import runs, roles and permissionsevery module (read), jobs

Build order ​

Seven phases, approved on 29 Oct. Phases 2 and 3 can run side by side after phase 1; phase 7 starts after phase 2 and ends after phase 6. Sizes are relative.

phasemoduleswhat works at the endsizestate today
1platformLogin without today's security gaps; every event, email and job saved with its business change and retried; one history table; files straight to S3; notificationsLIn progress. Done: jobs engine, schedules, Kafka outbox, history, typed settings, log retention, trace id, S3 files. Open: token lifetime, revoke and password hashing fixes; refresh tokens and lockout; email sending. Roles and permissions as data: designed, build about to start
2intake + mastersStores and channels; Kafka orders become DOs within 5 s, each message applied once, unknown-store orders parked and replayable; cancel and redelivery rules; admin create and Excel importMStarted in the prototype, ahead of phase 1 finishing. Done: DO and item REST, Kafka intake applied once, store master, DO updates out. Open: routing rules, parking, cancel, redelivery, channel master, Excel import, mapping versions
3workforceDrivers, vehicles (unique plate), partners, leave; bookings; duty record with clock-in and out, break, hold; day closeLNot started. Only users, devices, vehicles and vehicle types exist
4planningOne chosen plan per store and date; optimisation as a job; hand edits; generate tasks in one all-or-nothing step; add an order to a route not yet startedLPrototype exists, ahead of order. Done: plan from template, Google optimisation, move, assign, unassign, pins, history. Open: seven plan states, variants, claim at generate, optimisation as a job, task generation (endpoint is a stub)
5execution + COD collectionThe driver's run end to end, COD in the delivery step, failed attempt to hold, return and close-out, GPS trail, audited ops correctionsLNot started (task record is a stub; driver app v2 not started)
6COD handoverCashier PIN of the task's store; one handover per task with shortage reason; ops list of open cash; optional dispatch blockMNot started
7admin-reportingAdmin menus; reports on live data (up to 31 days, first page in 2 s); the import and export configs ops still use; roles with partner scopeMFoundations only. Done: templates (print, email, SMS render), export configs, field catalog, data script sandbox. Open: running exports, imports, reports, permission per endpoint, partner scope

Before each phase starts, what is already on main-v2-prototype is read and reused, not rebuilt. Each phase also waits on BigC rules that touch it (18 are still open, listed in workscope.md § "Rules BigC must confirm").

Where code and design differ today ​

These are the gaps a reader is most likely to trip over when comparing the prototype with the design.

topiccode todaydesign
DO status namesv1-style: PENDING, PLANNED, IN_TRANSIT, DELIVERED, FAILED, CANCELLEDv2 names: UNASSIGNED, ASSIGNED, DISPATCHED, OUT_FOR_DELIVERY, HOLD, DELIVERED, FAILED_DELIVERY, CANCELLED, with a fixed move table
Plan states3 (pending, planned, generated)7 (adds optimising, failed, generating, cancelled)
Optimisationruns inside the HTTP requestruns as a background job that answers at once
Generate tasksendpoint returns success and does nothingone transaction per route: task, stops, totals, orders ASSIGNED
Order claimnone; optimise reads PENDING orders of the store and dateclaimed only at generate, with a conditional write
Unknown store on an orderthe message fails and is dead-letteredthe order is parked with its payload and can be replayed
Outbound channel listsfixed in code (OMS: DONJAI, CHOKCHAI, HLH; staff app: SPO, OD, HLH)configuration
Load, task and driver Kafka topicsevent names still declared in code, never sentnot built; PROD never had them
DO linesREST allows create, update and deleteDO lines are transactional and change only through intake and execution commands
Vehicle platenot uniqueunique plate
Auth1-year tokens, revoke accepts any token, SHA-256 hash salted with the creation date, role check by a fixed role listshort-lived access token plus rotating refresh token, lockout, stronger hash, roles as data with permission keys
Postal-code zonesnoneplanning design retires them; a later decision moves them into a v2 zoning design that is not written yet