Operations Domain (schema: operations) β
The execution layer handling real-world logistics, fleet assignments, hardware IoT integrations, offline app synchronization, and fulfillment validation.
β Hub: See domain-model.md for the bounded context map and cross-boundary integration surface.
Entity Relationship Diagram β
Cross-context references (soft FKs, not shown above):
SERVICE_LEGβ created from BackofficeTOUR_DEPARTUREviaTourDeparturePublishedevent (tour_departure_idsoft FK)LEG_ASSIGNMENTβ references BackofficeVEHICLEandCREW_MEMBERONBOARD_SALEβ billed to CommerceTICKET(seat reference)BOARDING_EVENTβ validates CommerceTICKETviaqr_hashEXPENSE_RECEIPTβ emitsExpenseSubmittedβ CommerceFINANCIAL_LEDGERONBOARD_SALEβ emitsOnboardSaleRecordedβ CommerceFINANCIAL_LEDGER
Entity Dictionary β
- ServiceLeg: The physical, continuous operation of a vehicle between an origin and destination. A single
TourDepartureconsists of multipleServiceLegs. Operations creates ServiceLegs when theTourDeparturePublishedevent arrives from Backoffice (see ADR-018). Carriestour_departure_id(soft FK to Backoffice),leg_typeenum (PICKUP,TRANSIT,TRANSFER,DROPOFF,REPOSITIONING), andactual_start/actual_endtimestamps for Soll/Ist comparison. APICKUP-typed ServiceLeg is the Operations-side representation of a BackofficeBoardingPoint(1:1) β see ADR-001. Lifecycle:SCHEDULEDβACTIVE(emitsServiceLegStarted) βCOMPLETED(emitsServiceLegCompleted) orDELAYED(emitsServiceLegDelayed) βCOMPLETED/CANCELLED(emitsServiceLegCancelled). DELAYED can recover to ACTIVE (emitsServiceLegDelayResolved). Full state machine with guards, actors, and cancellation resolution scenarios in schema-operations.md Β§ServiceLeg State Machine. - LegAssignment: The dispatching link tying a specific
ServiceLegto aVehicleand aCrewMember. Carriesstatus(CONFIRMED,RELEASED) andassigned_attimestamp for audit and multi-dispatcher conflict resolution. - CrewDutyLog: The immutable ledger recording driving and rest times. Carries
service_leg_id(nullable) to correlate duty events with active legs. Phase 1 uses only the single-timestamp model (log_time) for the 11h daily rest heuristic. Phase 2 will introduce aDutyActivityentity with duration-based logging (start_time,end_time,duration_minutes) and asource_typediscriminator (TOUR_LEG,LINE_ROUTE,CHARTER,TACHOGRAPH_IMPORT,SELF_DECLARATION) to decouple compliance evaluation from the tour-specificServiceLegpipeline.CrewDutyLogremains for operational correlation;DutyActivitysupersedes it as the compliance data source. Phase 2 reserves thetachograph_dataJSONB column for Gen-2 Smart Digital Tachograph IoT integration. See EU-561 research Β§6 for the full design intent. - TelemetryPoint: High-frequency GPS signals emitted by the vehicle. Carries
service_leg_id(nullable) to correlate position data with active legs. Phase 2 reservesfuel_levelfor future use. - RouteWaypoint: Planned geographical execution paths with ETA tracking. Carries
label(descriptive name, e.g., "KΓΆln Hbf") andwaypoint_typeenum (BOARDING_STOP,REST_AREA,WAYPOINT,BORDER_CROSSING).BOARDING_STOPwaypoints enable the Consumer ETA Tracking endpoint to show "ETA to your stop" β see event-contracts-operations.md Β§Consumer ETA Tracking. - IssueReport: The raw field log a
CrewMembercreates and ties to aVehicle. Captures any observed problem (e.g., cracked mirror, engine warning light). Status lifecycle:OPEN(driver submits) βIN_PROGRESS(Backoffice schedules aVehicleInspectionand emitsVehicleInspectionScheduled) βRESOLVED(Backoffice completes inspection and emitsVehicleInspectionCompleted). Whenmaintenance_urgency = IMMEDIATE, the system emitsVehicleMaintenanceRequiredβ Backoffice. An IssueReport does not automatically create an Incident β the dispatcher manually links IssueReports to Incidents via a join table when a vehicle observation escalates into an operational disruption. SupportsattachmentsJSONB for photographic evidence. - Incident: The operational disruption tied to a
ServiceLeg. Represents a logistical impact (delay, breakdown, passenger issue). Created by the driver from the Driver Hub, or auto-created by the system for telemetry-detected delays (see schema-operations.md Β§ServiceLeg State Machine ACTIVEβDELAYED). Lifecycle:OPEN(emitsIncidentCreatedwithseverityandtypein payload) βACKNOWLEDGED(dispatcher setsassigned_to) βIN_PROGRESS(dispatcher acting) βRESOLVED(setsresolved_at, emitsIncidentResolved).IncidentCreatedis the sole trigger for all passenger broadcasts β the Communications consumer routes uniformly by severity: CRITICAL (any type: DELAY, BREAKDOWN, PASSENGER_ISSUE) triggers proactive WhatsApp broadcast to downstream passengers (Journey 2); LOW/MEDIUM triggers dispatch board alert only. System-created DELAY Incidents carryreporter_crew_id=NULLandseverity=CRITICAL(ensures entry into the broadcast chain β dispatcher approval gate). BREAKDOWN incidents do NOT directly triggerVehicleMaintenanceRequiredβ vehicle maintenance is the responsibility ofIssueReport(see ADR-008). The Driver Hub prompts the driver to file an IssueReport alongside a BREAKDOWN incident. Carriesgeo_coordinatesfor the GPS pin location anddescriptionfor unstructured details. - OnboardSale: Point-of-Sale records managing the driver's cash box and dynamic upsells. Carries
sale_statuslifecycle:ACTIVEβVOIDED(driver or dispatcher cancels before end-of-day, emitsOnboardSaleVoided) /REFUNDED(role-gated, emitsOnboardSaleRefunded). Trackscrew_member_id(the seller),payment_method(CASH,PAYMENT_LINK,CARD_READER), andquantity. Supports digital payments viapayment_status(PAID,PENDING_LINK,FAILED) andcheckout_session_id(soft FK to Commerce CheckoutSession for Magic Link flow). PENDING_LINK sales require connectivity β the driver app disables payment link creation when offline. Cash sales operate fully offline. Voiding and refunding create GoBD-compliant counter-entries viachange_events(scope = GOBD). On sync, emitsOnboardSaleRecordedβ Commerce FinancialLedger forrealized_expenseaggregation whenpayment_status = PAID. Refund authorization is payment-method-scoped:CASHrefunds are available to any user with sufficient permissions (MANAGER, DISPATCHER, or DRIVER withcan_refund_onboard_salegrant withindriver_cash_refund_limit), supporting owner-operators who drive themselves.PAYMENT_LINK/CARD_READERrefunds require MANAGER or DISPATCHER role (crosses into Commerce for Mollie refund API). Feature gap: four-eyes refund approval workflow deferred to Phase 2. - ExpenseReceipt: AI-parsed OCR data capturing actual operational costs (fuel, tolls, parking) incurred during a
ServiceLeg. Carriesreceipt_image_keyfor the uploaded photo (storage key, not URL) andocr_dataJSONB for extracted fields. Includesnet_amount,vat_amount, andvat_rate(default 0, populated by OCR, verified by dispatcher) for DATEV-compliant accounting. OCR pipeline:PENDING(driver uploads photo) βPARSED(BullMQ OCR worker extracts data via AI service) βVERIFIED(dispatcher approves, emitsExpenseSubmittedβ Commerce FinancialLedger) orREJECTED(terminal state β dispatcher rejects withrejection_reason, driver creates a newExpenseReceiptrow withreplaces_receipt_idlinking to the rejected original). - BoardingEvent: Records the QR scan check-in of a passenger during boarding. References
ticket_id(soft FK to CommerceTicket) and capturescheck_in_status(SUCCESS,INVALID,ALREADY_SCANNED,MANUAL_OVERRIDE),qr_hash, and physical baggage metrics. Carriesexpected_service_leg_idwhen the system usesMANUAL_OVERRIDE(wrong-stop boarding β preserves the audit trail of where the system expected the passenger to board vs. where they actually boarded). The driver app validates QR codes offline against a cached manifest with 5 sequential checks β see schema-operations.md Β§Offline Validation Rules. Per-passenger scanning enables accurateBookingNoShowdetection perTicket, not perBooking. This entity replaces the previous ambiguous Ticket dual-ownership β Commerce owns theTicket, Operations owns theBoardingEvent.
Offline Sync & Compliance Strategy β
- Offline Conflict Resolution: The Driver Hub (PWA) uses an aggressive offline-caching strategy (IndexedDB/RxDB) providing read-isolated clones of the dispatch manifest. The architecture uses a "Server Wins (Delta Driven)" sync mechanism when the system restores the connection, generating
change_eventsserver-side on receipt of synced records. The client sends raw mutations with client-generatedidempotency_keyUUIDs; the server deduplicates via thesync_idempotency_logtable. See offline-sync-protocol.md for the full protocol specification including queue structure, sync API contract, batch semantics, and connectivity detection. - Compliance Rules Boundary (EU-561/2006): Complex compliance evaluations (e.g., matching driving hours with EU requirements) intentionally do not occur in the operations physical database schema.
CrewDutyLogpersists the raw events. In Phase 2, a statelessComplianceEvaluatordomain service in Backoffice will consumeDutyActivityrecords (source-agnostic: tours, scheduled routes, chartering, tachograph imports) and produce per-driverComplianceStatus(remaining driving budget, rest deficit, violation flags) injected back to the dispatch board asynchronously. This design ensures EU-561 evaluation is reusable across all business areas without coupling to theServiceLegβTourDeparturepipeline. See EU-561 research Β§6.
Aggregates β
Each aggregate defines a transactional consistency boundary. Cross-aggregate references follow ADR-036.
ServiceLeg β
| Role | Entity |
|---|---|
| Root | ServiceLeg |
| Child | LegAssignment |
Invariants: Status state machine: SCHEDULED β ACTIVE β DELAYED β COMPLETED / CANCELLED. Terminal states: COMPLETED and CANCELLED. Delay hysteresis prevents notification spam. LegAssignment unique: one crew member per leg. LegAssignment CHECK: internal (vehicle + crew) or external (supplier), never mixed. Events: ServiceLegStarted, ServiceLegCompleted, ServiceLegDelayed, ServiceLegDelayResolved, ServiceLegCancelled, VehicleSwapped.
RouteWaypoint is an infrastructure entity (ETA read-model projection), not a child of ServiceLeg. The ETA recalculation service updates
route_waypoints.etaevery 30 seconds, bypassing the domain model. The ServiceLeg factory creates waypoints at leg creation; subsequent ETA updates are projections.
Incident β
Single-entity aggregate. Operational disruption tied to a ServiceLeg.
Invariants: Status: OPEN β ACKNOWLEDGED β IN_PROGRESS β RESOLVED. Concurrent take-over protected by SELECT ... FOR UPDATE. System-created incidents (reporter_crew_id = NULL) can auto-resolve on delay recovery. Events: IncidentCreated, IncidentResolved. Cross-aggregate refs: service_leg_id (hard FK β stable, leg never deleted).
incident_issue_reportsis a cross-aggregate join table between Incident and IssueReport, managed by thelinkIssueReportToIncidentdomain service. It is not a child of either aggregate.
IssueReport β
Single-entity aggregate. Field log tied to a Vehicle.
Invariants: Status: OPEN β IN_PROGRESS β RESOLVED. Cross-context maintenance feedback loop (Operations β Backoffice β Operations). Events: IssueReportCreated, VehicleMaintenanceRequired.
ExpenseReceipt β
Single-entity aggregate. AI-parsed OCR receipt for operational costs.
Invariants: OCR pipeline: PENDING β PARSED β VERIFIED / REJECTED. REJECTED is terminal β driver creates a new row with replaces_receipt_id. Events: ExpenseSubmitted. Cross-aggregate refs: service_leg_id (hard FK β stable).
OnboardSale β
Single-entity aggregate. Driver POS record.
Invariants: Sale: ACTIVE β VOIDED / REFUNDED. Payment: PAID / PENDING_LINK / FAILED. GoBD-compliant counter-entries on void/refund. Cash refund authorization role-gated. Events: OnboardSaleRecorded, OnboardSaleVoided, OnboardSaleRefunded. Cross-aggregate refs: service_leg_id (hard FK β stable).
BoardingEvent β
Single-entity aggregate. QR scan check-in record.
Invariants: Immutable after creation. check_in_status: SUCCESS, INVALID, ALREADY_SCANNED, MANUAL_OVERRIDE. Offline validation against cached manifest. Events: BoardingConflictDetected. Cross-aggregate refs: service_leg_id (hard FK β stable).
Infrastructure Entities (not aggregates) β
change_events, sync_idempotency_log, telemetry_points (high-frequency ingestion, partitioned), crew_duty_logs (raw event ledger), route_waypoints (ETA read-model projection), incident_issue_reports (cross-aggregate join table).