trihub-ernaehrung-backseatDevs/src/server/swagger.json

681 lines
26 KiB
JSON

{
"openapi": "3.0.3",
"info": {
"title": "Tri-Hub Ernährungsberatung & Booking API",
"description": "API-Spezifikation für die Angebotsübersicht (US2.1), die Paket-Detailansicht und den Buchungsservice (US2.4 Paket buchen).",
"version": "1.1.0"
},
"servers": [
{
"url": "http://localhost:3000/api",
"description": "Lokaler Node.js Entwicklungsserver"
}
],
"paths": {
"/packages": {
"get": {
"summary": "Alle Ernährungs-Pakete abrufen (Kurzübersicht)",
"description": "Liefert die Basisdaten aus packages.js für die Angebotsübersicht (US2.1).",
"tags": ["Packages"],
"responses": {
"200": {
"description": "Erfolgreiche Rückgabe der Paketliste",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PackageOverview"
}
}
}
}
}
}
}
},
"/packages/{id}": {
"get": {
"summary": "Detaillierte Paketinformationen für Detailseite & Bestellprozess abrufen",
"description": "Liefert die ausführlichen Paketdaten aus packagesdetails.js (inkl. Preis, Laufzeit, Leistungen und Varianten), um sie auf der Detailseite und in der Bestellzusammenfassung des Booking-Service anzuzeigen.",
"tags": ["Packages", "Booking"],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "Eindeutige ID des Pakets (z. B. ernaehrung-starter)",
"schema": {
"type": "string",
"example": "ernaehrung-standard"
}
}
],
"responses": {
"200": {
"description": "Detaillierte Paketdaten erfolgreich geladen",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PackageDetail"
}
}
}
},
"404": {
"description": "Paket mit dieser ID wurde nicht gefunden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/bookings/preview": {
"post": {
"summary": "Preis- und Leistungsübersicht für den Bestellprozess berechnen",
"description": "Berechnet die Bestellübersicht aus dem serverseitigen Paketkatalog. Preisangaben aus der Anfrage werden ignoriert. Ohne Varianten-ID wird bei Paketen mit Varianten die erste Variante gewählt. Es wird keine Buchung angelegt.",
"tags": ["Booking"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BookingPreviewRequest"
}
}
}
},
"responses": {
"200": {
"description": "Berechnete Bestellübersicht für das Checkout-Formular",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BookingPreviewResponse"
}
}
}
},
"400": {
"description": "Ungültige Paket- oder Varianten-ID",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/bookings": {
"post": {
"summary": "Paket verbindlich buchen (US2.4)",
"description": "Speichert Paket, gewählte Variante, Leistungen und Preise zum Buchungszeitpunkt und startet den Bestätigungsversand. Der aktuelle Ablauf simuliert die Bestellung ohne Zahlung.",
"tags": ["Booking"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BookingCreateRequest"
}
}
}
},
"responses": {
"201": {
"description": "Buchung erfolgreich angelegt (Bestellbestätigung)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BookingConfirmation"
}
}
}
},
"400": {
"description": "Fehlende oder ungültige Eingabedaten",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"200": {
"description": "Bereits gespeicherte Buchung; keine zweite Buchung oder Mail",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BookingConfirmation"
}
}
}
},
"202": {
"description": "Buchung gespeichert; Versand ausstehend, fehlgeschlagen oder unklar",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BookingConfirmation"
}
}
}
},
"409": {
"description": "Anfrageschlüssel wurde mit anderen Buchungsdaten verwendet",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"413": {
"description": "Anfrage größer als 8 KiB",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"415": {
"description": "JSON-Content-Type erforderlich",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"503": {
"description": "Speicherung oder Statusprüfung nicht verfügbar",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
},
"parameters": [
{
"name": "Idempotency-Key",
"in": "header",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
},
"description": "UUID v4; bei Wiederholung denselben Schlüssel und dieselben Buchungsdaten verwenden."
}
]
}
}
},
"components": {
"schemas": {
"PackageOverview": {
"type": "object",
"required": [
"id",
"type",
"title",
"description",
"fokus",
"anamnese",
"begleitung",
"buttonText"
],
"properties": {
"id": {
"type": "string",
"example": "ernaehrung-standard"
},
"type": {
"type": "string",
"example": "STANDARD"
},
"title": {
"type": "string",
"example": "Für Best Ager mit ersten Erfahrungen und klaren Zielen"
},
"description": {
"type": "string"
},
"fokus": {
"type": "string"
},
"anamnese": {
"type": "string"
},
"begleitung": {
"type": "string"
},
"buttonText": {
"type": "string",
"example": "Standard-Paket ansehen"
},
"highlight": {
"type": "string",
"nullable": true,
"example": "BESONDERS PASSEND"
}
}
},
"PackageVariant": {
"type": "object",
"properties": {
"variantId": {
"type": "string",
"example": "ernaehrung-premium-24"
},
"label": {
"type": "string",
"example": "24-Wochen-Variante"
},
"durationWeeks": {
"type": "integer",
"example": 24
},
"price": {
"type": "number",
"format": "float",
"example": 799.0,
"description": "Bruttopreis der Variante inklusive MwSt."
}
}
},
"PackageDetail": {
"type": "object",
"required": [
"id",
"type",
"title",
"subtitle",
"durationWeeks",
"price",
"currency",
"taxRate",
"includedFeatures"
],
"properties": {
"id": {
"type": "string",
"example": "ernaehrung-standard"
},
"type": {
"type": "string",
"example": "STANDARD"
},
"badge": {
"type": "string",
"example": "BESONDERS PASSEND"
},
"title": {
"type": "string",
"example": "Für Best Ager mit ersten Erfahrungen und klaren Zielen"
},
"subtitle": {
"type": "string"
},
"durationWeeks": {
"type": "integer",
"example": 24
},
"durationLabel": {
"type": "string",
"example": "24 Wochen Begleitung"
},
"price": {
"type": "number",
"format": "float",
"example": 449.0,
"description": "Bruttopreis inklusive der angegebenen MwSt."
},
"currency": {
"type": "string",
"example": "EUR"
},
"billingInterval": {
"type": "string",
"example": "einmalig"
},
"taxRate": {
"type": "integer",
"example": 19
},
"summaryForBooking": {
"type": "string",
"example": "Standard-Paket Sporternährung (24 Wochen Coaching)"
},
"targetGroup": {
"type": "array",
"items": {
"type": "string"
}
},
"includedFeatures": {
"type": "array",
"items": {
"type": "string"
}
},
"processSteps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"step": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
},
"variants": {
"type": "array",
"nullable": true,
"items": {
"$ref": "#/components/schemas/PackageVariant"
}
},
"ctaButtonText": {
"type": "string",
"example": "Standard-Paket jetzt buchen"
}
}
},
"BookingPreviewRequest": {
"type": "object",
"required": ["packageId"],
"properties": {
"packageId": {
"type": "string",
"example": "ernaehrung-premium"
},
"variantId": {
"type": "string",
"nullable": true,
"example": "ernaehrung-premium-52"
}
}
},
"BookingPreviewResponse": {
"type": "object",
"properties": {
"packageId": {
"type": "string",
"example": "ernaehrung-premium"
},
"variantId": {
"type": "string",
"example": "ernaehrung-premium-52",
"nullable": true
},
"title": {
"type": "string",
"example": "Für maximale Individualität und intensive 1:1-Begleitung"
},
"summaryForBooking": {
"type": "string"
},
"durationWeeks": {
"type": "integer",
"example": 52
},
"netPrice": {
"type": "number",
"format": "float",
"example": 1175.63
},
"taxAmount": {
"type": "number",
"format": "float",
"example": 223.37
},
"grossPrice": {
"type": "number",
"format": "float",
"example": 1399.0
},
"currency": {
"type": "string",
"example": "EUR"
},
"variantLabel": {
"type": "string",
"nullable": true
},
"type": {
"type": "string"
},
"subtitle": {
"type": "string"
},
"durationLabel": {
"type": "string"
},
"quantity": {
"type": "integer",
"enum": [1]
},
"billingInterval": {
"type": "string",
"example": "einmalig"
},
"taxRate": {
"type": "number",
"example": 19
},
"includedFeatures": {
"type": "array",
"items": {
"type": "string"
}
},
"processSteps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"step": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
},
"required": [
"packageId",
"variantId",
"title",
"summaryForBooking",
"durationWeeks",
"netPrice",
"taxAmount",
"grossPrice",
"currency",
"variantLabel",
"type",
"subtitle",
"durationLabel",
"quantity",
"billingInterval",
"taxRate",
"includedFeatures",
"processSteps"
]
},
"BookingCreateRequest": {
"type": "object",
"required": ["packageId"],
"properties": {
"packageId": {
"type": "string",
"example": "ernaehrung-standard"
},
"variantId": {
"type": "string",
"nullable": true,
"example": "ernaehrung-premium-52"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 120,
"example": "Thomas Müller"
},
"email": {
"type": "string",
"format": "email",
"maxLength": 254,
"example": "thomas.mueller@example.de"
},
"phone": {
"type": "string",
"maxLength": 50,
"description": "Optionale Telefonnummer bei Übergabe von name und email, ohne Steuerzeichen. Bei customer gilt customer.phone.",
"example": "+49 170 1234567"
},
"customer": {
"type": "object",
"required": ["firstName", "lastName", "email"],
"properties": {
"firstName": {
"type": "string",
"example": "Thomas"
},
"lastName": {
"type": "string",
"example": "Müller"
},
"email": {
"type": "string",
"format": "email",
"example": "thomas.mueller@example.de"
},
"phone": {
"type": "string",
"example": "+49 170 1234567"
},
"ageGroup": {
"type": "string",
"example": "50-59"
},
"notes": {
"type": "string",
"example": "Vorbereitung auf meine erste Mitteldistanz im August."
}
}
},
"acceptedTerms": {
"type": "boolean",
"example": true,
"enum": [true]
}
},
"anyOf": [
{
"required": ["customer", "acceptedTerms"]
},
{
"required": ["name", "email"]
}
],
"description": "Kundendaten gemäß customer mit acceptedTerms=true. Bestehende Clients können alternativ name und email sowie optional phone übergeben."
},
"BookingConfirmation": {
"type": "object",
"properties": {
"bookingId": {
"type": "string",
"example": "TH-000001"
},
"status": {
"type": "string",
"example": "CONFIRMED"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"bookedPackage": {
"allOf": [
{
"$ref": "#/components/schemas/BookingPreviewResponse"
}
],
"nullable": true,
"description": "Gespeicherter Bestellstand; bei älteren Buchungen ohne diese Daten null."
},
"customerEmail": {
"type": "string",
"example": "thomas.mueller@example.de"
},
"packageId": {
"type": "string"
},
"packageName": {
"type": "string"
},
"saved": {
"type": "boolean"
},
"emailStatus": {
"type": "string",
"enum": ["pending", "accepted", "failed", "unknown"],
"description": "accepted bedeutet SMTP-Annahme, keine bestätigte Zustellung."
},
"replayed": {
"type": "boolean"
}
}
},
"ErrorResponse": {
"type": "object",
"required": ["error"],
"properties": {
"error": {
"type": "object",
"required": ["code", "message"],
"properties": {
"code": {
"type": "string",
"example": "INVALID_VARIANT"
},
"message": {
"type": "string"
},
"fields": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
}
}
}
}