All diagrams //1 of 1
Open Appointment Single Booking
🍋
Appointment Single Booking
27 Jul, 2026
flowchart TD
%% ===== SINGLE APPOINTMENT (1:1) — worktree1 (4c62bbd7, FA-631-streamline) =====
Start(["Kunde wählt Trainer + freien TimeSlot"])
subgraph BUCHUNG["1 · Buchung"]
direction TB
Card{"Zahlungsmethode<br/>hinterlegt?"}
NoCard["Abbruch:<br/>Karte erforderlich"]
Accepted["Appointment: ACCEPTED<br/>Order: OPEN<br/>TimeSlot: geschlossen"]
end
subgraph ZAHLUNG["2 · Zahlung (Off-Session, ChargeStoredPaymentMethodAction)"]
direction TB
Processing["Order: PAYMENT_PROCESSING"]
Reauth["3DS / SCA nötig<br/>Kunde authentifiziert (Reauth)"]
Hook{"Stripe Webhook"}
FailSync["Order: PAYMENT_FAILED<br/>Appointment: DECLINED<br/>TimeSlot: wieder offen<br/>(sync Karten-Ablehnung)"]
FailAsync["Order: PAYMENT_FAILED<br/>Appointment bleibt ACCEPTED<br/>Slot bleibt zu<br/>(async Webhook)"]
Paid["Order: PAID<br/>Appointment: BOOKED<br/>+ Handshake-Code, Rechnung,<br/>Benachrichtigung Kunde + Trainer"]
end
subgraph DURCH["3 · Durchführung"]
direction TB
Handshake["Appointment: HANDSHAKE_DONE"]
Missed["Handshake verpasst<br/>Appointment bleibt BOOKED"]
Req["TrainingCompletionRequest: PENDING<br/>(Kunde & Trainer)"]
Completed["Appointment: COMPLETED"]
Support["Streitfall (occurred=false)<br/>Support / Operator prüft"]
end
subgraph ABSCHLUSS["4 · Abschluss"]
Reviewed["Appointment: REVIEWED"]
end
subgraph STORNO["Storno (solange Start in der Zukunft)"]
direction TB
CancelC["Order: CANCELED<br/>Appointment: CANCELED_BY_CUSTOMER<br/>TimeSlot: wieder offen"]
CancelT["Order: CANCELED<br/>Appointment: CANCELED_BY_SUPPLIER<br/>Kunde benachrichtigt"]
end
Start --> Card
Card -- "nein" --> NoCard
Card -- "ja · «Kunde» bestätigt Buchung" --> Accepted
Accepted -- "«System» Off-Session Charge" --> Processing
Processing -- "«Stripe» requires_action (3DS)" --> Reauth
Reauth --> Hook
Processing -- "«Stripe» sofortige Ablehnung (CardException)" --> FailSync
Processing -- "«System» wartet auf Webhook" --> Hook
Hook -- "payment_intent.succeeded" --> Paid
Hook -- "payment_intent.payment_failed (async)" --> FailAsync
FailSync -. "«Kunde» retryPayment (reaktiviert Termin/Slot, Order->OPEN)" .-> Processing
FailAsync -. "«Kunde» retryPayment (Order->OPEN, erneute Belastung)" .-> Processing
Paid -- "«Trainer» scannt Kunden-QR bei Session-Start" --> Handshake
Paid -. "kein Handshake" .-> Missed
Handshake -- "«System» complete-ended (nach Endzeit)" --> Completed
Missed -- "«System» detect-missed (Endzeit + 15 min)" --> Req
Req -- "beide bestätigen: fand statt" --> Completed
Req -- "occurred = false" --> Support
Completed -- "«Kunde/Trainer» Bewertung abgeben" --> Reviewed
Accepted -. "«Kunde» storniert" .-> CancelC
Paid -. "«Kunde» storniert · >12h: Gratis + Refund · <12h: KEIN Refund" .-> CancelC
FailAsync -. "«Kunde» storniert" .-> CancelC
Paid -. "«Trainer» storniert · immer Refund wenn PAID" .-> CancelT
Accepted -. "«Trainer» storniert" .-> CancelT
classDef good fill:#d4f4dd,stroke:#1a7f37,color:#0b3d1c;
classDef bad fill:#ffd7d5,stroke:#c1121f,color:#5c0a0f;
classDef wait fill:#fff3cd,stroke:#b8860b,color:#5c4400;
classDef sys fill:#dbe9ff,stroke:#1f6feb,color:#0a2a5e;
class Start,Card,Hook sys;
class Accepted,Processing,Reauth,Missed,Req wait;
class Paid,Handshake,Completed,Reviewed good;
class NoCard,FailSync,FailAsync,Support,CancelC,CancelT bad;