Busflow Docs

Internal documentation portal

Skip to content
Reviewed 17 May 2026

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 ​

100%

Cross-context references (soft FKs, not shown above):

  • SERVICE_LEG ← created from Backoffice TOUR_DEPARTURE via TourDeparturePublished event (tour_departure_id soft FK)
  • LEG_ASSIGNMENT β†’ references Backoffice VEHICLE and CREW_MEMBER
  • ONBOARD_SALE β†’ billed to Commerce TICKET (seat reference)
  • BOARDING_EVENT β†’ validates Commerce TICKET via qr_hash
  • EXPENSE_RECEIPT β†’ emits ExpenseSubmitted β†’ Commerce FINANCIAL_LEDGER
  • ONBOARD_SALE β†’ emits OnboardSaleRecorded β†’ Commerce FINANCIAL_LEDGER

Entity Dictionary ​

  • ServiceLeg: The physical, continuous operation of a vehicle between an origin and destination. A single TourDeparture consists of multiple ServiceLegs. Operations creates ServiceLegs when the TourDeparturePublished event arrives from Backoffice (see ADR-018). Carries tour_departure_id (soft FK to Backoffice), leg_type enum (PICKUP, TRANSIT, TRANSFER, DROPOFF, REPOSITIONING), and actual_start/actual_end timestamps for Soll/Ist comparison. A PICKUP-typed ServiceLeg is the Operations-side representation of a Backoffice BoardingPoint (1:1) β€” see ADR-001. Lifecycle: SCHEDULED β†’ ACTIVE (emits ServiceLegStarted) β†’ COMPLETED (emits ServiceLegCompleted) or DELAYED (emits ServiceLegDelayed) β†’ COMPLETED/CANCELLED (emits ServiceLegCancelled). DELAYED can recover to ACTIVE (emits ServiceLegDelayResolved). Full state machine with guards, actors, and cancellation resolution scenarios in schema-operations.md Β§ServiceLeg State Machine.
  • LegAssignment: The dispatching link tying a specific ServiceLeg to a Vehicle and a CrewMember. Carries status (CONFIRMED, RELEASED) and assigned_at timestamp 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 a DutyActivity entity with duration-based logging (start_time, end_time, duration_minutes) and a source_type discriminator (TOUR_LEG, LINE_ROUTE, CHARTER, TACHOGRAPH_IMPORT, SELF_DECLARATION) to decouple compliance evaluation from the tour-specific ServiceLeg pipeline. CrewDutyLog remains for operational correlation; DutyActivity supersedes it as the compliance data source. Phase 2 reserves the tachograph_data JSONB 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 reserves fuel_level for future use.
  • RouteWaypoint: Planned geographical execution paths with ETA tracking. Carries label (descriptive name, e.g., "KΓΆln Hbf") and waypoint_type enum (BOARDING_STOP, REST_AREA, WAYPOINT, BORDER_CROSSING). BOARDING_STOP waypoints 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 CrewMember creates and ties to a Vehicle. Captures any observed problem (e.g., cracked mirror, engine warning light). Status lifecycle: OPEN (driver submits) β†’ IN_PROGRESS (Backoffice schedules a VehicleInspection and emits VehicleInspectionScheduled) β†’ RESOLVED (Backoffice completes inspection and emits VehicleInspectionCompleted). When maintenance_urgency = IMMEDIATE, the system emits VehicleMaintenanceRequired β†’ 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. Supports attachments JSONB 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 (emits IncidentCreated with severity and type in payload) β†’ ACKNOWLEDGED (dispatcher sets assigned_to) β†’ IN_PROGRESS (dispatcher acting) β†’ RESOLVED (sets resolved_at, emits IncidentResolved). IncidentCreated is 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 carry reporter_crew_id=NULL and severity=CRITICAL (ensures entry into the broadcast chain β†’ dispatcher approval gate). BREAKDOWN incidents do NOT directly trigger VehicleMaintenanceRequired β€” vehicle maintenance is the responsibility of IssueReport (see ADR-008). The Driver Hub prompts the driver to file an IssueReport alongside a BREAKDOWN incident. Carries geo_coordinates for the GPS pin location and description for unstructured details.
  • OnboardSale: Point-of-Sale records managing the driver's cash box and dynamic upsells. Carries sale_status lifecycle: ACTIVE β†’ VOIDED (driver or dispatcher cancels before end-of-day, emits OnboardSaleVoided) / REFUNDED (role-gated, emits OnboardSaleRefunded). Tracks crew_member_id (the seller), payment_method (CASH, PAYMENT_LINK, CARD_READER), and quantity. Supports digital payments via payment_status (PAID, PENDING_LINK, FAILED) and checkout_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 via change_events (scope = GOBD). On sync, emits OnboardSaleRecorded β†’ Commerce FinancialLedger for realized_expense aggregation when payment_status = PAID. Refund authorization is payment-method-scoped: CASH refunds are available to any user with sufficient permissions (MANAGER, DISPATCHER, or DRIVER with can_refund_onboard_sale grant within driver_cash_refund_limit), supporting owner-operators who drive themselves. PAYMENT_LINK/CARD_READER refunds 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. Carries receipt_image_key for the uploaded photo (storage key, not URL) and ocr_data JSONB for extracted fields. Includes net_amount, vat_amount, and vat_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, emits ExpenseSubmitted β†’ Commerce FinancialLedger) or REJECTED (terminal state β€” dispatcher rejects with rejection_reason, driver creates a new ExpenseReceipt row with replaces_receipt_id linking to the rejected original).
  • BoardingEvent: Records the QR scan check-in of a passenger during boarding. References ticket_id (soft FK to Commerce Ticket) and captures check_in_status (SUCCESS, INVALID, ALREADY_SCANNED, MANUAL_OVERRIDE), qr_hash, and physical baggage metrics. Carries expected_service_leg_id when the system uses MANUAL_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 accurate BookingNoShow detection per Ticket, not per Booking. This entity replaces the previous ambiguous Ticket dual-ownership β€” Commerce owns the Ticket, Operations owns the BoardingEvent.

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_events server-side on receipt of synced records. The client sends raw mutations with client-generated idempotency_key UUIDs; the server deduplicates via the sync_idempotency_log table. 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. CrewDutyLog persists the raw events. In Phase 2, a stateless ComplianceEvaluator domain service in Backoffice will consume DutyActivity records (source-agnostic: tours, scheduled routes, chartering, tachograph imports) and produce per-driver ComplianceStatus (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 the ServiceLeg β†’ TourDeparture pipeline. See EU-561 research Β§6.

Aggregates ​

Each aggregate defines a transactional consistency boundary. Cross-aggregate references follow ADR-036.

ServiceLeg ​

RoleEntity
RootServiceLeg
ChildLegAssignment

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.eta every 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_reports is a cross-aggregate join table between Incident and IssueReport, managed by the linkIssueReportToIncident domain 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).

Internal documentation β€” Busflow