Splitting a Logistics Core for Web, Mobile, and Admin
A logistics company runs three ODC apps: a customer portal, a driver mobile app, and a back-office admin. All three reference a single Core module containing 140 screens, 400 server actions, and 80 entities. The driver app's cold start is 9 seconds, and 30% of driver actions fail on 3G. Core deploys weekly, and every deployment forces the mobile team to re-test and re-release because shared screens and actions change. The company has three squads and wants to split Core into 12 microservices. The mobile squad needs offline-tolerant proof-of-delivery capture, while the portal needs near-real-time shipment tracking. The admin squad owns billing and exception handling. The CTO wants independent releases within one quarter and a mobile p95 action time under 2 seconds on a 3G connection.
1. Diagnose why the single Core module harms mobile performance and deployment independence. Propose a decomposition that separates channel concerns from domain logic.
Read the worked answer
Core is not a domain module; it is a deployment unit that mixes channel UI, orchestration, and domain logic. The mobile app pays for 140 screens and their dependencies even when it uses a fraction, which inflates cold start. The 400 server actions are a flat namespace, so mobile calls are chatty and often fetch web-shaped payloads over 3G. Weekly Core deployments force mobile re-release because the contract is the module, not a versioned service.
I would decompose into thin channel apps plus domain service modules: Shipment, Route, Proof of Delivery, and Billing/Exceptions. Each channel gets a small orchestration layer or BFF that exposes only the actions and DTOs that channel needs; the driver BFF returns compact POD payloads and supports local queueing. Domain services own entities and publish versioned service actions; channels must not reference domain screens or entities. Shared code is limited to a design-system library and technical utilities.
This reduces mobile startup because the app no longer compiles web screens, and it enables independent deployment because channels depend on contracts, not on Core's deployment unit. Start with POD because it has a clear boundary and offline need.
2. The team wants one shared entity model across all channels to avoid duplication. Assess the trade-offs and recommend an approach for Shipment and Proof-of-Delivery data.
Read the worked answer
A shared entity model feels efficient but makes every channel and service couple to one schema. In ODC, exposing entities across modules turns database design into a public contract; a column rename or relationship change becomes an estate-wide regression. It also encourages screens to read data directly, bypassing domain rules such as POD signature validation or shipment state transitions. The trade-off is real: duplication costs mapping code and can create inconsistent terms.
I would make each domain service own its entities and expose DTOs through service actions. Shipment service owns shipment state and tracking events; POD service owns proof-of-delivery records and references shipment by ID, not by a shared entity. The portal reads a tracking read model; the mobile app writes POD through an idempotent service action and queues offline captures. Shared reference data, such as predefined exception reasons, can be a small public entity or static entity because it is stable. Use contract tests and a canonical glossary to prevent semantic drift, not a shared schema. Accept eventual consistency between POD and shipment status.
3. Design the first six-week slice and define acceptance criteria that prove decomposition works.
Read the worked answer
Slice: extract Proof of Delivery and a driver BFF. Week 1-2 define the POD contract, offline queue behavior, and idempotency key; weeks 3-4 build the POD service and BFF in ODC, with the existing Core still serving other functions; weeks 5-6 migrate the driver app and run a controlled pilot. Do not extract Billing in the same slice.
Acceptance criteria: driver app cold start reduced by at least 40%; p95 POD submit action under 2 seconds on a throttled 3G profile with 300 ms latency; 100% of offline captures eventually submitted exactly once; POD service deploys independently of Core at least twice during the slice; no channel references Core screens; contract tests pass for portal tracking and admin exception reads. Also measure rework: zero mobile re-releases caused by Core changes during the pilot.
If the BFF becomes a new god module, stop and split it by channel use case. The slice proves the pattern on the highest-pain, lowest-coupling capability before scaling.