Bounded Context: Shared Kernel (SK)

Responsibility: Hosts the small set of value types and enums that are co-owned by all five bounded contexts (Rider, Driver, Ride, Geolocation, Payment). Keeping these here — rather than duplicating them inside each context — makes their unit semantics, constraints, and invariants the single source of truth across the system.


Context Map

Relation Other Bounded Context Position Pattern Description
Shared ↔ Rider, Driver, Ride, GEO, Payment every other context symmetric Shared Kernel (SK) All five contexts depend on Amount, Currency, Distance, Duration, and the Currencies enum. They are co-owned: no context modifies them unilaterally; any change requires coordinated agreement across the consumers. The kernel is intentionally small — only concepts that genuinely cut across contexts live here.

The Shared Kernel pattern fits this set of types because:

  • Money flows across contexts: a fare is computed in Payment, embedded in RideRequested from Ride, and pre-authorized back in Payment. Translating between bespoke per-context money types at every boundary would be needless ceremony.
  • Distance and Duration are physical quantities, not domain abstractions; their meaning (“meters”, “seconds”) is the same in every context that handles them. Defining them once removes the risk of a decimal field in one context being kilometers while another is meters.

Enums

Currencies

The closed set of ISO 4217 alphabetic currency codes (active list — ~178 entries). Lowercase to fit the DSL’s enum-value naming convention; the canonical ISO form is uppercase.

  • Sample values: usd, eur, gbp, jpy, chf, cny, inr, brl, … through to zwg.
  • Includes funds and precious-metal codes (xau, xag, xpt, xpd, xdr, xof, xaf, …) per ISO 4217.
  • Realizes: REQ-PAY-014 (fare denomination), REQ-PAY-NFR-001 (multi-market support).
  • Used as the code field of the Currency value type. The split between enum (the closed set of valid codes) and value type (the descriptor that bundles a code with its reference data) follows a common DDD pattern: the enum names the identity, the value type carries the attributes.

Value Types

Currency

ISO 4217 currency reference — alphabetic code, numeric code, and default minor-unit precision. Modeled on java.util.Currency.

  • Fields:
    • code: Currencies — the ISO 4217 alphabetic code (e.g. usd, eur, jpy).
    • numericCode: Integer — min(0), max(999). The ISO 4217 three-digit numeric identifier (e.g. 840 for USD, 978 for EUR, 392 for JPY).
    • defaultFractionDigits: Integer — min(-1), max(4). The minor-unit precision (most currencies use 2; JPY/KRW/VND use 0; KWD/BHD/JOD use 3; CLF/UYW use 4; XAU/XAG/XDR and similar funds/metals use -1 to mean “not applicable”).
  • Invariants:
    • numericCodeInRange: numericCode >= 0 and numericCode <= 999 — enforcement: reject.
    • fractionDigitsInRange: defaultFractionDigits >= -1 and defaultFractionDigits <= 4 — enforcement: reject.
  • Realizes: REQ-PAY-014 (fare denomination), REQ-PAY-NFR-001 (multi-market support), REQ-PAY-080 (receipt rendering — minor-unit precision drives the displayed digits).
  • Note: Display name and currency symbol are locale-dependent derivations, not stored on the value type — exactly mirroring java.util.Currency.getSymbol(Locale) and getDisplayName(Locale). They belong in the rendering layer, not in the domain model.

Amount

A non-negative monetary value with explicit currency.

  • Fields:
    • value: Decimal — min(0)
    • currency: Currency
  • Invariants:
    • nonNegative: value >= 0 — enforcement: reject. The constructor refuses to produce a negative Amount, so downstream code never has to defensively check.
  • Realizes: REQ-PAY-014, REQ-PAY-020, REQ-PAY-022 (fare amounts), REQ-RIDE-003 (committed fare), REQ-RIDE-061 (cancellation fees).
  • Replaces the prior Money value type that lived inside Payment. Currency is carried inside Amount itself as a Currency value type, so consumers no longer pass (decimal, currency-code) pairs by convention — and they get the reference data (numeric code, fraction digits) for free wherever an Amount is in scope.

Distance

Distance expressed in meters.

  • Fields:
    • meters: Decimal — min(0)
  • Invariants:
    • nonNegative: meters >= 0 — enforcement: reject.
  • Realizes: REQ-GEO-012 (route distance), REQ-RIDE-040 (driver-to-pickup proximity), REQ-RIDE-048 (final-fare actual distance).
  • Used by Route, FareEstimate, FinalFare, SignalDriverArrival, the ProximityService.findNearbyDrivers query, and the RideCompleted event.

Duration

Duration expressed in seconds.

  • Fields:
    • seconds: Integer — min(0)
  • Invariants:
    • nonNegative: seconds >= 0 — enforcement: reject.
  • Realizes: REQ-GEO-011 (ETA), REQ-GEO-012 (route duration), REQ-RIDE-048 (final-fare actual duration), REQ-DRV-045 (suspension length).
  • Used by Route, ETA, FareEstimate, FinalFare, RideCompleted, SuspendDriver, DriverSuspended, the InstantPayoutNetwork.getEstimatedArrival infrastructure call, and the document-storage TTL.

Concrete syntax (.domain DSL)

The full DSL definition that the narrative above is rendered from:

context Shared :: "Cross-cutting value types co-owned by all ride-now bounded contexts (Shared Kernel)" {

    // -----------------------------------------------------------------
    // Enums
    // -----------------------------------------------------------------

    // ISO 4217 alphabetic currency codes (active list). Lowercase to fit DSL
    // enum-value conventions; the canonical ISO form is uppercase.
    enum Currencies {
        aed, afn, all, amd, ang, aoa, ars, aud, awg, azn,
        bam, bbd, bdt, bgn, bhd, bif, bmd, bnd, bob, bov, brl, bsd, btn, bwp, byn, bzd,
        cad, cdf, che, chf, chw, clf, clp, cny, cop, cou, crc, cup, cve, czk,
        djf, dkk, dop, dzd,
        egp, ern, etb, eur,
        fjd, fkp,
        gbp, gel, ghs, gip, gmd, gnf, gtq, gyd,
        hkd, hnl, htg, huf,
        idr, ils, inr, iqd, irr, isk,
        jmd, jod, jpy,
        kes, kgs, khr, kmf, kpw, krw, kwd, kyd, kzt,
        lak, lbp, lkr, lrd, lsl, lyd,
        mad, mdl, mga, mkd, mmk, mnt, mop, mru, mur, mvr, mwk, mxn, mxv, myr, mzn,
        nad, ngn, nio, nok, npr, nzd,
        omr,
        pab, pen, pgk, php, pkr, pln, pyg,
        qar,
        ron, rsd, rub, rwf,
        sar, sbd, scr, sdg, sek, sgd, shp, sle, sos, srd, ssp, stn, svc, syp, szl,
        thb, tjs, tmt, tnd, top, try, ttd, twd, tzs,
        uah, ugx, usd, usn, uyi, uyu, uyw, uzs,
        ved, ves, vnd, vuv,
        wst,
        xaf, xag, xau, xba, xbb, xbc, xbd, xcd, xdr, xof, xpd, xpf, xpt, xsu, xts, xua, xxx,
        yer,
        zar, zmw, zwg
    }

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

    value Currency :: "ISO 4217 currency reference — alphabetic code, numeric code, and default minor-unit precision (modeled on java.util.Currency)" {
        fields {
            code : Currencies
            numericCode : int min(0) max(999)
            defaultFractionDigits : int min(-1) max(4)
        }
        invariants {
            numericCodeInRange :: "ISO 4217 numeric codes are 3-digit identifiers" enforcement reject {
                numericCode >= 0 and numericCode <= 999
            }
            fractionDigitsInRange :: "Minor-unit precision is between 0 and 4 (or -1 for funds/metals with no minor unit)" enforcement reject {
                defaultFractionDigits >= -1 and defaultFractionDigits <= 4
            }
        }
    }

    value Amount :: "A non-negative monetary value with explicit currency" {
        fields {
            value : decimal min(0)
            currency : Currency
        }
        invariants {
            nonNegative :: "Amount is never negative" enforcement reject { value >= 0 }
        }
    }

    value Distance :: "Distance expressed in meters" {
        fields { meters : decimal min(0) }
        invariants {
            nonNegative :: "Distance is never negative" enforcement reject { meters >= 0 }
        }
    }

    value Duration :: "Duration expressed in seconds" {
        fields { seconds : int min(0) }
        invariants {
            nonNegative :: "Duration is never negative" enforcement reject { seconds >= 0 }
        }
    }
}