Bounded Context: Driver Management (DRV)

Responsibility: Driver onboarding, identity and background verification, vehicle registration with document expiry, availability toggling, ratings, operator-reviewed suspension, and appeal lifecycle.


Context Map

Relation Other Bounded Context Position Pattern Description
DRV → RideManagement Ride Management (RIDE) upstream Open Host Service (OHS) DRV exposes match-eligible online drivers with their current location (REQ-DRV-032) for matching. RIDE is the dominant consumer.
DRV ↔ RideManagement Ride Management (RIDE) downstream Customer/Supplier DRV consumes RideCompleted (carrying driverRating) and DriverNoShowRecorded from RIDE; bridged into SubmitRating and into suspension-proposal context.
DRV → GeolocationRouting Geolocation & Routing (GEO) downstream Anti-Corruption Layer (ACL) DRV consumes DriverPositionStale from GEO through an ACL and translates it into GoOffline(reason=stalePosition).
DRV → IdentityVerificationProvider external (certified third party) downstream Conformist (infrastructure) DRV depends on a certified third-party for identity and background verification. Wrapped behind the IdentityVerificationProvider infrastructure-service; SLA bounded by REQ-DRV-NFR-001.
DRV → DocumentStorage external infrastructure downstream Conformist (infrastructure) Encrypted document store wrapped behind DocumentStorageService; meets REQ-DRV-NFR-002 and REQ-DRV-NFR-003.
DRV → DriverNotification external infrastructure downstream Conformist (infrastructure) Push, SMS, and email channels wrapped behind DriverNotificationService for status updates, warnings, and appeal outcomes.

Enums

VerificationState

  • Values: pendingVerification, verified, rejected, suspended, appealInReview, permanentlySuspended.
  • Realizes: REQ-DRV-001, REQ-DRV-003, REQ-DRV-004, REQ-DRV-005, REQ-DRV-006, REQ-DRV-033, REQ-DRV-048, REQ-DRV-049.

AvailabilityState

  • Values: offline, online.
  • Realizes: REQ-DRV-030, REQ-DRV-031, REQ-DRV-032, REQ-DRV-034.

DocumentType

  • Values: driversLicence, passport, nationalId, selfie.
  • Realizes: REQ-DRV-002.

BackgroundCheckResult

  • Values: clear, failed.
  • Realizes: REQ-DRV-005, REQ-DRV-006.

OfflineReason

  • Values: voluntary, stalePosition, suspension, documentExpired.
  • Realizes: REQ-DRV-031, REQ-DRV-034, REQ-DRV-022.

AppealOutcome

  • Values: reinstated, permanentlySuspended.
  • Realizes: REQ-DRV-049.

NotificationChannel

  • Values: email, sms, push.
  • Realizes: REQ-DRV-008.

Value Types

EmailAddress

  • Fields:
    • value: String — format(email)
  • Realizes: REQ-DRV-001 (driver contact).

PhoneNumber

  • Fields:
    • countryCode: String
    • number: String
  • Realizes: REQ-DRV-001 (driver contact).

FullName

  • Fields:
    • firstName: String — maxLength(100)
    • lastName: String — maxLength(100)
  • Realizes: REQ-DRV-001.

Rating

  • Fields:
    • value: Integer — min(1), max(5)
  • Realizes: REQ-DRV-040, REQ-DRV-041.

AverageRating

Running aggregate of ratings for a driver.

  • Fields:
    • value: Decimal — min(1.0), max(5.0)
    • totalRatings: Integer — min(0)
    • ratingSum: Integer — min(0)
  • Invariants:
    • consistentAggregate: when totalRatings > 0, value = ratingSum / totalRatings — enforcement: reject.
  • Realizes: REQ-DRV-040, REQ-DRV-041, REQ-DRV-042.

VehicleDetails

  • Fields:
    • make: String
    • model: String
    • year: Integer — min(1990)
    • color: String
    • licencePlate: String
  • Realizes: REQ-DRV-020.

InspectionResult

  • Fields:
    • passed: Boolean
    • inspectedAt: DateTime
    • expiresAt: DateTime
    • partner: String
  • Invariants:
    • expiryAfterInspection: expiresAt > inspectedAt.
  • Realizes: REQ-DRV-021, REQ-DRV-022.

AppealDetails

  • Fields:
    • reason: String — maxLength(2000)
    • submittedAt: DateTime
  • Realizes: REQ-DRV-047, REQ-DRV-048.

AppealResolution

  • Fields:
    • outcome: AppealOutcome
    • operatorId: UUID
    • resolvedAt: DateTime
    • justification: String — maxLength(2000)
  • Realizes: REQ-DRV-049, REQ-DRV-NFR-005.

Entities

IdentityDocument

Driver-provided identity, licence, or selfie.

  • Identifier: documentId : UUID
  • Fields:
    • driverId: UUID
    • documentType: DocumentType
    • documentNumber: String
    • storageRef: String
    • uploadedAt: DateTime
    • expiresAt: DateTime optional
    • verified: Boolean — default false
  • Operations:
    • Upload identity document on command UploadIdentityDocument
      • Realizes: REQ-DRV-002
      • State changes (sets): driverId, documentType, documentNumber, storageRef, expiresAt from the command; uploadedAt = now().
      • Emits: IdentityDocumentUploaded with documentId, driverId, documentType, uploadedAt.
  • Realizes: REQ-DRV-002, REQ-DRV-NFR-002, REQ-DRV-NFR-003.

Vehicle

Driver vehicle with documents and inspection state.

  • Identifier: vehicleId : UUID
  • Fields:
    • driverId: UUID
    • details: VehicleDetails
    • registrationExpiresAt: DateTime
    • insuranceExpiresAt: DateTime
    • inspection: InspectionResult
    • eligible: Boolean — default false
    • registeredAt: DateTime
  • Invariants:
    • eligibilityRequiresValidDocs: when eligible = true, inspection.passed = true and inspection.expiresAt > now() and registrationExpiresAt > now() and insuranceExpiresAt > now() — enforcement: reject.
  • Operations:
    • Register vehicle on command RegisterVehicle
      • Realizes: REQ-DRV-020
      • State changes (sets): driverId, details, registrationExpiresAt, insuranceExpiresAt from the command; registeredAt = now(); eligible = false.
      • Emits: VehicleRegistered with vehicleId, driverId, registeredAt.
    • Record inspection result on command RecordVehicleInspection
      • Realizes: REQ-DRV-020, REQ-DRV-021
      • State changes: inspection = recordVehicleInspection.inspection; eligible = inspection.passed and inspection.expiresAt > now() and Vehicle.registrationExpiresAt > now() and Vehicle.insuranceExpiresAt > now().
      • Emits: VehicleInspectionRecorded with vehicleId, passed, eligibleNow.
    • Mark vehicle ineligible due to expired document on command MarkVehicleIneligible
      • Realizes: REQ-DRV-022, REQ-DRV-023
      • Precondition documentExpired: Vehicle.registrationExpiresAt <= now() or Vehicle.insuranceExpiresAt <= now() or Vehicle.inspection.expiresAt <= now().
      • State change: eligible = false.
      • Emits: VehicleBecameIneligible with vehicleId, driverId, reason, detectedAt = now().
  • Realizes: REQ-DRV-020, REQ-DRV-021, REQ-DRV-022, REQ-DRV-023.

Driver

Driver lifecycle root — verification, availability, ratings, appeals.

  • Identifier: driverId : UUID
  • Fields:
    • fullName: FullName
    • email: EmailAddress
    • phone: PhoneNumber
    • verificationState: VerificationState — default pendingVerification
    • availability: AvailabilityState — default offline
    • selectedVehicleId: UUID optional
    • averageRating: AverageRating optional
    • totalRidesCompleted: Integer — min(0), default 0
    • cancellationCountWindow: Integer — min(0), default 0
    • noShowCountWindow: Integer — min(0), default 0
    • appeal: AppealDetails optional
    • appealResolution: AppealResolution optional
    • registeredAt: DateTime
  • Invariants:
    • singleVehicleSelected: selectedVehicleId is null or count(selectedVehicleId) = 1 — enforcement: reject.
    • verifiedHasNoOpenAppeal: when verificationState = verified, appeal is null — enforcement: alert.
  • Operations:
    • Register driver on command RegisterDriver
      • Realizes: REQ-DRV-001
      • State changes: fullName, email, phone from the command; verificationState = pendingVerification; availability = offline; registeredAt = now().
      • Emits: DriverRegistered with driverId, registeredAt.
    • Complete background check on command CompleteBackgroundCheck
      • Realizes: REQ-DRV-005
      • Preconditions:
        • awaitingVerification: Driver.verificationState = pendingVerification
        • resultIsClear: completeBackgroundCheck.result = clear
      • State change: verificationState = verified.
      • Emits: DriverVerified with driverId, verifiedAt = now().
    • Reject driver application on command RejectDriverApplication
      • Realizes: REQ-DRV-006
      • Precondition awaitingVerification: Driver.verificationState = pendingVerification.
      • State change: verificationState = rejected.
      • Emits: DriverApplicationRejected with driverId, reason, rejectedAt = now().
    • Go online on command GoOnline
      • Realizes: REQ-DRV-030, REQ-DRV-032, REQ-DRV-033, REQ-DRV-NFR-004
      • Preconditions:
        • isVerified: Driver.verificationState = verified
        • notSuspended: Driver.verificationState != suspended
        • hasEligibleVehicle: Driver.selectedVehicleId is defined
      • State change: availability = online.
      • Emits: DriverWentOnline with driverId, selectedVehicleId, onlineAt = now().
    • Go offline on command GoOffline
      • Realizes: REQ-DRV-031
      • Precondition wasOnline: Driver.availability = online.
      • State change: availability = offline.
      • Emits: DriverWentOffline with driverId, reason, offlineAt = now().
    • Submit rating on command SubmitRating
      • Realizes: REQ-DRV-040, REQ-DRV-041, REQ-DRV-042
      • Precondition validRange: submitRating.rating.value >= 1 and submitRating.rating.value <= 5.
      • State changes: averageRating = recompute(Driver.averageRating, submitRating.rating); totalRidesCompleted = Driver.totalRidesCompleted + 1.
      • Emits: RatingSubmitted with driverId, rating, newAverage, totalRides, submittedAt = now().
    • Issue rating warning on command IssueRatingWarning
      • Realizes: REQ-DRV-043
      • Preconditions:
        • matureDriver: Driver.totalRidesCompleted > 20
        • belowWarningThreshold: Driver.averageRating.value < 4.2
      • Emits: RatingWarningIssued with driverId, averageRating, issuedAt = now().
    • Propose suspension on command ProposeSuspension
      • Realizes: REQ-DRV-044, REQ-DRV-046
      • Preconditions:
        • matureDriver: Driver.totalRidesCompleted > 20
        • belowSuspensionThreshold: Driver.averageRating.value < 4.0
      • Emits: SuspensionProposalCreated with driverId, averageRating, cancellationCount, noShowCount, proposedAt = now().
    • Suspend driver on command SuspendDriver
      • Realizes: REQ-DRV-044, REQ-DRV-045, REQ-DRV-046, REQ-DRV-NFR-005
      • Precondition operatorApproved: suspendDriver.operatorId is defined.
      • State changes: verificationState = suspended; availability = offline.
      • Emits: DriverSuspended with driverId, operatorId, reason, duration (Duration), suspendedAt = now().
    • Submit suspension appeal on command SubmitAppeal
      • Realizes: REQ-DRV-047, REQ-DRV-048
      • Precondition isSuspended: Driver.verificationState = suspended.
      • State changes: verificationState = appealInReview; appeal = AppealDetails(reason = submitAppeal.reason, submittedAt = now()).
      • Emits: AppealSubmitted with driverId, submittedAt = now().
    • Resolve appeal on command ResolveAppeal
      • Realizes: REQ-DRV-049, REQ-DRV-NFR-005
      • Precondition appealUnderReview: Driver.verificationState = appealInReview.
      • State changes: verificationState = if resolveAppeal.outcome = reinstated then verified else permanentlySuspended; appealResolution = AppealResolution(outcome, operatorId, resolvedAt = now(), justification); appeal = null.
      • Emits: AppealResolved with driverId, outcome, operatorId, resolvedAt = now().
  • Realizes: REQ-DRV-001, REQ-DRV-003, REQ-DRV-004, REQ-DRV-005, REQ-DRV-006, REQ-DRV-030, REQ-DRV-031, REQ-DRV-032, REQ-DRV-033, REQ-DRV-040, REQ-DRV-043, REQ-DRV-044, REQ-DRV-046, REQ-DRV-047, REQ-DRV-048, REQ-DRV-049.

Aggregates

DriverAggregate

  • Root: Driver
  • Contains: Vehicle, IdentityDocument
  • Boundary intent: consistency for driver state, vehicle eligibility, and document attachment is enforced inside this aggregate. Cross-aggregate effects (rating bridge from RIDE, stale-position from GEO) are mediated through reactions.

State Machines

DriverLifecycle on Driver

  • Start state: pendingVerification
  • States:
    • pendingVerification — state-scoped invariant noRidesYet: Driver.totalRidesCompleted = 0
    • verified — no extra invariants beyond the entity-level verifiedHasNoOpenAppeal
    • rejected — final
    • suspended — state-scoped invariant offlineWhileSuspended: Driver.availability = offline
    • appealInReview — driver awaits operator decision
    • permanentlySuspended — final
  • Transitions:
    • pendingVerificationverified on command CompleteBackgroundCheck
    • pendingVerificationrejected on command RejectDriverApplication
    • verifiedsuspended on command SuspendDriver
    • suspendedappealInReview on command SubmitAppeal
    • appealInReviewverified on command ResolveAppeal (when outcome = reinstated)
    • appealInReviewpermanentlySuspended on command ResolveAppeal (when outcome = permanentlySuspended)
  • Final states: rejected, permanentlySuspended.

The state-scoped invariants are conjoined with the entity-level invariants. offlineWhileSuspended together with the notSuspended precondition on GoOnline realizes REQ-DRV-033. noRidesYet together with the isVerified precondition on GoOnline realizes REQ-DRV-004.


Domain Services

DocumentExpiryChecker

Detects upcoming or expired documents and triggers the ineligibility path.

  • Operations:
    • checkDocumentExpiry(now: datetime) : void — scans vehicles for expiry and issues MarkVehicleIneligible when needed.
  • Realizes: REQ-DRV-022.

VerificationStatusReporter

Exposes onboarding status to the driver app.

  • Operations:
    • getCurrentStatus(driverId: uuid) : VerificationState
    • getEstimatedTimeToVerify(driverId: uuid) : Duration
  • Realizes: REQ-DRV-003, REQ-DRV-007, REQ-DRV-008.

Infrastructure Services

IdentityVerificationProvider

Certified third-party identity and background check — infrastructure boundary.

  • Operations:
    • requestVerification(driverId: uuid, documents: list<DocumentRef>) : void — submit application to provider.
    • getStatus(requestId: uuid) : VerificationState — poll or receive callback.
  • Realizes: REQ-DRV-002, REQ-DRV-005, REQ-DRV-006, REQ-DRV-NFR-001, REQ-NFR-010.

DocumentStorageService

Encrypted document store — infrastructure boundary for identity documents and licences.

  • Operations:
    • storeDocument(driverId: uuid, documentType: DocumentType, fileContent: bytes) : string — returns a storageRef.
    • getDocumentUrl(storageRef: string, ttl: Duration) : string — time-limited signed URL.
    • deleteDocument(storageRef: string) : void — used to honour erasure requests.
  • Realizes: REQ-DRV-NFR-002, REQ-NFR-020.

DriverNotificationService

Push, SMS, and email channels to drivers — infrastructure boundary.

  • Operations:
    • notifyDriver(driverId: uuid, subject: string, message: string, channel: NotificationChannel) : void
  • Realizes: REQ-DRV-006, REQ-DRV-008, REQ-DRV-022, REQ-DRV-043, REQ-DRV-044, REQ-DRV-049.

Commands

Command Fields Realizes
RegisterDriver fullName, email, phone, correlationId REQ-DRV-001
UploadIdentityDocument driverId, documentType, documentNumber, storageRef, expiresAt?, correlationId REQ-DRV-002
CompleteBackgroundCheck driverId, result, correlationId REQ-DRV-005
RejectDriverApplication driverId, reason, correlationId REQ-DRV-006
RegisterVehicle driverId, details, registrationExpiresAt, insuranceExpiresAt, correlationId REQ-DRV-020
RecordVehicleInspection vehicleId, inspection, correlationId REQ-DRV-020, REQ-DRV-021
MarkVehicleIneligible vehicleId, reason, correlationId REQ-DRV-022, REQ-DRV-023
GoOnline driverId, correlationId REQ-DRV-030, REQ-DRV-032, REQ-DRV-033, REQ-DRV-NFR-004
GoOffline driverId, reason, correlationId REQ-DRV-031, REQ-DRV-034
SubmitRating driverId, rideId, rating, correlationId REQ-DRV-040, REQ-DRV-041
IssueRatingWarning driverId, correlationId REQ-DRV-043
ProposeSuspension driverId, correlationId REQ-DRV-044, REQ-DRV-046
SuspendDriver driverId, operatorId, reason, duration, correlationId REQ-DRV-044, REQ-DRV-045
SubmitAppeal driverId, reason, correlationId REQ-DRV-047, REQ-DRV-048
ResolveAppeal driverId, operatorId, outcome, justification, correlationId REQ-DRV-049, REQ-DRV-NFR-005

Events

Internal events

Event Fields Realizes
DriverRegistered driverId, registeredAt REQ-DRV-001
IdentityDocumentUploaded documentId, driverId, documentType, uploadedAt REQ-DRV-002
DriverVerified driverId, verifiedAt REQ-DRV-005
DriverApplicationRejected driverId, reason, rejectedAt REQ-DRV-006
VehicleRegistered vehicleId, driverId, registeredAt REQ-DRV-020
VehicleInspectionRecorded vehicleId, passed, eligibleNow REQ-DRV-021
VehicleBecameIneligible vehicleId, driverId, reason, detectedAt REQ-DRV-022
DriverWentOnline driverId, selectedVehicleId, onlineAt REQ-DRV-030
DriverWentOffline driverId, reason, offlineAt REQ-DRV-031, REQ-DRV-034
RatingSubmitted driverId, rating, newAverage, totalRides, submittedAt REQ-DRV-040
RatingWarningIssued driverId, averageRating, issuedAt REQ-DRV-043
SuspensionProposalCreated driverId, averageRating, cancellationCount, noShowCount, proposedAt REQ-DRV-044
DriverSuspended driverId, operatorId, reason, duration, suspendedAt REQ-DRV-044, REQ-DRV-045, REQ-DRV-NFR-005
AppealSubmitted driverId, submittedAt REQ-DRV-047, REQ-DRV-048
AppealResolved driverId, outcome, operatorId, resolvedAt REQ-DRV-049, REQ-DRV-NFR-005

External-bound events (Published Language)

DriverWentOnline, DriverWentOffline, and the implicit match-eligibility projection cross to Ride Management, which is the consumer of the supply-side state. DriverVerified, DriverSuspended, and AppealResolved are also published to the audit and notification surface.

External-consumed events

Event From Used by
RideCompleted Ride Management reaction tickRatingsOnRideCompletedSubmitRating when event.driverRating is defined
DriverNoShowRecorded Ride Management feeds noShowCountWindow and suspension-proposal context
DriverPositionStale Geolocation & Routing reaction takeOfflineOnStalePositionGoOffline(reason=stalePosition) (ACL)

Reactions

warnOnLowRating

“Issue rating warning when driver dips below 4.2 with maturity.”

  • Trigger: event RatingSubmitted
  • Guard: event.totalRides > 20 and event.newAverage.value < 4.2 and event.newAverage.value >= 4.0
  • Effect: IssueRatingWarning(driverId = event.driverId)
  • Realizes: REQ-DRV-043

proposeSuspensionOnSustainedLowRating

“Queue suspension proposal when driver drops below 4.0.”

  • Trigger: event RatingSubmitted
  • Guard: event.totalRides > 20 and event.newAverage.value < 4.0
  • Effect: ProposeSuspension(driverId = event.driverId)
  • Realizes: REQ-DRV-044, REQ-DRV-046

suspendOnVehicleIneligibility

“Take driver offline when their vehicle becomes ineligible.”

  • Trigger: event VehicleBecameIneligible
  • Effect: GoOffline(driverId = event.driverId, reason = documentExpired)
  • Realizes: REQ-DRV-022, REQ-DRV-023

takeOfflineOnStalePosition

“Take driver offline on stale position from Geolocation.”

  • Trigger: event DriverPositionStale
  • Effect: GoOffline(driverId = event.driverId, reason = stalePosition)
  • Realizes: REQ-DRV-034

notifyOnRejection

“Notify driver and include reason on rejection.”

  • Trigger: event DriverApplicationRejected
  • Effect: DriverNotificationService.notifyDriver(driverId, subject = "Application rejected", message = event.reason, channel = push)
  • Realizes: REQ-DRV-006, REQ-DRV-008

notifyOnVerified

“Notify driver within 24h of verification status change.”

  • Trigger: event DriverVerified
  • Effect: DriverNotificationService.notifyDriver(driverId, subject = "You are verified", message = "You can now go online and start driving.", channel = push)
  • Realizes: REQ-DRV-008

notifyOnSuspensionDecision

“Notify driver on appeal resolution.”

  • Trigger: event AppealResolved
  • Effect: DriverNotificationService.notifyDriver(driverId, subject = "Appeal resolved", message = "Outcome: " + event.outcome, channel = push)
  • Realizes: REQ-DRV-049

tickRatingsOnRideCompleted

“Bridge from RideManagement — record rider rating of driver.”

  • Trigger: event RideCompleted
  • Guard: event.driverRating is defined
  • Effect: SubmitRating(driverId = event.driverId, rideId = event.rideId, rating = event.driverRating)
  • Realizes: REQ-DRV-040

Traceability Matrix

Requirement Realized by
REQ-DRV-001 Driver, command RegisterDriver, op Register driver, event DriverRegistered
REQ-DRV-002 IdentityDocument, command UploadIdentityDocument, op Upload identity document, event IdentityDocumentUploaded, IdentityVerificationProvider
REQ-DRV-003 Driver (verificationState), VerificationStatusReporter.getCurrentStatus
REQ-DRV-004 Driver precondition isVerified on GoOnline; statemachine pendingVerification/rejected states
REQ-DRV-005 Driver op Complete background check, command CompleteBackgroundCheck, event DriverVerified, IdentityVerificationProvider
REQ-DRV-006 Driver op Reject driver application, command RejectDriverApplication, event DriverApplicationRejected, reaction notifyOnRejection, DriverNotificationService
REQ-DRV-007 VerificationStatusReporter.getEstimatedTimeToVerify
REQ-DRV-008 VerificationStatusReporter, reactions notifyOnRejection, notifyOnVerified, DriverNotificationService
REQ-DRV-020 Vehicle, command RegisterVehicle, op Register vehicle, event VehicleRegistered; RecordVehicleInspection
REQ-DRV-021 Vehicle invariant eligibilityRequiresValidDocs, InspectionResult, op Record inspection result
REQ-DRV-022 Vehicle op Mark vehicle ineligible, event VehicleBecameIneligible, DocumentExpiryChecker, reaction suspendOnVehicleIneligibility, DriverNotificationService
REQ-DRV-023 Vehicle (eligibility) + Driver precondition hasEligibleVehicle on GoOnline; reaction suspendOnVehicleIneligibility
REQ-DRV-030 Driver op Go online, command GoOnline, event DriverWentOnline
REQ-DRV-031 Driver op Go offline, command GoOffline, event DriverWentOffline
REQ-DRV-032 Driver (online state exposed to RIDE via OHS)
REQ-DRV-033 Driver precondition notSuspended on GoOnline; statemachine offlineWhileSuspended invariant
REQ-DRV-034 reaction takeOfflineOnStalePosition, command GoOffline (reason = stalePosition), event DriverWentOffline
REQ-DRV-040 Rating, AverageRating, Driver op Submit rating, command SubmitRating, event RatingSubmitted, reaction tickRatingsOnRideCompleted
REQ-DRV-041 Rating (min(1), max(5)), op Submit rating (precondition validRange)
REQ-DRV-042 AverageRating, Driver.averageRating exposed to driver app
REQ-DRV-043 Driver op Issue rating warning, command IssueRatingWarning, event RatingWarningIssued, reaction warnOnLowRating, DriverNotificationService
REQ-DRV-044 Driver op Propose suspension and Suspend driver, commands ProposeSuspension/SuspendDriver, events SuspensionProposalCreated/DriverSuspended, reaction proposeSuspensionOnSustainedLowRating
REQ-DRV-045 Driver op Suspend driver (records operatorId), event DriverSuspended, AppealResolution.operatorId
REQ-DRV-046 Driver op Suspend driver (precondition operatorApproved); reaction proposeSuspensionOnSustainedLowRating only proposes — does not auto-suspend
REQ-DRV-047 AppealDetails, Driver op Submit suspension appeal, command SubmitAppeal, event AppealSubmitted
REQ-DRV-048 Driver op Submit suspension appeal, statemachine transition suspendedappealInReview
REQ-DRV-049 AppealResolution, Driver op Resolve appeal, command ResolveAppeal, event AppealResolved, reaction notifyOnSuspensionDecision
REQ-DRV-NFR-001 IdentityVerificationProvider (SLA budget)
REQ-DRV-NFR-002 IdentityDocument, DocumentStorageService (encryption-at-rest baseline)
REQ-DRV-NFR-003 IdentityDocument, DocumentStorageService.deleteDocument (retention/erasure)
REQ-DRV-NFR-004 Driver op Go online (latency budget)
REQ-DRV-NFR-005 AppealResolution, events DriverSuspended and AppealResolved (append-only audit log retained ≥ 7 years)

Concrete syntax (.domain DSL)

The full .domain source that this page narrates. Entity declarations, value types, commands, events, invariants, preconditions, services, state machine, and reactions appear in parse order.

context DriverManagement :: "Driver onboarding, identity, vehicles, availability, ratings, suspension" {
    requirements-source "driver-management.sysreq"

    enum VerificationState { pendingVerification, verified, rejected, suspended, appealInReview, permanentlySuspended }
    enum AvailabilityState { offline, online }
    enum DocumentType { driversLicence, passport, nationalId, selfie }
    enum BackgroundCheckResult { clear, failed }
    enum OfflineReason { voluntary, stalePosition, suspension, documentExpired }
    enum AppealOutcome { reinstated, permanentlySuspended }
    enum NotificationChannel { email, sms, push }

    // -----------------------------------------------------------------
    // Value types
    // -----------------------------------------------------------------

    value EmailAddress { fields { value : string format(email) } }
    value PhoneNumber { fields { countryCode : string; number : string } }
    value FullName { fields { firstName : string maxLength(100); lastName : string maxLength(100) } }
    value Rating { fields { value : int min(1) max(5) } }

    value AverageRating :: "Running aggregate of ratings for a driver" {
        satisfies [REQ-DRV-040, REQ-DRV-041, REQ-DRV-042]
        fields {
            value : decimal min(1.0) max(5.0)
            totalRatings : int min(0)
            ratingSum : int min(0)
        }
        invariants {
            consistentAggregate :: "Average is sum / count" enforcement reject {
                if totalRatings > 0 { value = ratingSum / totalRatings }
            }
        }
    }

    value VehicleDetails {
        fields {
            make : string
            model : string
            year : int min(1990)
            color : string
            licencePlate : string
        }
    }

    value InspectionResult {
        satisfies [REQ-DRV-021, REQ-DRV-022]
        fields {
            passed : boolean
            inspectedAt : datetime
            expiresAt : datetime
            partner : string
        }
        invariants {
            expiryAfterInspection { expiresAt > inspectedAt }
        }
    }

    value AppealDetails {
        fields { reason : string maxLength(2000); submittedAt : datetime }
    }

    value AppealResolution {
        satisfies [REQ-DRV-049, REQ-DRV-NFR-005]
        fields {
            outcome : AppealOutcome
            operatorId : uuid
            resolvedAt : datetime
            justification : string maxLength(2000)
        }
    }

    // -----------------------------------------------------------------
    // Entities
    // -----------------------------------------------------------------

    entity IdentityDocument :: "Driver-provided identity, licence, or selfie" {
        satisfies [REQ-DRV-002, REQ-DRV-NFR-002, REQ-DRV-NFR-003]

        identifier documentId : UUID
        fields {
            driverId : UUID
            documentType : DocumentType
            documentNumber : string
            storageRef : string
            uploadedAt : datetime
            expiresAt : datetime optional
            verified : boolean default(false)
        }

        operations {
            "Upload identity document" on UploadIdentityDocument {
                satisfies [REQ-DRV-002]
                sets IdentityDocument {
                    driverId = uploadIdentityDocument.driverId
                    documentType = uploadIdentityDocument.documentType
                    documentNumber = uploadIdentityDocument.documentNumber
                    storageRef = uploadIdentityDocument.storageRef
                    uploadedAt = now()
                    expiresAt = uploadIdentityDocument.expiresAt
                }
                emits IdentityDocumentUploaded {
                    documentId = IdentityDocument.documentId
                    driverId = IdentityDocument.driverId
                    documentType = IdentityDocument.documentType
                    uploadedAt = IdentityDocument.uploadedAt
                }
            }
        }
    }

    entity Vehicle :: "Driver vehicle with documents and inspection state" {
        satisfies [REQ-DRV-020, REQ-DRV-021, REQ-DRV-022, REQ-DRV-023]

        identifier vehicleId : UUID
        fields {
            driverId : UUID
            details : VehicleDetails
            registrationExpiresAt : datetime
            insuranceExpiresAt : datetime
            inspection : InspectionResult
            eligible : boolean default(false)
            registeredAt : datetime
        }

        invariants {
            eligibilityRequiresValidDocs :: "Eligible only when all docs valid" enforcement reject {
                if eligible = true {
                    inspection.passed = true
                    and inspection.expiresAt > now()
                    and registrationExpiresAt > now()
                    and insuranceExpiresAt > now()
                }
            }
        }

        operations {
            "Register vehicle" on RegisterVehicle {
                satisfies [REQ-DRV-020]
                sets Vehicle {
                    driverId = registerVehicle.driverId
                    details = registerVehicle.details
                    registrationExpiresAt = registerVehicle.registrationExpiresAt
                    insuranceExpiresAt = registerVehicle.insuranceExpiresAt
                    registeredAt = now()
                    eligible = false
                }
                emits VehicleRegistered {
                    vehicleId = Vehicle.vehicleId
                    driverId = Vehicle.driverId
                    registeredAt = Vehicle.registeredAt
                }
            }

            "Record inspection result" on RecordVehicleInspection {
                satisfies [REQ-DRV-020, REQ-DRV-021]
                sets Vehicle {
                    inspection = recordVehicleInspection.inspection
                    eligible = recordVehicleInspection.inspection.passed
                                and recordVehicleInspection.inspection.expiresAt > now()
                                and Vehicle.registrationExpiresAt > now()
                                and Vehicle.insuranceExpiresAt > now()
                }
                emits VehicleInspectionRecorded {
                    vehicleId = Vehicle.vehicleId
                    passed = Vehicle.inspection.passed
                    eligibleNow = Vehicle.eligible
                }
            }

            "Mark vehicle ineligible due to expired document" on MarkVehicleIneligible {
                satisfies [REQ-DRV-022, REQ-DRV-023]
                precondition documentExpired {
                    Vehicle.registrationExpiresAt <= now()
                    or Vehicle.insuranceExpiresAt <= now()
                    or Vehicle.inspection.expiresAt <= now()
                }
                sets Vehicle { eligible = false }
                emits VehicleBecameIneligible {
                    vehicleId = Vehicle.vehicleId
                    driverId = Vehicle.driverId
                    reason = markVehicleIneligible.reason
                    detectedAt = now()
                }
            }
        }
    }

    entity Driver :: "Driver lifecycle root — verification, availability, ratings, appeals" {
        satisfies [REQ-DRV-001, REQ-DRV-003, REQ-DRV-004, REQ-DRV-005, REQ-DRV-006,
                   REQ-DRV-030, REQ-DRV-031, REQ-DRV-032, REQ-DRV-033,
                   REQ-DRV-040, REQ-DRV-043, REQ-DRV-044, REQ-DRV-046,
                   REQ-DRV-047, REQ-DRV-048, REQ-DRV-049]

        identifier driverId : UUID
        fields {
            fullName : FullName
            email : EmailAddress
            phone : PhoneNumber
            verificationState : VerificationState default("pendingVerification")
            availability : AvailabilityState default("offline")
            selectedVehicleId : UUID optional
            averageRating : AverageRating optional
            totalRidesCompleted : int min(0) default(0)
            cancellationCountWindow : int min(0) default(0)
            noShowCountWindow : int min(0) default(0)
            appeal : AppealDetails optional
            appealResolution : AppealResolution optional
            registeredAt : datetime
        }

        invariants {
            singleVehicleSelected :: "Driver may have at most one selected vehicle at a time" enforcement reject {
                selectedVehicleId is null or count(selectedVehicleId) = 1
            }
            verifiedHasNoOpenAppeal :: "Verified drivers do not carry an open appeal" enforcement alert {
                if verificationState = verified { appeal is null }
            }
        }

        operations {
            "Register driver" on RegisterDriver {
                satisfies [REQ-DRV-001]
                sets Driver {
                    fullName = registerDriver.fullName
                    email = registerDriver.email
                    phone = registerDriver.phone
                    verificationState = pendingVerification
                    availability = offline
                    registeredAt = now()
                }
                emits DriverRegistered {
                    driverId = Driver.driverId
                    registeredAt = Driver.registeredAt
                }
            }

            "Complete background check" on CompleteBackgroundCheck {
                satisfies [REQ-DRV-005]
                precondition awaitingVerification { Driver.verificationState = pendingVerification }
                precondition resultIsClear { completeBackgroundCheck.result = clear }
                sets Driver { verificationState = verified }
                emits DriverVerified {
                    driverId = Driver.driverId
                    verifiedAt = now()
                }
            }

            "Reject driver application" on RejectDriverApplication {
                satisfies [REQ-DRV-006]
                precondition awaitingVerification { Driver.verificationState = pendingVerification }
                sets Driver { verificationState = rejected }
                emits DriverApplicationRejected {
                    driverId = Driver.driverId
                    reason = rejectDriverApplication.reason
                    rejectedAt = now()
                }
            }

            "Go online" on GoOnline {
                satisfies [REQ-DRV-030, REQ-DRV-032, REQ-DRV-033, REQ-DRV-NFR-004]
                precondition isVerified { Driver.verificationState = verified }
                precondition notSuspended { Driver.verificationState != suspended }
                precondition hasEligibleVehicle { Driver.selectedVehicleId is defined }
                sets Driver { availability = online }
                emits DriverWentOnline {
                    driverId = Driver.driverId
                    selectedVehicleId = Driver.selectedVehicleId
                    onlineAt = now()
                }
            }

            "Go offline" on GoOffline {
                satisfies [REQ-DRV-031]
                precondition wasOnline { Driver.availability = online }
                sets Driver { availability = offline }
                emits DriverWentOffline {
                    driverId = Driver.driverId
                    reason = goOffline.reason
                    offlineAt = now()
                }
            }

            "Submit rating" on SubmitRating {
                satisfies [REQ-DRV-040, REQ-DRV-041, REQ-DRV-042]
                precondition validRange {
                    submitRating.rating.value >= 1
                    and submitRating.rating.value <= 5
                }
                sets Driver {
                    averageRating = recompute(Driver.averageRating, submitRating.rating)
                    totalRidesCompleted = Driver.totalRidesCompleted + 1
                }
                emits RatingSubmitted {
                    driverId = Driver.driverId
                    rating = submitRating.rating
                    newAverage = Driver.averageRating
                    totalRides = Driver.totalRidesCompleted
                    submittedAt = now()
                }
            }

            "Issue rating warning" on IssueRatingWarning {
                satisfies [REQ-DRV-043]
                precondition matureDriver { Driver.totalRidesCompleted > 20 }
                precondition belowWarningThreshold { Driver.averageRating.value < 4.2 }
                emits RatingWarningIssued {
                    driverId = Driver.driverId
                    averageRating = Driver.averageRating
                    issuedAt = now()
                }
            }

            "Propose suspension" on ProposeSuspension {
                satisfies [REQ-DRV-044, REQ-DRV-046]
                precondition matureDriver { Driver.totalRidesCompleted > 20 }
                precondition belowSuspensionThreshold { Driver.averageRating.value < 4.0 }
                emits SuspensionProposalCreated {
                    driverId = Driver.driverId
                    averageRating = Driver.averageRating
                    cancellationCount = Driver.cancellationCountWindow
                    noShowCount = Driver.noShowCountWindow
                    proposedAt = now()
                }
            }

            "Suspend driver" on SuspendDriver {
                satisfies [REQ-DRV-044, REQ-DRV-045, REQ-DRV-046, REQ-DRV-NFR-005]
                precondition operatorApproved { suspendDriver.operatorId is defined }
                sets Driver {
                    verificationState = suspended
                    availability = offline
                }
                emits DriverSuspended {
                    driverId = Driver.driverId
                    operatorId = suspendDriver.operatorId
                    reason = suspendDriver.reason
                    duration = suspendDriver.duration
                    suspendedAt = now()
                }
            }

            "Submit suspension appeal" on SubmitAppeal {
                satisfies [REQ-DRV-047, REQ-DRV-048]
                precondition isSuspended { Driver.verificationState = suspended }
                sets Driver {
                    verificationState = appealInReview
                    appeal = AppealDetails(reason = submitAppeal.reason, submittedAt = now())
                }
                emits AppealSubmitted {
                    driverId = Driver.driverId
                    submittedAt = now()
                }
            }

            "Resolve appeal" on ResolveAppeal {
                satisfies [REQ-DRV-049, REQ-DRV-NFR-005]
                precondition appealUnderReview { Driver.verificationState = appealInReview }
                sets Driver {
                    verificationState = if resolveAppeal.outcome = reinstated then verified else permanentlySuspended
                    appealResolution = AppealResolution(
                        outcome = resolveAppeal.outcome,
                        operatorId = resolveAppeal.operatorId,
                        resolvedAt = now(),
                        justification = resolveAppeal.justification
                    )
                    appeal = null
                }
                emits AppealResolved {
                    driverId = Driver.driverId
                    outcome = resolveAppeal.outcome
                    operatorId = resolveAppeal.operatorId
                    resolvedAt = now()
                }
            }
        }
    }

    aggregate DriverAggregate root Driver { contains [Vehicle, IdentityDocument] }

    statemachine DriverLifecycle on Driver {
        start pendingVerification

        state pendingVerification {
            invariant noRidesYet { Driver.totalRidesCompleted = 0 }
        }
        state verified {}
        state rejected {}
        state suspended {
            invariant offlineWhileSuspended { Driver.availability = offline }
        }
        state appealInReview {}
        state permanentlySuspended {}

        transition pendingVerification -> verified on CompleteBackgroundCheck
        transition pendingVerification -> rejected on RejectDriverApplication
        transition verified -> suspended on SuspendDriver
        transition suspended -> appealInReview on SubmitAppeal
        transition appealInReview -> verified on ResolveAppeal           // outcome = reinstated
        transition appealInReview -> permanentlySuspended on ResolveAppeal // outcome = permanentlySuspended

        final rejected
        final permanentlySuspended
    }

    // -----------------------------------------------------------------
    // Domain services
    // -----------------------------------------------------------------

    service DocumentExpiryChecker :: "Detects upcoming/expired documents" {
        satisfies [REQ-DRV-022]
        operations {
            checkDocumentExpiry(now: datetime) : void
        }
    }

    service VerificationStatusReporter :: "Exposes onboarding status to driver app" {
        satisfies [REQ-DRV-003, REQ-DRV-007, REQ-DRV-008]
        operations {
            getCurrentStatus(driverId: uuid) : VerificationState
            getEstimatedTimeToVerify(driverId: uuid) : Duration
        }
    }

    // -----------------------------------------------------------------
    // Infrastructure services
    // -----------------------------------------------------------------

    infrastructure-service IdentityVerificationProvider :: "Certified third-party identity & background check" {
        satisfies [REQ-DRV-002, REQ-DRV-005, REQ-DRV-006, REQ-DRV-NFR-001, REQ-NFR-010]
        operations {
            requestVerification(driverId: uuid, documents: list<DocumentRef>) : void
            getStatus(requestId: uuid) : VerificationState
        }
    }

    infrastructure-service DocumentStorageService :: "Encrypted document store" {
        satisfies [REQ-DRV-NFR-002, REQ-NFR-020]
        operations {
            storeDocument(driverId: uuid, documentType: DocumentType, fileContent: bytes) : string
            getDocumentUrl(storageRef: string, ttl: Duration) : string
            deleteDocument(storageRef: string) : void
        }
    }

    infrastructure-service DriverNotificationService :: "Push, SMS, and email to drivers" {
        satisfies [REQ-DRV-006, REQ-DRV-008, REQ-DRV-022, REQ-DRV-043, REQ-DRV-044, REQ-DRV-049]
        operations {
            notifyDriver(driverId: uuid, subject: string, message: string, channel: NotificationChannel) : void
        }
    }

    // -----------------------------------------------------------------
    // Commands (correlationId omitted for brevity except where critical)
    // -----------------------------------------------------------------

    command RegisterDriver { fields { fullName: FullName; email: EmailAddress; phone: PhoneNumber; correlationId: uuid } }
    command UploadIdentityDocument { fields { driverId: uuid; documentType: DocumentType; documentNumber: string; storageRef: string; expiresAt: datetime optional; correlationId: uuid } }
    command CompleteBackgroundCheck { fields { driverId: uuid; result: BackgroundCheckResult; correlationId: uuid } }
    command RejectDriverApplication { fields { driverId: uuid; reason: string; correlationId: uuid } }
    command RegisterVehicle { fields { driverId: uuid; details: VehicleDetails; registrationExpiresAt: datetime; insuranceExpiresAt: datetime; correlationId: uuid } }
    command RecordVehicleInspection { fields { vehicleId: uuid; inspection: InspectionResult; correlationId: uuid } }
    command MarkVehicleIneligible { fields { vehicleId: uuid; reason: string; correlationId: uuid } }
    command GoOnline { fields { driverId: uuid; correlationId: uuid } }
    command GoOffline { fields { driverId: uuid; reason: OfflineReason; correlationId: uuid } }
    command SubmitRating { fields { driverId: uuid; rideId: uuid; rating: Rating; correlationId: uuid } }
    command IssueRatingWarning { fields { driverId: uuid; correlationId: uuid } }
    command ProposeSuspension { fields { driverId: uuid; correlationId: uuid } }
    command SuspendDriver { fields { driverId: uuid; operatorId: uuid; reason: string; duration: Duration; correlationId: uuid } }
    command SubmitAppeal { fields { driverId: uuid; reason: string; correlationId: uuid } }
    command ResolveAppeal { fields { driverId: uuid; operatorId: uuid; outcome: AppealOutcome; justification: string; correlationId: uuid } }

    // -----------------------------------------------------------------
    // Events — internal
    // -----------------------------------------------------------------

    event DriverRegistered { satisfies [REQ-DRV-001] fields { driverId: uuid; registeredAt: datetime } }
    event IdentityDocumentUploaded { satisfies [REQ-DRV-002] fields { documentId: uuid; driverId: uuid; documentType: DocumentType; uploadedAt: datetime } }
    event DriverVerified { satisfies [REQ-DRV-005] fields { driverId: uuid; verifiedAt: datetime } }
    event DriverApplicationRejected { satisfies [REQ-DRV-006] fields { driverId: uuid; reason: string; rejectedAt: datetime } }
    event VehicleRegistered { satisfies [REQ-DRV-020] fields { vehicleId: uuid; driverId: uuid; registeredAt: datetime } }
    event VehicleInspectionRecorded { satisfies [REQ-DRV-021] fields { vehicleId: uuid; passed: boolean; eligibleNow: boolean } }
    event VehicleBecameIneligible { satisfies [REQ-DRV-022] fields { vehicleId: uuid; driverId: uuid; reason: string; detectedAt: datetime } }
    event DriverWentOnline { satisfies [REQ-DRV-030] fields { driverId: uuid; selectedVehicleId: uuid; onlineAt: datetime } }
    event DriverWentOffline { satisfies [REQ-DRV-031, REQ-DRV-034] fields { driverId: uuid; reason: OfflineReason; offlineAt: datetime } }
    event RatingSubmitted { satisfies [REQ-DRV-040] fields { driverId: uuid; rating: Rating; newAverage: AverageRating; totalRides: int; submittedAt: datetime } }
    event RatingWarningIssued { satisfies [REQ-DRV-043] fields { driverId: uuid; averageRating: AverageRating; issuedAt: datetime } }
    event SuspensionProposalCreated { satisfies [REQ-DRV-044] fields { driverId: uuid; averageRating: AverageRating; cancellationCount: int; noShowCount: int; proposedAt: datetime } }
    event DriverSuspended { satisfies [REQ-DRV-044, REQ-DRV-045, REQ-DRV-NFR-005] fields { driverId: uuid; operatorId: uuid; reason: string; duration: Duration; suspendedAt: datetime } }
    event AppealSubmitted { satisfies [REQ-DRV-047, REQ-DRV-048] fields { driverId: uuid; submittedAt: datetime } }
    event AppealResolved { satisfies [REQ-DRV-049, REQ-DRV-NFR-005] fields { driverId: uuid; outcome: AppealOutcome; operatorId: uuid; resolvedAt: datetime } }

    // -----------------------------------------------------------------
    // Events — external (consumed from other contexts)
    // -----------------------------------------------------------------

    external-event RideCompleted from RideManagement
    external-event DriverNoShowRecorded from RideManagement
    external-event DriverPositionStale from GeolocationRouting

    // -----------------------------------------------------------------
    // Reactions
    // -----------------------------------------------------------------

    reaction warnOnLowRating :: "Issue rating warning when driver dips below 4.2 with maturity" {
        satisfies [REQ-DRV-043]
        trigger RatingSubmitted
        guard event.totalRides > 20 and event.newAverage.value < 4.2 and event.newAverage.value >= 4.0
        effect IssueRatingWarning(driverId = event.driverId)
    }

    reaction proposeSuspensionOnSustainedLowRating :: "Queue suspension proposal when driver drops below 4.0" {
        satisfies [REQ-DRV-044, REQ-DRV-046]
        trigger RatingSubmitted
        guard event.totalRides > 20 and event.newAverage.value < 4.0
        effect ProposeSuspension(driverId = event.driverId)
    }

    reaction suspendOnVehicleIneligibility :: "Take driver offline when their vehicle becomes ineligible" {
        satisfies [REQ-DRV-022, REQ-DRV-023]
        trigger VehicleBecameIneligible
        effect GoOffline(driverId = event.driverId, reason = documentExpired)
    }

    reaction takeOfflineOnStalePosition :: "Take driver offline on stale position from Geolocation" {
        satisfies [REQ-DRV-034]
        trigger DriverPositionStale
        effect GoOffline(driverId = event.driverId, reason = stalePosition)
    }

    reaction notifyOnRejection :: "Notify driver and include reason on rejection" {
        satisfies [REQ-DRV-006, REQ-DRV-008]
        trigger DriverApplicationRejected
        effect DriverNotificationService.notifyDriver(
            driverId = event.driverId,
            subject = "Application rejected",
            message = event.reason,
            channel = push
        )
    }

    reaction notifyOnVerified :: "Notify driver within 24h of verification status change" {
        satisfies [REQ-DRV-008]
        trigger DriverVerified
        effect DriverNotificationService.notifyDriver(
            driverId = event.driverId,
            subject = "You are verified",
            message = "You can now go online and start driving.",
            channel = push
        )
    }

    reaction notifyOnSuspensionDecision :: "Notify driver on appeal resolution" {
        satisfies [REQ-DRV-049]
        trigger AppealResolved
        effect DriverNotificationService.notifyDriver(
            driverId = event.driverId,
            subject = "Appeal resolved",
            message = "Outcome: " + event.outcome,
            channel = push
        )
    }

    reaction tickRatingsOnRideCompleted :: "Bridge from RideManagement — record rider rating of driver" {
        satisfies [REQ-DRV-040]
        trigger RideCompleted
        guard event.driverRating is defined
        effect SubmitRating(driverId = event.driverId, rideId = event.rideId, rating = event.driverRating)
    }
}