Busflow Docs

Internal documentation portal

Skip to content
Reviewed 23 May 2026

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, and sicherungsschein_url.
  • Communications already owns durable delivery of transactional messages and booking documents.
  • The current docs now decouple DEPOSIT_PAID from BookingConfirmed conceptually, 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_pauschalreise toggle 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

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_FLOW
  • EXEMPT_FLOW
  • MANUAL_REVIEW_FLOW

Required Inputs

VariableTypeMeaning
includes_overnightBooleanWhether the trip includes any overnight stay. In Busflow, this usually implies transport + accommodation, but accommodation-only edge cases must not be inferred.
duration_hoursIntegerTrip duration from departure to return.
total_price_gross_centsIntegerTotal 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_arrayEnum arrayService composition: TRANSPORT, ACCOMMODATION, RENTAL, TOURIST_SERVICE.
tourist_service_value_pctFloatTourist-service value share for the 25% / essential-character test.
tourist_service_essential_characterBooleanWhether tourist services are marketed as an essential feature even below 25%.
b2b_framework_activeBooleanVerified business-travel framework-contract exemption.
operator_countryEnumJurisdiction profile for operator obligations.
traveler_countryEnumPassenger-facing legal context, if required by counsel.
departure_dateDateDrives payment, cancellation, and refund timing.
booking_dateDateDrives 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_array count is not enough when the second service is only a tourist service. The 25% / essential-character test matters.
  • b2b_framework_active must be a verified commercial context, not a checkout checkbox.
  • Store both the computed enum and the rationale.

Output

typescript
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

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:

  1. BookingOfferSubmitted — customer clicks the payment-obligation button; booking offer is recorded.
  2. PaymentAuthorized — PSP authorization or payment intent created, if the payment method supports it. No capture yet.
  3. BookingAccepted — operator auto-accepts or manually accepts according to product rules.
  4. SicherungsscheinIssued — system resolves the operator's valid insolvency-protection data and attaches the document.
  5. DocumentsDelivered — durable-medium delivery is sent and logged.
  6. PaymentCaptureRequested — only after required document delivery proof exists.
  7. PaymentCaptured / DepositPaid — ledger revenue fact is updated.

Current Busflow impact:

  • PENDING_PAYMENT is too coarse for regulated checkout. It should be split or supplemented with OFFER_SUBMITTED, ACCEPTED_PENDING_DOCUMENTS, DOCUMENTS_DELIVERED, and CAPTURE_PENDING.
  • PaymentReceived remains the financial fact.
  • BookingConfirmed should mean legal confirmation/document delivery, not merely deposit payment.
  • CostingBaselineLocked should be a separate internal accounting event.

3. Billing Configuration & DACH Localization

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:

typescript
interface RegionPolicyEngine {
  resolve(input: {
    operatorCountry: 'DE' | 'AT' | 'CH';
    travelerCountry?: 'DE' | 'AT' | 'CH';
    classification: TravelComplianceClassification;
    departureDate: string;
    bookingDate: string;
  }): RegionPolicy;
}

Initial policy table, pending counsel:

ConfigurationDefaultValidationNotes
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 departureMust not be earlier than counsel-approved limitCurrent docs use 28/30-day defaults; normalize before implementation.
Final payment due (AT)20 days before departureMust not be earlier than counsel-approved limitValidate against Austrian counsel before implementation.
Max advance booking (AT)11 monthsBlock regulated checkout if exceededValidate against Austrian counsel before implementation.

Current Busflow impact:

  • deposit_config should move from pure operator preference to policy-validated configuration.
  • final_payment_config should be validated by jurisdiction.
  • sicherungsschein_url is too weak long term; use structured insolvency-protection records with issuer, policy ID, validity dates, document hash, and jurisdiction.

4. Ticketing, Overdue Payments & Default

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.status currently supports ACTIVE / VOIDED; add boarding_valid or a richer lifecycle such as ISSUED_NOT_VALID, BOARDING_VALID, VOIDED.
  • ADR-014 currently allows DEPOSIT_PAID issuance. Keep "ticket artifact issuance" configurable, but make "boarding validity" a separate rule.
  • FinalPaymentOverdue should not directly void tickets unless the formal cancellation workflow has completed.

5. Document Delivery & Consumer Rights

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:

DocumentTimingRequired action
Standard Info / FormblattPre-checkoutNative display or prominent link above the button; record display and acknowledgment.
AGB + cancellation policyPre-checkoutUnchecked checkbox; store version/hash and timestamp.
No withdrawal right noticePre-checkoutCounsel-approved text; do not show generic withdrawal form unless policy requires it.
Booking confirmationPost-acceptanceEmailed PDF / durable medium.
SicherungsscheinBefore payment capture/acceptance in regulated flowsEmailed PDF / durable medium, with delivery proof.

Current Busflow impact:

  • legal_consent_snapshot should 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

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 / SubstituteTravelerAccepted workflow with admin fee, not percentage cancellation tiers.
  • Keep partial cancellation line-item based: passenger, ancillary, seat upgrade, excursion, insurance.

Current Busflow impact:

  • cancellation-protocol.md already 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

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_submit
  • ip_address
  • user_agent_hash
  • agb_version_id
  • cancellation_policy_version_id
  • formblatt_displayed_flag
  • classification_result_id
  • sicherungsschein_document_hash
  • timestamp_documents_delivered
  • timestamp_email_delivery_receipt
  • timestamp_payment_capture
  • timestamp_cancellation_executed
  • timestamp_refund_processed
  • previous-event hash for tamper evidence

Invariant:

  • In regulated flows, timestamp_payment_capture must 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

PhaseGoalOutput
0Counsel sign-offRatified DE rules, payment-flow role, and document templates.
1Classification foundationClassificationResult, rule versioning, UI blockers, audit snapshot.
2Regulated payment sagaAuthorization/capture split, document delivery gate, PSP capability checks.
3Ticket validity splitTicket artifact vs boarding-valid state, driver scanner check.
4Cancellation/refund hardeningRefund SLA alerts, substitute traveler flow, line-item policy envelopes.
5DACH expansionAT/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?

References

Internal documentation — Busflow