DACH Travel Law & Payment Compliance — Engineering Spec
Status: Action-oriented working spec. This is not legal advice and must be validated by Reise-, Datenschutz-, Zahlungsdienst-, and DACH-local counsel before implementation. It turns the current legal working draft into engineering tasks and intentionally marks counsel-sensitive assumptions.
Alignment With Current Busflow Domain
This spec aligns well with the direction already captured in Session 2:
- Commerce already owns
Booking,Payment,Ticket,FinancialLedger,CheckoutSession, and cancellation flows. - Backoffice already owns operator and tour configuration, including
deposit_config,final_payment_config,ticket_issuance_trigger, andsicherungsschein_url. - Communications already owns durable delivery of transactional messages and booking documents.
- The current docs now decouple
DEPOSIT_PAIDfromBookingConfirmedconceptually, which this spec relies on. - The existing Compliance Rule Engine idea already anticipates jurisdiction-specific validation profiles.
Required changes to the current model:
- Replace the single
is_pauschalreisetoggle with a computed classification result plus rationale. - Split payment authorization/capture facts from contract acceptance and booking confirmation.
- Add jurisdiction policy resolution (
DE,AT,CH, later cross-border composition). - Distinguish issued ticket artifacts from boarding-valid tickets.
- Add a WORM-style audit ledger for legal timelines, document versions, and payment/refund proofs.
1. Core Routing: Classification Engine
Legal Constraint
Package travel (PACKAGE_TRAVEL) triggers stricter information, insolvency-protection, cancellation, refund, and document-delivery obligations than excluded day trips, transport-only bookings, or B2B framework-contract bookings.
Technical Action
Do not rely on manual operator toggles. Compute a classification from the cart and tour payload, then route checkout into either:
REGULATED_FLOWEXEMPT_FLOWMANUAL_REVIEW_FLOW
Required Inputs
| Variable | Type | Meaning |
|---|---|---|
includes_overnight | Boolean | Whether the trip includes any overnight stay. In Busflow, this usually implies transport + accommodation, but accommodation-only edge cases must not be inferred. |
duration_hours | Integer | Trip duration from departure to return. |
total_price_gross_cents | Integer | Total gross trip price used for statutory threshold evaluation. Counsel must confirm whether thresholds apply per person, per booking, or advertised package price in each jurisdiction. |
services_array | Enum array | Service composition: TRANSPORT, ACCOMMODATION, RENTAL, TOURIST_SERVICE. |
tourist_service_value_pct | Float | Tourist-service value share for the 25% / essential-character test. |
tourist_service_essential_character | Boolean | Whether tourist services are marketed as an essential feature even below 25%. |
b2b_framework_active | Boolean | Verified business-travel framework-contract exemption. |
operator_country | Enum | Jurisdiction profile for operator obligations. |
traveler_country | Enum | Passenger-facing legal context, if required by counsel. |
departure_date | Date | Drives payment, cancellation, and refund timing. |
booking_date | Date | Drives near-departure payment rules. |
Rule Notes
duration_hours < 24, no overnight stay, and price below the statutory threshold can exempt a day trip, but the price threshold is not an independent "regulated" trigger by itself.services_arraycount is not enough when the second service is only a tourist service. The 25% / essential-character test matters.b2b_framework_activemust be a verified commercial context, not a checkout checkbox.- Store both the computed enum and the rationale.
Output
type TravelComplianceClassification =
| 'PACKAGE_TRAVEL'
| 'LINKED_TRAVEL_ARRANGEMENT'
| 'SINGLE_SERVICE_EXCLUDED'
| 'MANUAL_REVIEW_REQUIRED';
interface ClassificationResult {
classification: TravelComplianceClassification;
jurisdictionProfile: 'DE' | 'AT' | 'CH';
rationale: string[];
evaluatedAt: string;
ruleVersion: string;
}2. State Machine: Contract Formation & Payments
Legal Constraint
Payment facts, operator acceptance, legal confirmation, document delivery, and ledger updates are different events. For package travel, prepayment may require insolvency-protection information before funds are captured or accepted.
The ZAG / BaFin exposure around Busflow touching principal funds remains counsel-sensitive. The implementation target is: Busflow stays out of the flow of principal funds and uses Mollie Marketplaces or another regulated PSP structure.
Technical Action
Implement a saga that can support authorization-before-capture where the PSP and payment method support it. Where a method cannot support delayed capture, block or route through an approved alternative for regulated flows.
Required sequence for regulated flows:
BookingOfferSubmitted— customer clicks the payment-obligation button; booking offer is recorded.PaymentAuthorized— PSP authorization or payment intent created, if the payment method supports it. No capture yet.BookingAccepted— operator auto-accepts or manually accepts according to product rules.SicherungsscheinIssued— system resolves the operator's valid insolvency-protection data and attaches the document.DocumentsDelivered— durable-medium delivery is sent and logged.PaymentCaptureRequested— only after required document delivery proof exists.PaymentCaptured/DepositPaid— ledger revenue fact is updated.
Current Busflow impact:
PENDING_PAYMENTis too coarse for regulated checkout. It should be split or supplemented withOFFER_SUBMITTED,ACCEPTED_PENDING_DOCUMENTS,DOCUMENTS_DELIVERED, andCAPTURE_PENDING.PaymentReceivedremains the financial fact.BookingConfirmedshould mean legal confirmation/document delivery, not merely deposit payment.CostingBaselineLockedshould be a separate internal accounting event.
3. Billing Configuration & DACH Localization
Legal Constraint
Deposit limits, final-payment timing, insolvency protection, and registration/guarantee mechanisms vary by country. Germany, Austria, and Switzerland cannot share one hard-coded profile.
Technical Action
Implement a RegionPolicyEngine:
interface RegionPolicyEngine {
resolve(input: {
operatorCountry: 'DE' | 'AT' | 'CH';
travelerCountry?: 'DE' | 'AT' | 'CH';
classification: TravelComplianceClassification;
departureDate: string;
bookingDate: string;
}): RegionPolicy;
}Initial policy table, pending counsel:
| Configuration | Default | Validation | Notes |
|---|---|---|---|
Deposit % (DE) | 20% | Soft cap 20%; hard cap pending counsel, proposed 40% | Above 20% requires documented operator justification. |
Final payment due (DE) | 30 days before departure | Must not be earlier than counsel-approved limit | Current docs use 28/30-day defaults; normalize before implementation. |
Final payment due (AT) | 20 days before departure | Must not be earlier than counsel-approved limit | Validate against Austrian counsel before implementation. |
Max advance booking (AT) | 11 months | Block regulated checkout if exceeded | Validate against Austrian counsel before implementation. |
Current Busflow impact:
deposit_configshould move from pure operator preference to policy-validated configuration.final_payment_configshould be validated by jurisdiction.sicherungsschein_urlis too weak long term; use structured insolvency-protection records with issuer, policy ID, validity dates, document hash, and jurisdiction.
4. Ticketing, Overdue Payments & Default
Legal Constraint
Withholding boarding for non-payment is different from cancelling the contract. Overdue final payment needs a reminder and cure-period flow before cancellation side effects.
Technical Action
Separate confirmation from boarding pass:
- At deposit or legal confirmation: send confirmation without boarding-valid QR/barcode unless counsel approves early boarding validity.
- At full payment: generate and deliver the boarding-valid ticket.
- On overdue payment: transition to
PAYMENT_OVERDUE, send reminder with dynamic cure-period date. - On grace-period expiry: transition to
PENDING_CANCELLATION. - Cancellation requires operator approval or a logged formal declaration workflow; no silent deletion.
Current Busflow impact:
Ticket.statuscurrently supportsACTIVE/VOIDED; addboarding_validor a richer lifecycle such asISSUED_NOT_VALID,BOARDING_VALID,VOIDED.- ADR-014 currently allows
DEPOSIT_PAIDissuance. Keep "ticket artifact issuance" configurable, but make "boarding validity" a separate rule. FinalPaymentOverdueshould not directly void tickets unless the formal cancellation workflow has completed.
5. Document Delivery & Consumer Rights
Legal Constraint
Pre-contractual information must be shown before checkout in regulated flows. Dated travel services generally should not receive standard 14-day e-commerce withdrawal forms if counsel confirms the exclusion applies.
Technical Action
Enforce UI sequencing:
| Document | Timing | Required action |
|---|---|---|
| Standard Info / Formblatt | Pre-checkout | Native display or prominent link above the button; record display and acknowledgment. |
| AGB + cancellation policy | Pre-checkout | Unchecked checkbox; store version/hash and timestamp. |
| No withdrawal right notice | Pre-checkout | Counsel-approved text; do not show generic withdrawal form unless policy requires it. |
| Booking confirmation | Post-acceptance | Emailed PDF / durable medium. |
| Sicherungsschein | Before payment capture/acceptance in regulated flows | Emailed PDF / durable medium, with delivery proof. |
Current Busflow impact:
legal_consent_snapshotshould include all required document hashes and display/delivery timestamps, not only AGB/privacy/Formblatt flags.- Communications must emit durable-delivery proof events usable by the payment saga.
6. Cancellation & Refund Engine
Legal Constraint
Refund timing and cancellation fee logic are legally sensitive. For package travel, refunds must be processed within the statutory deadline. Substitute travelers need their own workflow and should not be treated as cancellation.
Technical Action
- On
Cancelled, calculate refund from paid amount minus applicable cancellation fee. - Trigger Mollie refund immediately where possible.
- If automation cannot refund, alert operator on days 1, 7, and 12.
- Add
SubstituteTravelerRequested/SubstituteTravelerAcceptedworkflow with admin fee, not percentage cancellation tiers. - Keep partial cancellation line-item based: passenger, ancillary, seat upgrade, excursion, insurance.
Current Busflow impact:
cancellation-protocol.mdalready has line-item cancellation, but needs policy validation envelopes and substitute-traveler flow.- Refund deadline monitoring belongs in Commerce, with Communications alerts.
7. WORM Audit Ledger
Legal Constraint
Disputes and regulatory reviews require immutable proof of sequence: disclosure, acceptance, document delivery, payment capture, cancellation, and refund.
Technical Action
Implement append-only audit events. Required fields/events:
timestamp_checkout_submitip_addressuser_agent_hashagb_version_idcancellation_policy_version_idformblatt_displayed_flagclassification_result_idsicherungsschein_document_hashtimestamp_documents_deliveredtimestamp_email_delivery_receipttimestamp_payment_capturetimestamp_cancellation_executedtimestamp_refund_processed- previous-event hash for tamper evidence
Invariant:
- In regulated flows,
timestamp_payment_capturemust be after required document delivery proof.
Current Busflow impact:
- Existing
change_events/ audit patterns should be checked before introducing a new ledger table. - If a new table is needed, model it as append-only and never use it for mutable workflow state.
Implementation Phases
| Phase | Goal | Output |
|---|---|---|
| 0 | Counsel sign-off | Ratified DE rules, payment-flow role, and document templates. |
| 1 | Classification foundation | ClassificationResult, rule versioning, UI blockers, audit snapshot. |
| 2 | Regulated payment saga | Authorization/capture split, document delivery gate, PSP capability checks. |
| 3 | Ticket validity split | Ticket artifact vs boarding-valid state, driver scanner check. |
| 4 | Cancellation/refund hardening | Refund SLA alerts, substitute traveler flow, line-item policy envelopes. |
| 5 | DACH expansion | AT/CH policy modules only after local counsel validation. |
Open Counsel Questions Before Implementation
- Does the classification threshold use per-person price, booking total, advertised product price, or another statutory price basis?
- Which payment methods support authorization-before-capture in the chosen PSP flow, and what is the compliant fallback?
- Is a generic Sicherungsschein URL sufficient, or must each booking receive a generated document tied to the exact operator/trip?
- What hard cap should Busflow enforce for deposits above 20%?
- What exact final-payment timing limits apply in DE, AT, and CH?
- Is early non-boarding-valid ticket issuance acceptable, or should all ticket artifacts wait until full payment?
- Can any overdue-payment cancellation step be automated if the system sends the formal declarations on durable medium?
- What exact WORM retention period applies across legal, tax, and GDPR constraints?