{
    "openapi": "3.1.0",
    "info": {
        "title": "Bookitly Hold API",
        "version": "1.9.0",
        "summary": "Property Management System für den Hotelbetrieb — REST-API für Stammdaten, Raten und Buchungen",
        "description": "Bookitly Hold ist das Property-Management-System (PMS) für kleine und\nmittlere Hotels im DACH-Raum. Diese OpenAPI-Spezifikation beschreibt die\nöffentliche REST-Schnittstelle für Integrationen mit Channel-Managern,\nBooking-Engines, Buchhaltungs-Systemen und eigenen Tools.\n\n## Datenmodell\n\nEin Account verwaltet ein oder mehrere **Hotels** (Property). Jedes Hotel\nhat **Zimmerkategorien** (UnitGroup, z. B. „Doppelzimmer Komfort\") und\nunter jeder Kategorie die konkreten **Zimmer** (Unit, z. B. Zimmer 101).\nAn Zimmerkategorien hängen **Ratenpläne** (RatePlan, z. B. „Flexibel mit\nFrühstück\"). **Zimmermerkmale** (Amenity, z. B. Balkon, Dusche) sind ein\nzentraler Katalog pro Account und werden Kategorien und einzelnen Zimmern\nzugeordnet.\n\n```\nHotel ─┬─ Zimmerkategorie ─┬─ Zimmer (101, 102, …)\n       │                   │\n       │                   └─ Ratenplan (FLEX-BB, NONREF, …)\n       │\n       └─ Merkmale-Katalog (Balkon, Dusche, WLAN, …)\n             │\n             ├─ Default-Merkmale der Zimmerkategorie\n             └─ Merkmale des einzelnen Zimmers\n```\n\n## Authentifizierung\n\nAlle Endpunkte außer `/api/health` brauchen einen **Bearer-Token** im\n`Authorization`-Header:\n\n```\nAuthorization: Bearer <access_token>\n```\n\nEs gibt **zwei Token-Arten**, die alle authentifizierten Endpunkte\ntransparent akzeptieren:\n\n### 1. User-Token (für die SPA)\n\nÜber `POST /api/control/auth/login` mit E-Mail + Passwort. Lebenszeit\n24 Stunden. Wird intern von der Web-Oberfläche verwendet.\n\n### 2. Client-Credentials-Token (für Integrationen, M2M)\n\nStandard OAuth2 Client-Credentials-Grant für Maschine-zu-Maschine-\nAnbindungen (Channel-Manager, Booking-Engines, ERP-Connectoren).\n\n**Setup (durch Bookitly):**\n1. Bookitly stellt einen Client (UUID + Secret) aus.\n2. Bookitly verknüpft den Client mit deinem Hotel-Account (Tenant).\n3. Du erhältst `client_id` + `client_secret`.\n\n**Token holen:**\n\n```\nPOST /oauth/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=client_credentials\n&client_id=<UUID>\n&client_secret=<Secret>\n```\n\nAntwort:\n\n```json\n{\n  \"token_type\": \"Bearer\",\n  \"expires_in\": 86400,\n  \"access_token\": \"eyJ0eXAi...\"\n}\n```\n\n**Tenant-Auflösung:** Der Client ist serverseitig genau einem Hotel-Account\nzugeordnet (`oauth_client_tenant`-Pivot in der Control-Plane). Alle\n`/api/*`-Calls mit diesem Token sind automatisch auf diesen Tenant\ngescoped — kein zusätzlicher Tenant-Header nötig, kein Kontext-Wechsel\nmöglich.\n\n**Berechtigungen:** Client-Tokens umgehen das Permission-System (das nur\nfür menschliche User gilt) und haben den vollen Lese-/Schreib-Zugriff\nauf den verknüpften Tenant. Vertrauen wird über die Client-Tenant-\nZuordnung gewährt — ein böswilliger Client betrifft nur seinen eigenen\nTenant. Granulare Token-Scopes sind ein Followup-Feature.\n\n**Erste Schritte:** siehe `docs/patterns/m2m-auth.md` im Repo für\nCode-Beispiele in PHP, Python und cURL plus Troubleshooting.\n\nZugänge für Integrationen werden administrativ durch Bookitly ausgestellt —\nSelf-Service-Registrierung gibt es nicht. Schreib an `api@bookitly.de`,\nwenn du einen Integrationszugang brauchst.\n\n## API-Routing — zwei Namespaces\n\n- `/api/control/*` — Login, Profil, Account-Wechsel. Immer unter der\n  in dieser Spec hinterlegten Server-URL erreichbar.\n- `/api/*` (ohne `control/`) — Business-Daten. Die **Base-URL** für\n  diese Endpunkte kommt in der Login-Response als `api_base_url`. Dein\n  Client soll Business-Calls dorthin schicken; in den meisten Fällen\n  ist das dieselbe URL wie die Control-Plane, kann aber account-abhängig\n  abweichen.\n\n## Hotel-Kontext und Account-Wechsel\n\nDer aktive Hotel-Kontext ist Teil des Tokens — serverseitig wird jeder\nRequest auf das aktive Hotel gescoped, Cross-Account-Zugriffe sind\nsystemisch ausgeschlossen.\n\nUser, die zu mehreren Hotels verknüpft sind, können über\n`POST /api/control/session/tenant` den aktiven Kontext wechseln — die\nAntwort enthält einen neuen Token mit geändertem Hotel-Bezug und die\npassende `api_base_url`. Verfügbare Hotels liefert\n`GET /api/control/auth/me` im Feld `available_tenants`.\n\n## Konventionen\n\n- **IDs sind UUIDs** (Format: String, z. B. `019da213-2e5f-725a-a06e-…`).\n- **Kürzel** (`code` auf Property, UnitGroup, RatePlan, Amenity, sowie\n  `number` auf Unit) sind stabile Identifier. Einmal angelegt sind sie\n  nicht mehr änderbar — externe Systeme referenzieren darüber.\n- **Property-Endpunkte akzeptieren UUID *oder* Code** als Pfad-Parameter\n  (case-insensitive). `/api/properties/019da213-…` und `/api/properties/LEB`\n  liefern dasselbe Hotel. Bei anderen Entitäten ist\n  ausschließlich die UUID erlaubt.\n- **Soft-Delete**: `DELETE` markiert Entitäten als gelöscht; sie\n  verschwinden aus Listen und Einzelabrufen. Wiederherstellung nur\n  administrativ.\n- **Antwort-Umschlag**: Ressourcen-Antworten sind in `{ \"data\": … }`\n  gewrappt.\n- **Fehler-Antworten**:\n    - `422` — Validierungsfehler: `{ \"message\": \"...\", \"errors\": { field: [...] } }`\n    - sonstige — `{ \"error\": \"slug\", \"message\": \"Lesbarer Hinweis.\" }`\n\n## Pagination\n\nListen-Endpunkte unterstützen zwei Modi — der Client entscheidet pro\nRequest über die Query-Parameter, kein expliziter Mode-Switch nötig.\n\n### Page-Mode (Default)\n\nStandard-Laravel-Pagination. Antwort enthält `meta.current_page`,\n`meta.last_page`, `meta.total`, `meta.per_page` und `links`-Hashes.\nGeeignet für UI-Listen mit Seitenanzeige.\n\n```\nGET /api/quotes?page=2&per_page=50\n```\n\n### Cursor-Mode (Stripe-Stil)\n\nSobald der Request einen `cursor`-Parameter mitbringt (auch leer für\nden ersten Aufruf, dann via `use_cursor=1` aktivierbar), wechselt der\nEndpunkt in den Cursor-Mode. Antwort enthält `meta.next_cursor` und\n`meta.prev_cursor` (Base64-encodiert, opaque) — der Client gibt den\nToken unverändert beim Folge-Request zurück.\n\n```\nGET /api/quotes?use_cursor=1\nGET /api/quotes?cursor=eyJpZCI6Ik5VTC...\n```\n\nCursor-Mode ist effizienter bei großen Datenmengen (Index-Range statt\nOFFSET) und ist die empfohlene Variante für externe Integrationen.\nAktuell verfügbar an `/api/quotes`; weitere Listen-Endpunkte folgen.\n\n## Versionierung\n\nÄnderungen werden nach Semver gepflegt:\n- Minor-Bumps bei neuen Endpunkten oder neuen Feldern.\n- Patch-Bumps bei Doku- und Beispiel-Korrekturen.\n- Major-Bumps bei Breaking Changes — Vorlauf wird per Changelog und\n  Ankündigung kommuniziert.\n",
        "contact": {
            "name": "Bookitly API Support",
            "email": "api@bookitly.de",
            "url": "https://bookitly.de"
        },
        "license": {
            "name": "Proprietär — © Bookitly"
        }
    },
    "servers": [
        {
            "url": "https://api.hold.bookitly.de",
            "description": "Dev-Server — Control-Plane und aktueller Shard zusammen (Go-Live bleibt diese URL die Control-Plane)"
        }
    ],
    "tags": [
        {
            "name": "Authentication",
            "description": "Login, Logout, Session-Abfrage"
        },
        {
            "name": "Session",
            "description": "Wechsel des aktiven Hotels für User mit mehreren Hotel-Kontexten"
        },
        {
            "name": "Properties",
            "description": "Hotels — jede Property ist ein konkretes Haus innerhalb eines Accounts."
        },
        {
            "name": "Unit Groups",
            "description": "Zimmerkategorien innerhalb eines Hotels (z. B. „Doppelzimmer Komfort\"). Unter einer Kategorie liegen konkrete Zimmer."
        },
        {
            "name": "Units",
            "description": "Einzelne Zimmer. Jedes Zimmer gehört zu einer Zimmerkategorie und damit zu einem Hotel."
        },
        {
            "name": "Rate Plans",
            "description": "Tarifpläne (z. B. „Flexibel\", „Nicht stornierbar\"). Jeder Tarif ist an eine Zimmerkategorie gebunden."
        },
        {
            "name": "Amenities",
            "description": "Zimmermerkmale — zentraler Katalog pro Account (Balkon, Dusche, Barrierefrei,\nMeerblick, …). Merkmale werden Zimmerkategorien und einzelnen Zimmern zugeordnet.\n"
        },
        {
            "name": "Cancellation Policies",
            "description": "Storno-Richtlinien — wiederverwendbare Regelwerke, an die Ratenpläne\ngebunden werden. Eine Policy beschreibt Stornierungsfrist\n(entweder Vorlaufzeit in Monaten/Tagen ODER Cut-off-Uhrzeit am Referenztag),\nStrafe-Art (fester Betrag, Prozent vom Buchungswert, oder erste Nacht),\nBegrenzung auf X Nächte und MwSt.-Satz.\n"
        },
        {
            "name": "Daily Pricing",
            "description": "Tages-basierte Preisgestaltung — Tagespreise, Verfügbarkeit und Restriktionen\npro RatePlan bzw. UnitGroup pro Datum. Grundlage für das Matrix-Kalender-UI\nund für OTA-Sync (Channel-Manager). Alle Endpunkte unterstützen Range-GET\n(from/to, max. 366 Tage) und Bulk-Upsert (max. 5000 Items pro Call).\n"
        },
        {
            "name": "Services",
            "description": "Extras und Zusatzleistungen pro Property (Frühstück, Parkplatz, Hund,\nWelcome-Drink, …). Mehrsprachig (Hotelsprache + Englisch), mit Verfügbarkeit,\nDistribution-Kanälen und optionalen Limitierungen (Aufenthaltsdauer + Datumsbereich).\nVerweis auf eine Altersgruppe möglich, wenn der Service nur bestimmten Gästen\nangeboten werden soll (z.B. Kindermenü nur für Kind 4-11).\n"
        },
        {
            "name": "Service Tax Configurations",
            "description": "MwSt-Konfigurationen pro Service mit Komponenten-Split. Eine Konfiguration\nhat ein `valid_from`-Datum und 1..n Komponenten (z.B. Speisen 16 EUR @ 7 %\n+ Getränke 2,50 EUR @ 19 %). Bei Rechnungslegung wird die Konfiguration\ngezogen, deren `valid_from` dem Belegdatum am nächsten (≤) liegt —\nGoBD-konform bei MwSt-Änderungen.\n"
        },
        {
            "name": "Age Groups",
            "description": "Altersgruppen pro Property (z.B. „Kind 0–3\", „Kind 4–11\", „Erwachsene\"),\nStammdaten-Modul unter Hotel. Wird von Services genutzt („Bereitgestellt für\").\nSpäter auch für Kinderpreise an Ratenplänen und Meldewesen vorgesehen.\n"
        },
        {
            "name": "Guests",
            "description": "Gäste als eigenständige Entität pro Tenant (Mews-Modell). Dauerhafte\nIdentität über mehrere Buchungen hinweg, keine eigene Gäste-Liste im\nUI — Gäste leben in ihrem Reservations-Kontext. Suchendpoint für\nAutocomplete beim Anlegen einer Reservation.\n"
        },
        {
            "name": "Reservations",
            "description": "Buchungen. Status-Flow: inquiry → booked → checked_in → checked_out\n(+ cancelled, no_show als Terminal-States). Status-Übergänge sind\nper Workflow-Endpoints (Paket 3.4) erzwungen — unerlaubte Sprünge\nwerfen 422. Automatisch generierte booking_number im Format\n`<CODE>-<YY>-<NNNN>` (z.B. LLB-26-0001). Jede Reservation kann\noptional einer ReservationGroup zugeordnet werden (`group_id`).\n"
        },
        {
            "name": "Reservation Workflow",
            "description": "Status-Transitions an Reservations — Check-In, Check-Out (mit\nSaldo-Blockade und `force`-Override), Cancel (voidet alle Charges),\nNo-Show (Charges bleiben aktiv), Confirm (inquiry → booked).\nZimmer-Zuweisung als separater Endpoint (Paket 3.9).\n"
        },
        {
            "name": "Reservation Groups",
            "description": "Gruppenbuchungen — Container über mehreren Einzelreservations\n(Hochzeiten, Firmenseminare, Reisegruppen, Hotelkontingente).\nJede Einzelreservation bleibt autonom (eigenes Folio, eigener\nGast, eigene An-/Abreise). Die Gruppe klammert nur. Zusätzlich\nein **Gruppen-Folio** für gruppenweite Posten (Hochzeitsmenü,\nSektempfang) und konsolidierte Rechnungen. Charges können\nbidirektional zwischen Einzel- und Gruppen-Folio transferiert\nwerden.\n"
        },
        {
            "name": "Folios",
            "description": "Konto pro Reservation **oder** Gruppe. DB-CHECK:\ngenau eines von `reservation_id` / `group_id` gesetzt.\nNimmt Charges auf, Zahlungen werden darauf gebucht, Rechnungen\nwerden daraus erstellt. Status `open` (mutierbar) oder `closed`\n(nach Check-Out/Abrechnung).\n"
        },
        {
            "name": "Charges",
            "description": "Posten im Folio — Übernachtung (auto beim Buchen), Service, Manuell,\nDiscount. MwSt-Komponenten-Split über ChargeTaxComponents (z. B.\nMenü mit 7 % Speise + 19 % Getränk). GoBD-void über `voided_at`\nstatt Delete. **Charge-Transfer** zwischen Folios derselben Gruppe\n(Paket 4.3) — Posten wandert von Einzel- aufs Gruppen-Folio für\nFirmenrechnungen.\n"
        },
        {
            "name": "Payments",
            "description": "Zahlungseingänge auf ein Folio. Sieben Methoden (bar/Kreditkarte/EC/\nÜberweisung/Auf Rechnung/Gutschein/Sonstiges). GoBD-Refund über\n`refunded_at` + `refunded_amount` + `refund_method` — **Teil-Refunds**\nwerden als partieller Betrag erfasst, die wirksame Summe ist\n`amount - refunded_amount`. Payments sind optional einer Invoice\nzugeordnet (`invoice_id`); beim Storno der Invoice werden Payments\nfreigegeben (nicht refundiert).\n"
        },
        {
            "name": "Invoices",
            "description": "Rechnungen — schneiden eine Teilmenge der Charges eines Folios ab\n(Invoice-orientiertes Modell — Folio bleibt offen, Rechnungen schneiden Charge-Mengen heraus). Fortlaufende\nNummerierung pro Property, nach erster Rechnung gelockt.\nGoBD-Storno erzeugt Reversal-Rechnung mit Negativ-Summen und gibt\ndie Charges + Payments frei für Neuausstellung. PDF-Download per\ndompdf, SMTP-Versand über Property-eigenen Mailer (Paket 3.7c).\nSplit: Charges beim Rechnungs-Erstellen pro Posten auswählbar\n(Firma/Gast-Aufteilung). **Empfänger-Dropdown** (Paket 3.10):\n`recipient_guest_id` zieht Name/Adresse/Email aus der Guest-DB,\nbei `company_name` im Format „Firma · z. Hd. Person\".\n"
        },
        {
            "name": "Quotes",
            "description": "Angebote (Quotes) — der Hotelier verschickt eine **Mini-Homepage** mit\neiner oder mehreren Zimmer-Optionen an einen Gast. Jede Option ist\neine echte Reservation mit Status `option` und blockt damit das Zimmer\nin der Verfügbarkeits-Suche für 3, 7 oder 14 Tage. Der Gast bekommt\neinen Token-Link per Mail (über den Property-eigenen SMTP), öffnet die\nPublic-Page und kann eine Option annehmen oder das Angebot ablehnen.\nBei Annahme wird die gewählte Reservation auf `booked` gesetzt + Folio\nangelegt, andere Optionen werden storniert.\nStatus-Flow: `draft → sent → accepted | declined | expired | withdrawn`.\nToken: SHA-256-Hash in der DB, Plaintext nur im Mail-Link (32 hex).\nPublic-Lookup geht über einen globalen Pointer-Index in der\nControl-Plane (`quote_token_index`), Skalierung unabhängig von der\nTenant-Anzahl.\n**Sprache pro Quote** (`language`: `de` | `en`) — bestimmt die\nSprache der Mini-Homepage und der Mail. Default ist die\nProperty-Primärsprache.\n"
        },
        {
            "name": "Quote Templates",
            "description": "Angebotsvorlagen — pro Property eine Liste benannter Anschreiben\n(z. B. „Tagung\", „Hochzeit\", „Standard-Anfrage\"), jede mit Texten in\nDeutsch und Englisch. Im Wizard wählt der User die Vorlage per\nDropdown — der passende Sprach-Text wird in das Anschreiben-Feld\nkopiert und ist editierbar. Archivierbar (`archived_at`), nicht\nhart gelöschen — gilt das Stammdaten-Pattern.\n"
        },
        {
            "name": "Apps",
            "description": "Externe Integrationen. Eine **App** buendelt einen OAuth-Client\n(fuer eingehende API-Calls vom Integrator) und N Webhook-Subscriptions\n(fuer ausgehende Events an den Integrator). Aktueller Anbindungs-Modus:\nmanuell — Inhaber legt App an, gibt `client_id` + `client_secret`\neinmalig an den Integrator weiter. OAuth2-Authorization-Code-Flow\nist Followup.\n"
        },
        {
            "name": "Webhooks",
            "description": "Webhook-Subscriptions als Sub-Resource einer App. Ausgehende\nHTTP-POST-Calls an die URL des Integrators bei Domain-Events,\nmit HMAC-SHA256-Signatur und Retry-Backoff. Empfaenger-Implementation:\nsiehe `docs/patterns/webhooks.md` im Repo (HMAC-Verifikation in\nPHP/Python/Node, Idempotenz-Pattern, Troubleshooting).\n"
        },
        {
            "name": "System",
            "description": "Health-Check"
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "paths": {
        "/oauth/token": {
            "post": {
                "tags": [
                    "Authentication"
                ],
                "summary": "OAuth2 Client-Credentials-Grant — Token holen (Maschine-zu-Maschine)",
                "description": "Standard OAuth2-Endpoint für den Client-Credentials-Flow.\nDer zurückgegebene Token wird wie ein User-Token verwendet\n(Bearer-Header), ist serverseitig aber automatisch dem\nverknüpften Hotel-Tenant zugeordnet.\n\nToken-Lebenszeit: **24 Stunden**. Tokens werden NICHT erneuert —\nkurz vor Ablauf einfach einen neuen anfragen.\n\nDer Endpoint ist **nicht** unter der API-Authentifizierung (kein\nBearer-Header nötig) und akzeptiert Form-URL-encoded Body.\n",
                "security": [],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "grant_type",
                                    "client_id",
                                    "client_secret"
                                ],
                                "properties": {
                                    "grant_type": {
                                        "type": "string",
                                        "enum": [
                                            "client_credentials"
                                        ]
                                    },
                                    "client_id": {
                                        "type": "string",
                                        "format": "uuid",
                                        "description": "Vom Bookitly ausgestellt"
                                    },
                                    "client_secret": {
                                        "type": "string",
                                        "description": "Vom Bookitly ausgestellt"
                                    },
                                    "scope": {
                                        "type": "string",
                                        "description": "Aktuell ignoriert — Tokens haben vollen Zugriff auf den verknüpften Tenant"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Token ausgestellt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "token_type": {
                                            "type": "string",
                                            "enum": [
                                                "Bearer"
                                            ]
                                        },
                                        "expires_in": {
                                            "type": "integer",
                                            "description": "Sekunden bis Ablauf — typisch 86400 (24h)"
                                        },
                                        "access_token": {
                                            "type": "string",
                                            "description": "JWT, im Authorization-Header verwenden"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "client_id oder client_secret ungültig"
                    },
                    "400": {
                        "description": "Fehlerhafter Request (z.B. fehlender Parameter)"
                    }
                }
            }
        },
        "/api/health": {
            "get": {
                "tags": [
                    "System"
                ],
                "summary": "Health-Check",
                "description": "Gibt den Status der API zurück. Erfordert keine Authentifizierung.",
                "security": [],
                "responses": {
                    "200": {
                        "description": "API ist verfügbar",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/HealthResponse"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/control/auth/login": {
            "post": {
                "tags": [
                    "Authentication"
                ],
                "summary": "Benutzer anmelden",
                "description": "Loggt einen User ein und gibt einen Bearer-Token zurück. Zusätzlich kommt\nim Response der aktive Tenant, alle verfügbaren Tenants für den User, und\ndie Base-URL des zum aktiven Tenant gehörenden Shards.\n",
                "security": [],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LoginRequest"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Login erfolgreich",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LoginResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "E-Mail oder Passwort falsch",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorResponse"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "User hat kein aktives Tenant-Mapping",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ErrorResponse"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Validierungsfehler",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ValidationError"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate-Limit überschritten (10 Versuche/Minute)"
                    }
                }
            }
        },
        "/api/control/auth/me": {
            "get": {
                "tags": [
                    "Authentication"
                ],
                "summary": "Aktuelle Session abfragen",
                "description": "Gibt User, aktiven Tenant und Shard-Info des aktuell authentifizierten Users zurück.",
                "responses": {
                    "200": {
                        "description": "Session-Daten",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SessionContext"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Nicht authentifiziert"
                    }
                }
            }
        },
        "/api/control/auth/logout": {
            "post": {
                "tags": [
                    "Authentication"
                ],
                "summary": "Token widerrufen",
                "description": "Revoke des aktuell verwendeten Bearer-Tokens. Der Token kann nach diesem Aufruf nicht mehr verwendet werden.",
                "responses": {
                    "200": {
                        "description": "Logout erfolgreich",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "status": {
                                            "type": "string",
                                            "example": "logged_out"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/control/session/tenant": {
            "post": {
                "tags": [
                    "Session"
                ],
                "summary": "Aktiven Tenant wechseln",
                "description": "Wechselt den aktiven Tenant des Users. Setzt `is_default=true` auf die\ngegebene Tenant-Zuordnung (und damit `false` auf alle anderen). Die\nResponse enthält die neue Shard-URL.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "tenant_id"
                                ],
                                "properties": {
                                    "tenant_id": {
                                        "type": "string",
                                        "format": "uuid",
                                        "example": "019d9e12-0a7c-7040-9dff-da5ee90408cf"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Tenant gewechselt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SessionContext"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "User hat keinen Zugriff auf diesen Tenant"
                    },
                    "404": {
                        "description": "Tenant nicht gefunden"
                    }
                }
            }
        },
        "/api/properties": {
            "get": {
                "tags": [
                    "Properties"
                ],
                "summary": "Alle Properties des aktiven Tenants auflisten",
                "responses": {
                    "200": {
                        "description": "Liste der Properties",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Property"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Properties"
                ],
                "summary": "Neue Property anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PropertyInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Property angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Property"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Validierungsfehler"
                    }
                }
            }
        },
        "/api/properties/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "description": "Property-UUID **oder** Property-Code (case-insensitive).\n`/api/properties/019da213-...` und `/api/properties/LEB` adressieren dasselbe Hotel.\n",
                    "schema": {
                        "type": "string",
                        "examples": [
                            "019da213-2e5f-725a-a06e-3a8f1c4b6d20",
                            "LEB"
                        ]
                    }
                }
            ],
            "get": {
                "tags": [
                    "Properties"
                ],
                "summary": "Einzelne Property anzeigen",
                "responses": {
                    "200": {
                        "description": "Property-Details",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Property"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Nicht gefunden"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Properties"
                ],
                "summary": "Property aktualisieren",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PropertyInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Property aktualisiert"
                    },
                    "404": {
                        "description": "Nicht gefunden"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Properties"
                ],
                "summary": "Property löschen (soft-delete)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    },
                    "404": {
                        "description": "Nicht gefunden"
                    }
                }
            }
        },
        "/api/unit-groups": {
            "get": {
                "tags": [
                    "Unit Groups"
                ],
                "summary": "Alle Zimmerkategorien des aktiven Tenants auflisten",
                "description": "Liefert alle UnitGroups, sortiert nach Position+Code. Optionaler Filter via ?property_id=.",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "Wenn gesetzt, nur UnitGroups dieser Property zurueckgeben."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste der UnitGroups",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/UnitGroup"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Unit Groups"
                ],
                "summary": "Neue UnitGroup anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UnitGroupInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "UnitGroup angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/UnitGroup"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Validierungsfehler (z.B. doppelter code in derselben Property)"
                    }
                }
            }
        },
        "/api/unit-groups/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Unit Groups"
                ],
                "summary": "Einzelne UnitGroup anzeigen",
                "responses": {
                    "200": {
                        "description": "Details",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/UnitGroup"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Unit Groups"
                ],
                "summary": "UnitGroup aktualisieren",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UnitGroupInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Unit Groups"
                ],
                "summary": "UnitGroup löschen (soft-delete)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/api/units": {
            "get": {
                "tags": [
                    "Units"
                ],
                "summary": "Alle Zimmer des aktiven Tenants auflisten",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "unit_group_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste der Units",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Unit"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Units"
                ],
                "summary": "Neues Zimmer anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UnitInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Unit angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Unit"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Validierungsfehler"
                    }
                }
            }
        },
        "/api/units/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Units"
                ],
                "summary": "Einzelnes Zimmer anzeigen",
                "responses": {
                    "200": {
                        "description": "Details",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Unit"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Units"
                ],
                "summary": "Zimmer aktualisieren",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UnitInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Units"
                ],
                "summary": "Zimmer löschen (soft-delete)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/api/rate-plans": {
            "get": {
                "tags": [
                    "Rate Plans"
                ],
                "summary": "Alle Tarifplaene des aktiven Tenants auflisten",
                "parameters": [
                    {
                        "name": "unit_group_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste der RatePlans",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/RatePlan"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Rate Plans"
                ],
                "summary": "Neuen Tarifplan anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/RatePlanInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "RatePlan angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/RatePlan"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/rate-plans/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Rate Plans"
                ],
                "summary": "Einzelnen Tarifplan anzeigen",
                "responses": {
                    "200": {
                        "description": "Details",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/RatePlan"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Rate Plans"
                ],
                "summary": "Tarifplan aktualisieren",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/RatePlanInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Rate Plans"
                ],
                "summary": "Tarifplan löschen (soft-delete)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/api/amenities": {
            "get": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Alle Zimmermerkmale des aktiven Tenants auflisten",
                "description": "Liefert den kompletten Merkmal-Katalog, sortiert nach Kategorie, Position und Name.",
                "parameters": [
                    {
                        "name": "category",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "bathroom",
                                "comfort",
                                "accessibility",
                                "equipment",
                                "view",
                                "other"
                            ]
                        },
                        "description": "Optional auf eine Kategorie filtern."
                    },
                    {
                        "name": "only_active",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Wenn true, werden nur aktive Merkmale zurückgegeben."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste der Amenities",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Amenity"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Neues Zimmermerkmal anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AmenityInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Merkmal angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Amenity"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Validierungsfehler (z.B. doppelter code)"
                    }
                }
            }
        },
        "/api/amenities/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Einzelnes Merkmal anzeigen",
                "responses": {
                    "200": {
                        "description": "Details",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Amenity"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Merkmal aktualisieren",
                "description": "Kürzel (`code`) darf beim Update nicht mehr geändert werden — das Frontend sendet es stabil mit.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AmenityInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Merkmal löschen (soft-delete)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/api/unit-groups/{id}/amenities": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "description": "UnitGroup-ID"
                }
            ],
            "get": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Merkmale einer Zimmerkategorie auflisten",
                "description": "Liefert die Standard-Merkmale, die dieser Zimmerkategorie zugeordnet sind.",
                "responses": {
                    "200": {
                        "description": "Liste der zugeordneten Merkmale",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Amenity"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "put": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Merkmal-Liste einer Zimmerkategorie setzen",
                "description": "Setzt die komplette Merkmal-Liste der Zimmerkategorie (PUT-Semantik).\nNicht mitgeschickte Merkmale werden entfernt. Beim Anlegen eines neuen\nZimmers in dieser Kategorie werden die hier gesetzten Merkmale als\nDefault-Vorauswahl verwendet.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AmenitySyncInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Liste der gesetzten Merkmale (nach Sync)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Amenity"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/units/{id}/amenities": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "description": "Unit-ID"
                }
            ],
            "get": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Merkmale eines einzelnen Zimmers auflisten",
                "responses": {
                    "200": {
                        "description": "Liste der zugeordneten Merkmale",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Amenity"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "put": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Merkmal-Liste eines Zimmers setzen",
                "description": "Setzt die komplette Merkmal-Liste für ein einzelnes Zimmer (PUT-Semantik).\nÜberschreibt die Default-Merkmale der Zimmerkategorie — ein Zimmer kann\nzusätzliche Merkmale haben (z.B. Meerblick) oder Kategorie-Defaults\nabwählen (z.B. kein Balkon in diesem speziellen Zimmer).\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AmenitySyncInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Liste der gesetzten Merkmale",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Amenity"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/unit-groups/{id}/archive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Unit Groups"
                ],
                "summary": "Zimmerkategorie archivieren",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/unit-groups/{id}/unarchive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Unit Groups"
                ],
                "summary": "Zimmerkategorie wiederherstellen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/units/{id}/archive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Units"
                ],
                "summary": "Zimmer archivieren",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/units/{id}/unarchive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Units"
                ],
                "summary": "Zimmer wiederherstellen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/unit-blocks": {
            "get": {
                "tags": [
                    "Unit Blocks"
                ],
                "summary": "Zimmer-Sperren auflisten",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "unit_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "description": "YYYY-MM-DD, beginnt Zeitraum-Filter (mit `to` zusammen nutzen)",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/UnitBlock"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Unit Blocks"
                ],
                "summary": "Zimmer-Sperre anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UnitBlockInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/UnitBlock"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/unit-blocks/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Unit Blocks"
                ],
                "summary": "Einzelne Sperre",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/UnitBlock"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Unit Blocks"
                ],
                "summary": "Sperre aktualisieren",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UnitBlockInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/UnitBlock"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Unit Blocks"
                ],
                "summary": "Sperre aufheben",
                "responses": {
                    "204": {
                        "description": "Aufgehoben"
                    }
                }
            }
        },
        "/api/rate-plans/{id}/archive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Rate Plans"
                ],
                "summary": "Tarifplan archivieren",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/rate-plans/{id}/unarchive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Rate Plans"
                ],
                "summary": "Tarifplan wiederherstellen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/amenities/{id}/archive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Zimmermerkmal archivieren",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/amenities/{id}/unarchive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Amenities"
                ],
                "summary": "Zimmermerkmal wiederherstellen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/cancellation-policies": {
            "get": {
                "tags": [
                    "Cancellation Policies"
                ],
                "summary": "Liste der Storno-Richtlinien",
                "parameters": [
                    {
                        "name": "include_archived",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Wenn `true`, werden archivierte Richtlinien mit ausgeliefert."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/CancellationPolicy"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            },
            "post": {
                "tags": [
                    "Cancellation Policies"
                ],
                "summary": "Neue Storno-Richtlinie anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CancellationPolicyInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CancellationPolicy"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/cancellation-policies/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Cancellation Policies"
                ],
                "summary": "Eine Storno-Richtlinie abrufen",
                "responses": {
                    "200": {
                        "description": "Richtlinie",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CancellationPolicy"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Cancellation Policies"
                ],
                "summary": "Storno-Richtlinie aktualisieren",
                "description": "`code` ist nach Anlegen immutable und wird ignoriert, falls gesendet.\nAlle anderen Felder sind editierbar.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CancellationPolicyInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CancellationPolicy"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Cancellation Policies"
                ],
                "summary": "Storno-Richtlinie löschen (Soft-Delete)",
                "description": "Für reguläres Ausblenden siehe `POST /archive`. Der Hard-Delete via\n`DELETE` entfernt die Policy soft aus der Datenbank; verknüpfte\nRatePlans behalten ihre Referenz aber sie zeigt dann auf null\n(`ON DELETE SET NULL`).\n",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            }
        },
        "/api/cancellation-policies/{id}/archive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Cancellation Policies"
                ],
                "summary": "Storno-Richtlinie archivieren",
                "description": "Setzt `archived_at` auf die aktuelle Zeit. Archivierte Richtlinien\nerscheinen nur bei `?include_archived=1` in der Liste.\n",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/cancellation-policies/{id}/unarchive": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Cancellation Policies"
                ],
                "summary": "Archivierung rückgängig machen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/daily-rates": {
            "get": {
                "tags": [
                    "Daily Pricing"
                ],
                "summary": "Tagespreise für RatePlans in einem Zeitraum abfragen",
                "description": "Gibt alle explizit gesetzten Tagespreise für die angegebenen RatePlans\nim Zeitraum zurück. Wo kein Eintrag existiert, greift die Default-\nBerechnung (Parent-Preis + Delta) — das muss der Client selbst auflösen.\n",
                "parameters": [
                    {
                        "name": "rate_plan_ids",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "maxItems": 200
                        },
                        "description": "Liste der RatePlan-IDs (max. 200)."
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        },
                        "description": "Max. 366 Tage Zeitraum."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Tagespreise",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DailyRate"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "post": {
                "tags": [
                    "Daily Pricing"
                ],
                "summary": "Tagespreise bulk-upserten",
                "description": "Atomare Bulk-Operation. Je `(rate_plan_id, date)` wird ein bestehender\nEintrag überschrieben oder ein neuer angelegt. Max. 5000 Items pro Call.\n\n**Einschränkungen:**\n - `date` maximal 3 Jahre in die Zukunft (hält die Tabelle klein).\n - Nur für Parent/Standalone-RatePlans erlaubt. Für abgeleitete RatePlans\n   (mit `parent_rate_plan_id`) gibt die API 422 zurück, da Kinder ihren Preis\n   aus Parent + Preisdifferenz berechnen.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/DailyRateBulkInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Anzahl geschriebener Items",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "written": {
                                            "type": "integer",
                                            "example": 42
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/daily-rates/{ratePlanId}/{date}": {
            "parameters": [
                {
                    "name": "ratePlanId",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                },
                {
                    "name": "date",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "date"
                    }
                }
            ],
            "delete": {
                "tags": [
                    "Daily Pricing"
                ],
                "summary": "Einen Tagespreis-Eintrag löschen",
                "description": "Nach dem Löschen greift für dieses Datum die Default-Berechnung\n(Parent + Delta) wieder.\n",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    }
                }
            }
        },
        "/api/daily-availability": {
            "get": {
                "tags": [
                    "Daily Pricing"
                ],
                "summary": "Verfügbarkeit pro UnitGroup in einem Zeitraum",
                "parameters": [
                    {
                        "name": "unit_group_ids",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "maxItems": 200
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Verfügbarkeitseinträge",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DailyAvailability"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "post": {
                "tags": [
                    "Daily Pricing"
                ],
                "summary": "Verfügbarkeit bulk-upserten",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/DailyAvailabilityBulkInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Anzahl geschriebener Items",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "written": {
                                            "type": "integer"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/daily-restrictions": {
            "get": {
                "tags": [
                    "Daily Pricing"
                ],
                "summary": "Restriktionen pro RatePlan in einem Zeitraum",
                "parameters": [
                    {
                        "name": "rate_plan_ids",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "array",
                            "items": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "maxItems": 200
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Restriktionen",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DailyRestriction"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "post": {
                "tags": [
                    "Daily Pricing"
                ],
                "summary": "Restriktionen bulk-upserten",
                "description": "Fehlt in einem Item ein Boolean-Feld (z.B. `closed_for_arrival`), wird\nes auf `false` gesetzt. Fehlt `min_stay`/`max_stay`, wird es auf `null`\ngesetzt (keine Restriktion).\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/DailyRestrictionBulkInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Anzahl geschriebener Items",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "written": {
                                            "type": "integer"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/services": {
            "get": {
                "tags": [
                    "Services"
                ],
                "summary": "Services einer Property listen",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "Filtert auf eine Property. Ohne Filter alle Services des aktiven Tenants."
                    },
                    {
                        "name": "include_archived",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Service-Liste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Service"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Services"
                ],
                "summary": "Neuen Service anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ServiceInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Service angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Service"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/services/{service}": {
            "parameters": [
                {
                    "name": "service",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Services"
                ],
                "summary": "Service abrufen",
                "responses": {
                    "200": {
                        "description": "Service",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Service"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Services"
                ],
                "summary": "Service aktualisieren",
                "description": "`code` und `property_id` sind nach Anlegen immutable und werden bei\neinem PATCH ignoriert. Alles andere kann geändert werden.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ServiceUpdateInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Service aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Service"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Services"
                ],
                "summary": "Service hart löschen",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    }
                }
            }
        },
        "/api/services/{service}/archive": {
            "parameters": [
                {
                    "name": "service",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Services"
                ],
                "summary": "Service archivieren",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/services/{service}/unarchive": {
            "parameters": [
                {
                    "name": "service",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Services"
                ],
                "summary": "Service wiederherstellen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/services/{service}/tax-configs": {
            "parameters": [
                {
                    "name": "service",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Service Tax Configurations"
                ],
                "summary": "Alle MwSt-Konfigurationen eines Services (absteigend nach valid_from)",
                "responses": {
                    "200": {
                        "description": "Konfigurationen mit geladenen Komponenten",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/ServiceTaxConfiguration"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Service Tax Configurations"
                ],
                "summary": "Neue MwSt-Konfiguration mit Komponenten anlegen",
                "description": "Validierung (alle atomar geprüft):\n - `valid_from` ist pro Service eindeutig (422 wenn bereits belegt).\n - Alle Komponenten haben denselben `allocation_type`\n   (entweder alle `fixed_amount` oder alle `percent`, nicht gemischt).\n - Bei `fixed_amount`: Summe aller `allocation_value` muss dem\n   `services.price_amount` entsprechen (Toleranz 1 Cent).\n - Bei `percent`: Summe aller `allocation_value` muss 100 ergeben.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ServiceTaxConfigurationInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Konfiguration angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ServiceTaxConfiguration"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/services/{service}/tax-configs/{config}": {
            "parameters": [
                {
                    "name": "service",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                },
                {
                    "name": "config",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Service Tax Configurations"
                ],
                "summary": "Eine Konfiguration abrufen",
                "responses": {
                    "200": {
                        "description": "Konfiguration mit Komponenten",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ServiceTaxConfiguration"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "put": {
                "tags": [
                    "Service Tax Configurations"
                ],
                "summary": "Konfiguration komplett ersetzen (inkl. Komponenten)",
                "description": "Ersetzt sowohl `valid_from` als auch die Komponenten vollständig.\nGleiche Validierungs-Regeln wie beim POST.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ServiceTaxConfigurationInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Konfiguration aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ServiceTaxConfiguration"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Service Tax Configurations"
                ],
                "summary": "Konfiguration löschen (inkl. Komponenten via Cascade)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    }
                }
            }
        },
        "/api/age-groups": {
            "get": {
                "tags": [
                    "Age Groups"
                ],
                "summary": "Altersgruppen einer Property listen",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "include_archived",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Altersgruppen",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/AgeGroup"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Age Groups"
                ],
                "summary": "Neue Altersgruppe anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AgeGroupInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Altersgruppe angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AgeGroup"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/age-groups/{group}": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Age Groups"
                ],
                "summary": "Altersgruppe abrufen",
                "responses": {
                    "200": {
                        "description": "Altersgruppe",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AgeGroup"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Age Groups"
                ],
                "summary": "Altersgruppe aktualisieren",
                "description": "`code` und `property_id` sind immutable. `max_age` muss ≥ `min_age` sein\n(422 falls nicht).\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AgeGroupUpdateInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Altersgruppe aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AgeGroup"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Age Groups"
                ],
                "summary": "Altersgruppe hart löschen (setzt Services.served_for_age_group_id auf NULL)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    }
                }
            }
        },
        "/api/age-groups/{group}/archive": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Age Groups"
                ],
                "summary": "Altersgruppe archivieren",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/age-groups/{group}/unarchive": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Age Groups"
                ],
                "summary": "Altersgruppe wiederherstellen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/guests": {
            "get": {
                "tags": [
                    "Guests"
                ],
                "summary": "Gäste listen mit optionaler Suche",
                "parameters": [
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Such-Pattern (ILIKE über last_name, first_name, email)."
                    },
                    {
                        "name": "include_archived",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": false
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "default": 50,
                            "minimum": 10,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Gäste-Liste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Guest"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Guests"
                ],
                "summary": "Neuen Gast anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/GuestInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Gast angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Guest"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/guests/{guest}": {
            "parameters": [
                {
                    "name": "guest",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Guests"
                ],
                "summary": "Gast abrufen",
                "responses": {
                    "200": {
                        "description": "Gast",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Guest"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Guests"
                ],
                "summary": "Gast aktualisieren",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/GuestInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Gast aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Guest"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Guests"
                ],
                "summary": "Gast hart löschen (nur wenn keine Reservation verknüpft ist)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    }
                }
            }
        },
        "/api/guests/{guest}/archive": {
            "parameters": [
                {
                    "name": "guest",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Guests"
                ],
                "summary": "Gast archivieren",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/guests/{guest}/unarchive": {
            "parameters": [
                {
                    "name": "guest",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Guests"
                ],
                "summary": "Gast wiederherstellen",
                "responses": {
                    "204": {
                        "description": "Wiederhergestellt"
                    }
                }
            }
        },
        "/api/reservations": {
            "get": {
                "tags": [
                    "Reservations"
                ],
                "summary": "Reservierungen listen mit Filtern",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inquiry",
                                "option",
                                "booked",
                                "checked_in",
                                "checked_out",
                                "cancelled",
                                "no_show"
                            ]
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        },
                        "description": "Untere Grenze — nur Reservierungen mit departure ≥ from."
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        },
                        "description": "Obere Grenze — nur Reservierungen mit arrival ≤ to."
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Volltext-Suche (ILIKE). Durchsucht: `booking_number`,\n`external_reference`, sowie im primary_guest\n`last_name`, `first_name`, `email`, `company_name`, `phone`.\nZusätzlich Treffer im `group.name` — wenn jemand\n„Hochzeit Müller\" tippt, werden alle Mitgliedsreservationen\nder Gruppe gefunden.\n"
                    },
                    {
                        "name": "unassigned",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Nur Reservations ohne zugewiesenes Zimmer (Rezeptions-Filter)."
                    },
                    {
                        "name": "ungrouped",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Nur Einzelreservationen (ohne Gruppen-Zugehörigkeit). Default-Filter in der Einzel-Liste."
                    },
                    {
                        "name": "group_id",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "Nur Reservations einer bestimmten Gruppe."
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "default": 100,
                            "minimum": 10,
                            "maximum": 500
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Reservierungen",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Reservation"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Reservations"
                ],
                "summary": "Reservierung anlegen",
                "description": "`booking_number` wird automatisch generiert\n(`<property.code>-<YY>-<NNNN>`). `booked_at` wird auf `now()`\ngesetzt, wenn nicht mitgegeben.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ReservationInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Reservierung angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/reservations/{reservation}": {
            "parameters": [
                {
                    "name": "reservation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Reservations"
                ],
                "summary": "Reservierung abrufen (inkl. primary_guest und additional_guests)",
                "responses": {
                    "200": {
                        "description": "Reservierung",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Reservations"
                ],
                "summary": "Reservierung aktualisieren",
                "description": "`booking_number` und `property_id` sind immutable. Status-Übergänge\nsind in 3.2 noch frei — Workflow-Validierung kommt in Paket 3.4.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ReservationUpdateInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Reservierung aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Reservations"
                ],
                "summary": "Reservierung soft-löschen",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    }
                }
            }
        },
        "/api/reservations/{reservation}/check-in": {
            "parameters": [
                {
                    "name": "reservation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservations"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Gast einchecken (status → checked_in)",
                "description": "Erfordert ein konkretes Zimmer (`assigned_unit_id`). Nur aus\nStatus `booked` möglich.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "assigned_unit_id"
                                ],
                                "properties": {
                                    "assigned_unit_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Eingecheckt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Übergang nicht erlaubt oder Unit existiert nicht"
                    }
                }
            }
        },
        "/api/reservations/{reservation}/check-out": {
            "parameters": [
                {
                    "name": "reservation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservations"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Gast auschecken (status = checked_out)",
                "description": "Nur aus checked_in moeglich. Seit Paket 3.5 blockiert der\nEndpoint bei offenem Folio-Saldo (422). Mit force: true +\noptionalem force_reason kann die Rezeption trotzdem auschecken\n(z.B. bei Rechnungs-Versand an Firmenkunden). Der Vorgang wird\ndann mit Zeitstempel und Betrag in reservation.notes protokolliert.\n",
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "force": {
                                        "type": "boolean",
                                        "default": false
                                    },
                                    "force_reason": {
                                        "type": "string",
                                        "nullable": true,
                                        "maxLength": 500
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Ausgecheckt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        },
                                        "open_balance": {
                                            "type": "number",
                                            "format": "float"
                                        },
                                        "paid_total": {
                                            "type": "number",
                                            "format": "float"
                                        },
                                        "has_open_balance": {
                                            "type": "boolean"
                                        },
                                        "was_forced": {
                                            "type": "boolean"
                                        },
                                        "warning": {
                                            "type": "string",
                                            "nullable": true
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Offener Saldo — Check-Out blockiert (ohne force)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "error": {
                                            "type": "string",
                                            "example": "open_balance"
                                        },
                                        "message": {
                                            "type": "string"
                                        },
                                        "open_balance": {
                                            "type": "number",
                                            "format": "float"
                                        },
                                        "paid_total": {
                                            "type": "number",
                                            "format": "float"
                                        },
                                        "total_gross": {
                                            "type": "number",
                                            "format": "float"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservations/{reservation}/cancel": null,
        "parameters": [
            {
                "name": "reservation",
                "in": "path",
                "required": true,
                "schema": {
                    "type": "string",
                    "format": "uuid"
                }
            }
        ],
        "post": {
            "tags": [
                "Reservations"
            ],
            "security": [
                {
                    "bearerAuth": [
                        "tenant:write"
                    ]
                }
            ],
            "summary": "Reservation stornieren",
            "description": "Aktive Charges im Folio werden automatisch gevoidet\n(GoBD-konform, bleiben in der DB). Storno-Hinweis wird mit\nZeitstempel in die `notes` geschrieben.\n",
            "requestBody": {
                "required": false,
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "reason": {
                                    "type": "string",
                                    "nullable": true,
                                    "maxLength": 500
                                }
                            }
                        }
                    }
                }
            },
            "responses": {
                "200": {
                    "description": "Storniert",
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "data": {
                                        "$ref": "#/components/schemas/Reservation"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservations/{reservation}/no-show": {
            "parameters": [
                {
                    "name": "reservation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservations"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Als No-Show markieren",
                "description": "Charges bleiben aktiv (No-Show-Gebühren fallen oft über die\nStorno-Policy an). Nur aus `booked` möglich.\n",
                "responses": {
                    "200": {
                        "description": "No-Show markiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservations/{reservation}/confirm": {
            "parameters": [
                {
                    "name": "reservation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservations"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Anfrage bestätigen (inquiry → booked)",
                "description": "Legt das Gast-Folio inklusive Accommodation-Charges an, falls\ndie Reservation zunächst als `inquiry` erstellt wurde.\n",
                "responses": {
                    "200": {
                        "description": "Bestätigt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/dashboard/today": {
            "get": {
                "tags": [
                    "Dashboard"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Dashboard-Daten für heute (Übersicht Rezeption)",
                "description": "Rundumschlag für die Startseite: heutige An-/Abreisen, In-Haus-\nBelegung, offene Rechnungen, heute eingegangene Zahlungen und\ndie nächsten 10 ablaufenden Optionen.\n",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "today": {
                                            "type": "string",
                                            "format": "date"
                                        },
                                        "arrivals": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DashboardReservationRow"
                                            }
                                        },
                                        "departures": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DashboardReservationRow"
                                            }
                                        },
                                        "in_house": {
                                            "type": "object",
                                            "properties": {
                                                "count": {
                                                    "type": "integer"
                                                },
                                                "total_units": {
                                                    "type": "integer"
                                                },
                                                "percent": {
                                                    "type": "integer"
                                                }
                                            }
                                        },
                                        "open_invoices": {
                                            "type": "object",
                                            "properties": {
                                                "count": {
                                                    "type": "integer"
                                                },
                                                "total_open": {
                                                    "type": "number",
                                                    "format": "float"
                                                }
                                            }
                                        },
                                        "revenue_today": {
                                            "type": "object",
                                            "properties": {
                                                "payments": {
                                                    "type": "number",
                                                    "format": "float"
                                                },
                                                "count": {
                                                    "type": "integer"
                                                }
                                            }
                                        },
                                        "expiring_options": {
                                            "type": "array",
                                            "description": "Bis zu 10 aktive Optionen sortiert nach option_until\naufsteigend. Inkl. days_left als negativ (überfällig) /\n0 (heute) / positiv (Tage bis Ablauf).\n",
                                            "items": {
                                                "allOf": [
                                                    {
                                                        "$ref": "#/components/schemas/DashboardReservationRow"
                                                    },
                                                    {
                                                        "type": "object",
                                                        "properties": {
                                                            "option_until": {
                                                                "type": "string",
                                                                "format": "date",
                                                                "nullable": true
                                                            },
                                                            "days_left": {
                                                                "type": "integer",
                                                                "nullable": true
                                                            }
                                                        }
                                                    }
                                                ]
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/roomplan": {
            "get": {
                "tags": [
                    "Roomplan"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Zimmerplan-Daten (Units + Reservierungen im Zeitraum)",
                "description": "Liefert für eine Property den kompletten Zimmerplan für einen\nZeitraum: alle aktiven Units, Reservierungen mit\nassigned_unit_id im Zeitraum (Status ≠ cancelled/no_show), und\nunzugewiesene Buchungen. Der Frontend-Zimmerplan nutzt das, um\nBalken pro Zimmer-Zeile zu zeichnen — halbe Zellen am\nAnreise-/Abreisetag bei booking_display_mode = 'night'.\n",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "property_id": {
                                            "type": "string",
                                            "format": "uuid"
                                        },
                                        "from": {
                                            "type": "string",
                                            "format": "date"
                                        },
                                        "to": {
                                            "type": "string",
                                            "format": "date"
                                        },
                                        "booking_display_mode": {
                                            "type": "string",
                                            "enum": [
                                                "night",
                                                "day"
                                            ]
                                        },
                                        "units": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "string",
                                                        "format": "uuid"
                                                    },
                                                    "number": {
                                                        "type": "string"
                                                    },
                                                    "floor": {
                                                        "type": "string",
                                                        "nullable": true
                                                    },
                                                    "unit_group_id": {
                                                        "type": "string",
                                                        "format": "uuid"
                                                    },
                                                    "unit_group_name": {
                                                        "type": "string",
                                                        "nullable": true
                                                    },
                                                    "unit_group_code": {
                                                        "type": "string",
                                                        "nullable": true
                                                    }
                                                }
                                            }
                                        },
                                        "reservations": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/RoomplanReservation"
                                            }
                                        },
                                        "unassigned": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/RoomplanReservation"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservations/search-availability": {
            "post": {
                "tags": [
                    "Reservation Workflow"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Verfügbare Unit-Groups + Tarife für einen Zeitraum suchen",
                "description": "Liefert verfügbare Zimmerkategorien und passende Rate-Plans inkl.\nGesamtpreis für den gewünschten Zeitraum. Berücksichtigt\n`daily_availability` (Fallback auf `unit_count` der Kategorie),\nRestriktionen (stop_sell / CTA / CTD / min_stay / max_stay) und\nberechnet den Preis aus `daily_rates` (Parent-Rate) oder aus\nParent-Rate + Delta (abgeleiteter Tarif mit `price_delta_type`).\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "property_id",
                                    "arrival",
                                    "departure"
                                ],
                                "properties": {
                                    "property_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    },
                                    "arrival": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "departure": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "adults": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10,
                                        "default": 2
                                    },
                                    "children": {
                                        "type": "integer",
                                        "minimum": 0,
                                        "maximum": 10,
                                        "default": 0
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Verfügbarkeit + Preise",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "nights": {
                                            "type": "integer"
                                        },
                                        "unit_groups": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "string",
                                                        "format": "uuid"
                                                    },
                                                    "code": {
                                                        "type": "string"
                                                    },
                                                    "name": {
                                                        "type": "string"
                                                    },
                                                    "max_occupancy": {
                                                        "type": "integer"
                                                    },
                                                    "available_units": {
                                                        "type": "integer"
                                                    },
                                                    "min_price": {
                                                        "type": "number",
                                                        "format": "float"
                                                    },
                                                    "rate_plans": {
                                                        "type": "array",
                                                        "items": {
                                                            "type": "object",
                                                            "properties": {
                                                                "id": {
                                                                    "type": "string",
                                                                    "format": "uuid"
                                                                },
                                                                "code": {
                                                                    "type": "string"
                                                                },
                                                                "name": {
                                                                    "type": "string"
                                                                },
                                                                "board": {
                                                                    "type": "string",
                                                                    "enum": [
                                                                        "NB",
                                                                        "BB",
                                                                        "HB",
                                                                        "FB",
                                                                        "AI"
                                                                    ]
                                                                },
                                                                "price_per_night": {
                                                                    "type": "number",
                                                                    "format": "float"
                                                                },
                                                                "total_price": {
                                                                    "type": "number",
                                                                    "format": "float"
                                                                },
                                                                "is_derived": {
                                                                    "type": "boolean"
                                                                },
                                                                "price_horizon_date": {
                                                                    "type": "string",
                                                                    "format": "date",
                                                                    "nullable": true,
                                                                    "description": "Letztes gepflegtes Preisdatum (MAX(date) aus daily_rates).\nBei abgeleiteten Raten das Datum der Parent-Rate.\n"
                                                                },
                                                                "price_horizon_days": {
                                                                    "type": "integer",
                                                                    "nullable": true,
                                                                    "description": "Tage ab heute bis zum letzten gepflegten Preis.\nNegativ/0 wenn bereits ueberlaufen; null ohne Preise.\n"
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservations/{reservation}/available-units": {
            "parameters": [
                {
                    "name": "reservation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Reservation Workflow"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Verfügbare Zimmer für Reservierung auflisten",
                "description": "Liefert alle Zimmer in der gebuchten Kategorie, die im\nReservierungs-Zeitraum frei sind (kein Overlap mit anderen\naktiven Reservations). Das aktuell zugewiesene Zimmer\n(falls vorhanden) wird mit `is_current: true` markiert.\nPaket 3.9d-UI nutzt diesen Endpoint für die Schnell-\nZuweisung direkt aus der Reservations-Liste.\n",
                "responses": {
                    "200": {
                        "description": "Freie Zimmer",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "string",
                                                        "format": "uuid"
                                                    },
                                                    "number": {
                                                        "type": "string"
                                                    },
                                                    "name": {
                                                        "type": "string",
                                                        "nullable": true
                                                    },
                                                    "floor": {
                                                        "type": "integer",
                                                        "nullable": true
                                                    },
                                                    "is_current": {
                                                        "type": "boolean"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservations/{reservation}/assign-unit": {
            "parameters": [
                {
                    "name": "reservation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservation Workflow"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Zimmer zuweisen oder entziehen",
                "description": "Paket 3.9: Zuweisung als **eigenständiger** Workflow, losgelöst\nvom Check-In. Rezeption kann das Zimmer auch schon vor Anreise\noder nachträglich wechseln, ohne Status-Übergang auszulösen.\nBody `assigned_unit_id: null` entzieht das Zimmer wieder.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "assigned_unit_id": {
                                        "type": "string",
                                        "format": "uuid",
                                        "nullable": true
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reservation"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservation-groups": {
            "get": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Gruppenbuchungen auflisten",
                "description": "Suchbar über Name, Organisator und Buchungsnummern der\nMitgliedsreservationen.\n",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        },
                        "description": "Such-Term über Name, Organisator, Mitglieds-Buchungsnummer"
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "inquiry",
                                "confirmed",
                                "in_house",
                                "completed",
                                "cancelled"
                            ]
                        }
                    },
                    {
                        "name": "include_archived",
                        "in": "query",
                        "schema": {
                            "type": "boolean"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/ReservationGroup"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Neue Gruppenbuchung anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ReservationGroupInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ReservationGroup"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservation-groups/{group}": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Gruppe mit Mitglieds-Reservationen",
                "responses": {
                    "200": {
                        "description": "Gruppe",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ReservationGroup"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Gruppeninfos ändern (Name, Anlass, Veranstaltungsdatum, Organisator, Status, Notizen)",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ReservationGroupUpdateInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ReservationGroup"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Gruppe löschen (soft delete)",
                "responses": {
                    "204": {
                        "description": "Gelöscht"
                    }
                }
            }
        },
        "/api/reservation-groups/{group}/archive": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Archivieren (verschwindet aus der Standard-Liste)",
                "responses": {
                    "204": {
                        "description": "Archiviert"
                    }
                }
            }
        },
        "/api/reservation-groups/{group}/unarchive": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Aus dem Archiv zurückholen",
                "responses": {
                    "204": {
                        "description": "Reaktiviert"
                    }
                }
            }
        },
        "/api/reservation-groups/{group}/attach-reservation": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Existierende Einzelreservation an Gruppe hängen",
                "description": "Validiert, dass die Reservation zur selben Property gehört und\nnicht bereits einer anderen Gruppe angehört. Die Reservation\nselbst bleibt unverändert (Posten, Zahlungen, Status); nur\n`group_id` wird gesetzt.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "reservation_id"
                                ],
                                "properties": {
                                    "reservation_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Verknüpft",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ReservationGroup"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservation-groups/{group}/detach-reservation": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Reservation aus Gruppe entfernen (Reservation bleibt erhalten)",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "reservation_id"
                                ],
                                "properties": {
                                    "reservation_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Entfernt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/ReservationGroup"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservation-groups/{group}/bulk-reservations": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Mehrere identische Reservations in einem Call anlegen (Paket 4.2b)",
                "description": "Erzeugt N Reservations mit identischen Parametern (Zeitraum,\nZimmerkategorie, Tarif, Haupt-Gast, Belegung). Alle bekommen\naufsteigende Buchungsnummern und die `group_id` der Gruppe.\nJede Reservation bekommt ihr Einzel-Folio inkl. Accommodation-\nCharges. Typischer Fall: Firmenseminar mit 30 identisch\nkonfigurierten Zimmern.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/BulkReservationInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "count": {
                                                    "type": "integer"
                                                },
                                                "reservations": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Reservation"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/reservation-groups/{group}/folio": {
            "parameters": [
                {
                    "name": "group",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Reservation Groups"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Gruppen-Folio abrufen (lazy anlegen) (Paket 4.3)",
                "description": "Liefert das Gruppen-Folio dieser Gruppe. Wenn noch keines\nexistiert, wird es on-demand angelegt (idempotent — pro Gruppe\nexistiert genau **ein** Folio mit `group_id` gesetzt und\n`reservation_id` NULL). Antwortet inklusive Charges und\nPayments wie jedes andere Folio.\n",
                "responses": {
                    "200": {
                        "description": "Gruppen-Folio",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Folio"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/folios": {
            "get": {
                "tags": [
                    "Folios"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Folios auflisten",
                "parameters": [
                    {
                        "name": "reservation_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "open",
                                "closed"
                            ]
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 10,
                            "maximum": 500,
                            "default": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste von Folios",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Folio"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/folios/{folio}": {
            "parameters": [
                {
                    "name": "folio",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Folios"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Folio mit allen Posten abrufen",
                "responses": {
                    "200": {
                        "description": "Folio",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Folio"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Folios"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Folio-Stammdaten ändern (Label, Notes)",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "label": {
                                        "type": "string",
                                        "maxLength": 120
                                    },
                                    "notes": {
                                        "type": "string",
                                        "nullable": true,
                                        "maxLength": 4000
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert"
                    }
                }
            }
        },
        "/api/folios/{folio}/close": {
            "parameters": [
                {
                    "name": "folio",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Folios"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Folio schließen (keine Änderungen mehr möglich)",
                "responses": {
                    "200": {
                        "description": "Geschlossen"
                    }
                }
            }
        },
        "/api/folios/{folio}/reopen": {
            "parameters": [
                {
                    "name": "folio",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Folios"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Folio wieder öffnen",
                "responses": {
                    "200": {
                        "description": "Geöffnet"
                    }
                }
            }
        },
        "/api/folios/{folio}/charges": {
            "parameters": [
                {
                    "name": "folio",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Charges"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Posten hinzufügen (service, manual, discount)",
                "description": "Accommodation-Charges werden automatisch vom System erzeugt\nund können nicht über diesen Endpunkt angelegt werden.\nBei `type: discount` wird `unit_price_gross` automatisch\nnegativ gemacht.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ChargeInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Charge angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Charge"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/charges/{charge}": {
            "parameters": [
                {
                    "name": "charge",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "patch": {
                "tags": [
                    "Charges"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Charge ändern (Betrag, Beschreibung, Datum)",
                "description": "Nur bei offenem Folio möglich. Gevoidete Charges sind gesperrt.\n`amount_gross`, `amount_net` und `tax_amount` werden automatisch\naus quantity × unit_price_gross berechnet.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "description": {
                                        "type": "string",
                                        "maxLength": 255
                                    },
                                    "quantity": {
                                        "type": "number",
                                        "format": "float",
                                        "minimum": 0.01
                                    },
                                    "unit_price_gross": {
                                        "type": "number",
                                        "format": "float"
                                    },
                                    "tax_rate": {
                                        "type": "number",
                                        "format": "float",
                                        "minimum": 0,
                                        "maximum": 100
                                    },
                                    "service_date": {
                                        "type": "string",
                                        "format": "date"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert"
                    }
                }
            }
        },
        "/api/charges/{charge}/void": {
            "parameters": [
                {
                    "name": "charge",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Charges"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Charge stornieren (GoBD — Soft-Void, bleibt in der DB)",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "reason"
                                ],
                                "properties": {
                                    "reason": {
                                        "type": "string",
                                        "maxLength": 500
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Gevoided"
                    }
                }
            }
        },
        "/api/charges/{charge}/transfer": {
            "parameters": [
                {
                    "name": "charge",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Charges"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Charge zwischen Folios derselben Gruppe verschieben (Paket 4.3)",
                "description": "Bidirektional: Einzel-Folio → Gruppen-Folio (für Firmenrechnungen),\nGruppen-Folio → Einzel-Folio (Rück-Transfer), oder zwischen zwei\nEinzel-Folios derselben Gruppe (z. B. Frühstück-Irrläufer\nkorrigieren). Validierung:\n\n- Charge darf nicht gevoidet und nicht invoice-gelockt sein\n- Beide Folios müssen Status `open` haben\n- Beide Folios müssen derselben Gruppe angehören\n- Accommodation-Charges sind nicht transferierbar (bleiben an\n  der Reservation)\n\nDas Ziel-Folio bekommt einen History-Eintrag in `notes` mit\nZeitstempel und Ursprungs-Folio-ID.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "target_folio_id"
                                ],
                                "properties": {
                                    "target_folio_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Transferiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Charge"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/folios/{folio}/payments": {
            "parameters": [
                {
                    "name": "folio",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Payments"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Zahlungen eines Folios auflisten",
                "responses": {
                    "200": {
                        "description": "Liste von Payments",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Payment"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Payments"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Zahlung erfassen",
                "description": "Nur bei offenem Folio möglich. `amount` immer positiv\n(Zahlungseingang). `currency` default EUR. `received_at`\ndefault jetzt.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PaymentInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Zahlung erfasst",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Payment"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/payments/{payment}": {
            "parameters": [
                {
                    "name": "payment",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "patch": {
                "tags": [
                    "Payments"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Zahlung ändern",
                "description": "Nur bei offenem Folio und nicht-zurückerstatteter Zahlung möglich.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "method": {
                                        "type": "string",
                                        "enum": [
                                            "cash",
                                            "credit_card",
                                            "debit_card",
                                            "bank_transfer",
                                            "invoice",
                                            "voucher",
                                            "other"
                                        ]
                                    },
                                    "amount": {
                                        "type": "number",
                                        "format": "float",
                                        "minimum": 0.01
                                    },
                                    "reference": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "received_at": {
                                        "type": "string",
                                        "format": "date-time"
                                    },
                                    "notes": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisiert"
                    }
                }
            }
        },
        "/api/payments/{payment}/refund": {
            "parameters": [
                {
                    "name": "payment",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Payments"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Zahlung (teilweise) zurückerstatten (Paket 3.10 — Partial-Refund + Methode)",
                "description": "GoBD-konform: Payment bleibt in der DB. Refund wird über\n`refunded_at` + `refunded_amount` + `refund_method` dokumentiert.\n\n**Partial-Refund**: wenn `amount` kleiner als der volle verbleibende\nBetrag gesetzt wird, wird nur dieser Teil erstattet. Die wirksame\nSumme am Folio ist `amount - refunded_amount`. Mehrere Teil-Refunds\nkumulieren — `refunded_reason` sammelt die Historie chronologisch\n(jeweils \"+Betrag (Methode): Grund\").\n\n**Methoden-Wahl**: Der Default für `method` ist die Original-\nZahlungsmethode (Rückbuchung auf Karte/EC/Überweisung ist der\nNormalfall). Bar-Rückgabe bei Kartenzahlung wird explizit gesetzt.\n\nRefund wird abgelehnt wenn der Payment bereits voll erstattet ist.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "reason"
                                ],
                                "properties": {
                                    "reason": {
                                        "type": "string",
                                        "maxLength": 500
                                    },
                                    "amount": {
                                        "type": "number",
                                        "format": "float",
                                        "description": "Optionaler Erstattungsbetrag. Muss > 0 und ≤ dem noch\nnicht erstatteten Rest sein. Fehlt er, wird der komplette\nRest refundiert (Full-Refund).\n"
                                    },
                                    "method": {
                                        "type": "string",
                                        "enum": [
                                            "cash",
                                            "credit_card",
                                            "debit_card",
                                            "bank_transfer",
                                            "invoice",
                                            "voucher",
                                            "other"
                                        ],
                                        "description": "Optionale Erstattungs-Methode. Default = Methode der\nOriginal-Zahlung.\n"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Zurückerstattet",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Payment"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/invoices": {
            "get": {
                "tags": [
                    "Invoices"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Rechnungen auflisten",
                "parameters": [
                    {
                        "name": "folio_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "issued",
                                "cancelled",
                                "reversal"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste von Rechnungen",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Invoice"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/invoices/{invoice}": {
            "parameters": [
                {
                    "name": "invoice",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Invoices"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Rechnung mit allen Posten abrufen",
                "responses": {
                    "200": {
                        "description": "Rechnung"
                    }
                }
            }
        },
        "/api/folios/{folio}/invoices": {
            "parameters": [
                {
                    "name": "folio",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Invoices"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Rechnung aus Folio-Posten erstellen",
                "description": "Erzeugt aus einer Teilmenge offener Posten eines Folios eine\nneue Rechnung mit fortlaufender Nummer. Die gewählten Charges\nwerden auf invoice_id gesetzt und sind damit fiskalisch\neingefroren — sie können nicht mehr geändert werden, nur noch\nein Storno der gesamten Rechnung ist möglich.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/InvoiceInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Rechnung erstellt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Invoice"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Posten bereits abgerechnet, gehören nicht zum Folio, oder Folio geschlossen"
                    }
                }
            }
        },
        "/api/invoices/{invoice}/cancel": {
            "parameters": [
                {
                    "name": "invoice",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Invoices"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Rechnung stornieren (GoBD-konform via Storno-Rechnung)",
                "description": "Erstellt eine Storno-Rechnung mit eigener fortlaufender Nummer\nund negativen Summen. Die Original-Rechnung bekommt status=cancelled\nund einen Rückverweis. Die Charges bleiben fiskalisch bei der\nOriginal (sie gehören dort hin) — Nummer-Sequenz bleibt lückenlos.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "reason"
                                ],
                                "properties": {
                                    "reason": {
                                        "type": "string",
                                        "maxLength": 500
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Storno-Rechnung erstellt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Invoice"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Bereits storniert, oder Versuch eine Storno-Rechnung zu stornieren"
                    }
                }
            }
        },
        "/api/invoices/{invoice}/pdf": {
            "parameters": [
                {
                    "name": "invoice",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Invoices"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:read"
                        ]
                    }
                ],
                "summary": "Rechnung als PDF abrufen (inline)",
                "description": "Erzeugt das Rechnungs-PDF on-the-fly aus dem Snapshot (Rechnung +\nCharges + Property-Stammdaten). Wird als `application/pdf` mit\n`Content-Disposition: inline` ausgeliefert — Browser öffnet es\nim eingebauten PDF-Viewer.\n",
                "responses": {
                    "200": {
                        "description": "PDF-Datei",
                        "content": {
                            "application/pdf": {
                                "schema": {
                                    "type": "string",
                                    "format": "binary"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/invoices/{invoice}/send": {
            "parameters": [
                {
                    "name": "invoice",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Invoices"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "Rechnung per E-Mail verschicken (PDF als Anhang)",
                "description": "Versendet die Rechnung über den SMTP-Server der Property. Wenn\ndie Property keinen eigenen SMTP konfiguriert hat, antwortet\nder Endpoint mit 422 — Bookitly leitet keine Rechnungsmails\nüber eigene Server. Tracking am Invoice: `last_sent_at`,\n`last_sent_to`, `sent_count`.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "to",
                                    "subject"
                                ],
                                "properties": {
                                    "to": {
                                        "type": "string",
                                        "format": "email",
                                        "maxLength": 200
                                    },
                                    "subject": {
                                        "type": "string",
                                        "maxLength": 200
                                    },
                                    "message": {
                                        "type": "string",
                                        "nullable": true,
                                        "maxLength": 4000
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Versendet — Invoice mit aktualisierten Sent-Feldern",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Invoice"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "SMTP nicht konfiguriert"
                    }
                }
            }
        },
        "/api/properties/{property}/test-smtp": {
            "parameters": [
                {
                    "name": "property",
                    "in": "path",
                    "required": true,
                    "description": "Property-UUID oder Property-Code (case-insensitive).",
                    "schema": {
                        "type": "string"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Properties"
                ],
                "security": [
                    {
                        "bearerAuth": [
                            "tenant:write"
                        ]
                    }
                ],
                "summary": "SMTP-Verbindung testen (ohne Speichern)",
                "description": "Versucht eine Verbindung zum angegebenen SMTP-Server aufzubauen\nund wieder zu trennen. Wenn das Passwort leer ist, wird das\naktuell gespeicherte verwendet (Update-Flow mit unverändertem\nPasswort). Liefert strukturierte `{ok, message}` zurück.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "host",
                                    "port",
                                    "username",
                                    "from_email"
                                ],
                                "properties": {
                                    "host": {
                                        "type": "string",
                                        "maxLength": 200
                                    },
                                    "port": {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 65535
                                    },
                                    "username": {
                                        "type": "string",
                                        "maxLength": 200
                                    },
                                    "password": {
                                        "type": "string",
                                        "nullable": true,
                                        "maxLength": 500
                                    },
                                    "encryption": {
                                        "type": "string",
                                        "nullable": true,
                                        "enum": [
                                            "tls",
                                            "ssl"
                                        ]
                                    },
                                    "from_email": {
                                        "type": "string",
                                        "format": "email",
                                        "maxLength": 200
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Verbindung erfolgreich",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "ok": {
                                            "type": "boolean",
                                            "example": true
                                        },
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Verbindung fehlgeschlagen oder Passwort fehlt"
                    }
                }
            }
        },
        "/api/users": {
            "get": {
                "tags": [
                    "Users"
                ],
                "summary": "Benutzer + offene Einladungen im aktiven Tenant",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Membership"
                                            }
                                        },
                                        "invitations": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/PendingInvitation"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Users"
                ],
                "summary": "Benutzer einladen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "email",
                                    "name",
                                    "role_id"
                                ],
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "format": "email"
                                    },
                                    "name": {
                                        "type": "string",
                                        "maxLength": 120
                                    },
                                    "role_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Einladung angelegt, Mail gesendet",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "invitation_id": {
                                                    "type": "string",
                                                    "format": "uuid"
                                                },
                                                "email": {
                                                    "type": "string"
                                                },
                                                "name": {
                                                    "type": "string"
                                                },
                                                "role_id": {
                                                    "type": "string",
                                                    "format": "uuid"
                                                },
                                                "expires_at": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/users/{user}": {
            "parameters": [
                {
                    "name": "user",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer"
                    }
                }
            ],
            "patch": {
                "tags": [
                    "Users"
                ],
                "summary": "Rolle / Permissions / Status eines Benutzers aendern",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "role_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    },
                                    "permission_overrides": {
                                        "type": "object",
                                        "properties": {
                                            "granted": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            },
                                            "revoked": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    },
                                    "is_active": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "422": {
                        "description": "Safeguard greift (Selbst-Aenderung, letzter Inhaber, ...)"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Users"
                ],
                "summary": "Mitgliedschaft entfernen",
                "responses": {
                    "204": {
                        "description": "Entfernt"
                    }
                }
            }
        },
        "/api/invitations/{invitation}/resend": {
            "parameters": [
                {
                    "name": "invitation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Users"
                ],
                "summary": "Einladung erneut verschicken (neues Token + Mail)",
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/api/invitations/{invitation}": {
            "parameters": [
                {
                    "name": "invitation",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "delete": {
                "tags": [
                    "Users"
                ],
                "summary": "Einladung zurueckziehen",
                "responses": {
                    "204": {
                        "description": "Entfernt"
                    }
                }
            }
        },
        "/api/roles": {
            "get": {
                "tags": [
                    "Roles"
                ],
                "summary": "Rollen + user_count im aktiven Tenant",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Role"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Roles"
                ],
                "summary": "Neue Rolle anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/RoleInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Role"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/roles/meta/permissions": {
            "get": {
                "tags": [
                    "Roles"
                ],
                "summary": "Permission-Gruppen fuer UI-Matrix",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "additionalProperties": {
                                                "type": "object",
                                                "additionalProperties": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/roles/{role}": {
            "parameters": [
                {
                    "name": "role",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "patch": {
                "tags": [
                    "Roles"
                ],
                "summary": "Rolle aendern (Name/Beschreibung/Permissions)",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/RoleInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Role"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "System-Rolle oder noch verwendet"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Roles"
                ],
                "summary": "Rolle loeschen",
                "responses": {
                    "204": {
                        "description": "Geloescht"
                    },
                    "422": {
                        "description": "System-Rolle oder noch verwendet"
                    }
                }
            }
        },
        "/api/public/invitations/{token}": {
            "parameters": [
                {
                    "name": "token",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Invitations (Public)"
                ],
                "summary": "Einladung fuer Annahme-Seite laden",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "email": {
                                                    "type": "string"
                                                },
                                                "name": {
                                                    "type": "string"
                                                },
                                                "tenant": {
                                                    "type": "object",
                                                    "properties": {
                                                        "slug": {
                                                            "type": "string"
                                                        },
                                                        "name": {
                                                            "type": "string"
                                                        }
                                                    }
                                                },
                                                "role": {
                                                    "type": "object",
                                                    "properties": {
                                                        "slug": {
                                                            "type": "string"
                                                        },
                                                        "name": {
                                                            "type": "string"
                                                        }
                                                    }
                                                },
                                                "user_exists": {
                                                    "type": "boolean"
                                                },
                                                "expires_at": {
                                                    "type": "string",
                                                    "format": "date-time"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "410": {
                        "description": "Invalid/expired/already accepted"
                    }
                }
            }
        },
        "/api/public/invitations/{token}/accept": {
            "parameters": [
                {
                    "name": "token",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Invitations (Public)"
                ],
                "summary": "Einladung akzeptieren (Passwort optional bei bestehendem User)",
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "password": {
                                        "type": "string",
                                        "minLength": 8
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "email": {
                                                    "type": "string"
                                                },
                                                "name": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Annahme fehlgeschlagen (ungueltig/expired/...)"
                    }
                }
            }
        },
        "/api/finance/opos": {
            "get": {
                "tags": [
                    "Finance"
                ],
                "summary": "Offene-Posten-Liste (OPOS)",
                "description": "Alle unbezahlten Rechnungen, gruppiert in Faelligkeits-Buckets (not_due, 1_7, 8_30, 30_60, 60_plus).",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/OposBucket"
                                            }
                                        },
                                        "total_count": {
                                            "type": "integer"
                                        },
                                        "total_open": {
                                            "type": "number"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/finance/summary": {
            "get": {
                "tags": [
                    "Finance"
                ],
                "summary": "Finance-KPI-Summary",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/FinanceSummary"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/finance/dunning/eligible": {
            "get": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Rechnungen, die fuer die naechste Mahnstufe faellig sind",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DunningEligible"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/finance/dunning/history": {
            "get": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Globale Mahn-Historie (versendete Mahnungen)",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "invoice_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 500,
                            "default": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DunningHistoryRow"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/invoices/{invoice}/dunnings": {
            "parameters": [
                {
                    "name": "invoice",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Mahn-Historie einer Rechnung",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Dunning"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Naechste Mahnstufe verschicken",
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "recipient_email": {
                                        "type": "string",
                                        "format": "email"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Mahnung verschickt, Audit-Zeile angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Dunning"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Stufe nicht erreicht / bezahlt / keine weitere Stufe / keine E-Mail"
                    }
                }
            }
        },
        "/api/dunnings/{dunning}/pdf": {
            "parameters": [
                {
                    "name": "dunning",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Mahnungs-PDF (Stream)",
                "responses": {
                    "200": {
                        "description": "PDF",
                        "content": {
                            "application/pdf": []
                        }
                    }
                }
            }
        },
        "/api/properties/{property}/dunning-stages": {
            "parameters": [
                {
                    "name": "property",
                    "in": "path",
                    "required": true,
                    "description": "Property-UUID oder Property-Code (case-insensitive).",
                    "schema": {
                        "type": "string"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Stufen-Konfiguration der Property",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DunningStage"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "put": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Stufen-Konfiguration ersetzen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "stages"
                                ],
                                "properties": {
                                    "stages": {
                                        "type": "array",
                                        "maxItems": 10,
                                        "items": {
                                            "$ref": "#/components/schemas/DunningStageInput"
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DunningStage"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/properties/{property}/dunning-stages/seed-defaults": {
            "parameters": [
                {
                    "name": "property",
                    "in": "path",
                    "required": true,
                    "description": "Property-UUID oder Property-Code (case-insensitive).",
                    "schema": {
                        "type": "string"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Dunning"
                ],
                "summary": "Default-Stufen seeden (Zahlungserinnerung 7T / 1. Mahnung 14T+5EUR / 2. Mahnung 30T+10EUR)",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DunningStage"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/invoices/{invoice}/payments": {
            "parameters": [
                {
                    "name": "invoice",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Invoices"
                ],
                "summary": "Zahlungen, die dieser Rechnung zugeordnet sind",
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/PaymentForInvoice"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/cash-book": {
            "get": {
                "tags": [
                    "Cash Book"
                ],
                "summary": "Stammdaten des Kassenbuchs + Feature-Flag",
                "parameters": [
                    {
                        "name": "property_id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "feature_enabled": {
                                            "type": "boolean"
                                        },
                                        "cash_book": {
                                            "$ref": "#/components/schemas/CashBook"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Cash Book"
                ],
                "summary": "Kassenbuch einrichten (eines pro Property)",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "property_id",
                                    "opening_date",
                                    "opening_balance"
                                ],
                                "properties": {
                                    "property_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    },
                                    "name": {
                                        "type": "string",
                                        "maxLength": 80
                                    },
                                    "opening_date": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "opening_balance": {
                                        "type": "number",
                                        "minimum": 0
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CashBook"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Feature deaktiviert oder Kassenbuch existiert bereits"
                    }
                }
            }
        },
        "/api/cash-book/{cashBook}/day": {
            "parameters": [
                {
                    "name": "cashBook",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Cash Book"
                ],
                "summary": "Tagesuebersicht eines Kassenbuchs",
                "parameters": [
                    {
                        "name": "date",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CashBookDay"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/cash-book/{cashBook}/closings": {
            "parameters": [
                {
                    "name": "cashBook",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Cash Book"
                ],
                "summary": "Tagesabschluss-Liste",
                "parameters": [
                    {
                        "name": "from",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/CashBookClosing"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/cash-book/{cashBook}/entries": {
            "parameters": [
                {
                    "name": "cashBook",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Cash Book"
                ],
                "summary": "Eintrag erfassen (Einnahme oder Ausgabe)",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "type",
                                    "amount",
                                    "description",
                                    "booking_date"
                                ],
                                "properties": {
                                    "type": {
                                        "type": "string",
                                        "enum": [
                                            "income",
                                            "expense"
                                        ]
                                    },
                                    "amount": {
                                        "type": "number",
                                        "minimum": 0.01
                                    },
                                    "description": {
                                        "type": "string",
                                        "maxLength": 255
                                    },
                                    "reference": {
                                        "type": "string",
                                        "nullable": true,
                                        "maxLength": 80
                                    },
                                    "booking_date": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "booking_time": {
                                        "type": "string",
                                        "nullable": true,
                                        "pattern": "^[0-2][0-9]:[0-5][0-9]$"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Eintrag angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CashBookEntry"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Tag bereits abgeschlossen oder Feature deaktiviert"
                    }
                }
            }
        },
        "/api/cash-book/{cashBook}/entries/{entry}/void": {
            "parameters": [
                {
                    "name": "cashBook",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                },
                {
                    "name": "entry",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Cash Book"
                ],
                "summary": "Korrektur via Gegenbuchung (GoBD-konform)",
                "description": "Original wird voided + Gegenbuchung mit umgekehrtem Vorzeichen wird angelegt.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "reason"
                                ],
                                "properties": {
                                    "reason": {
                                        "type": "string",
                                        "maxLength": 255
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "voided": {
                                                    "$ref": "#/components/schemas/CashBookEntry"
                                                },
                                                "counter": {
                                                    "$ref": "#/components/schemas/CashBookEntry"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/cash-book/{cashBook}/close": {
            "parameters": [
                {
                    "name": "cashBook",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Cash Book"
                ],
                "summary": "Tagesabschluss erstellen — sperrt den Tag fuer weitere Eintraege",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "closing_date",
                                    "counted_balance"
                                ],
                                "properties": {
                                    "closing_date": {
                                        "type": "string",
                                        "format": "date"
                                    },
                                    "counted_balance": {
                                        "type": "number",
                                        "minimum": 0
                                    },
                                    "notes": {
                                        "type": "string",
                                        "nullable": true,
                                        "maxLength": 1000
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Abschluss erstellt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CashBookClosing"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Abschluss fuer diesen Tag existiert bereits"
                    }
                }
            }
        },
        "/api/quotes": {
            "get": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Angebote auflisten",
                "parameters": [
                    {
                        "in": "query",
                        "name": "property_id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "in": "query",
                        "name": "status",
                        "schema": {
                            "type": "string",
                            "description": "Komma-Liste: draft,sent,accepted,declined,expired,withdrawn"
                        }
                    },
                    {
                        "in": "query",
                        "name": "q",
                        "schema": {
                            "type": "string",
                            "description": "Suche in quote_number, recipient_name, recipient_email"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Angebote-Liste (paginiert)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Quote"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    }
                }
            },
            "post": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Neues Angebot anlegen (Status `draft`)",
                "description": "Pro Option entsteht eine Reservation mit Status `option` und\n`option_until = today + option_hold_days`. Quote erhält eine\nfortlaufende Nummer im Format `Q-YYYY-NNNN` pro Property und\neinen Token (Plaintext nur in der Antwort, in der DB nur Hash).\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QuoteInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Angebot angelegt — Antwort enthält einmalig `plain_token`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Quote"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/quotes/{id}": {
            "parameters": [
                {
                    "in": "path",
                    "name": "id",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Angebot-Detail",
                "responses": {
                    "200": {
                        "description": "Angebot mit Optionen + Reservationen",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Quote"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Draft bearbeiten",
                "description": "Nur Quotes im Status `draft` können editiert werden.",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QuoteUpdateInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Geändert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Quote"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Quote ist nicht mehr im Status draft"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Draft löschen",
                "description": "Löscht Draft + Pointer-Index + Option-Reservationen.",
                "responses": {
                    "204": {
                        "description": "gelöscht"
                    },
                    "422": {
                        "description": "Nicht-Draft Quotes müssen stattdessen zurückgezogen werden"
                    }
                }
            }
        },
        "/api/quotes/{id}/send": {
            "parameters": [
                {
                    "in": "path",
                    "name": "id",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Angebot per Mail an den Gast senden",
                "description": "Verschickt eine Mail über den Property-eigenen SMTP. Beim\nErst-Versand wird `status` auf `sent` gesetzt, `valid_until`\nab heute neu berechnet, Reservation-`option_until` ebenfalls.\nBei Re-Send wird ein neuer Token generiert (alter Pointer-Index\nwird durch neuen ersetzt). Antwort enthält einmalig `plain_token`.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QuoteSendInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Versendet",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Quote"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Status verbietet den Versand oder SMTP nicht konfiguriert"
                    }
                }
            }
        },
        "/api/quotes/{id}/withdraw": {
            "parameters": [
                {
                    "in": "path",
                    "name": "id",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Hotel zieht das Angebot zurück",
                "description": "Erlaubt für Status `draft` und `sent`. Alle Option-Reservationen\nwerden auf `cancelled` gesetzt, Quote auf `withdrawn`.\n",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "reason": {
                                        "type": "string",
                                        "maxLength": 500,
                                        "nullable": true
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Zurückgezogen",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Quote"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Status erlaubt kein Withdraw"
                    }
                }
            }
        },
        "/api/quote-templates": {
            "get": {
                "tags": [
                    "Quote Templates"
                ],
                "summary": "Vorlagen auflisten",
                "parameters": [
                    {
                        "in": "query",
                        "name": "property_id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "in": "query",
                        "name": "archived",
                        "schema": {
                            "type": "boolean",
                            "description": "Wenn true, werden nur archivierte Vorlagen geliefert; sonst nur aktive."
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/QuoteTemplate"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Quote Templates"
                ],
                "summary": "Neue Vorlage anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QuoteTemplateInput"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/QuoteTemplate"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    }
                }
            }
        },
        "/api/quote-templates/{id}": {
            "parameters": [
                {
                    "in": "path",
                    "name": "id",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Quote Templates"
                ],
                "summary": "Vorlage-Detail",
                "responses": {
                    "200": {
                        "description": "Detail",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/QuoteTemplate"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Quote Templates"
                ],
                "summary": "Vorlage bearbeiten",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/QuoteTemplateInput"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Geaendert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/QuoteTemplate"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Quote Templates"
                ],
                "summary": "Vorlage hart löschen",
                "responses": {
                    "204": {
                        "description": "gelöscht"
                    }
                }
            }
        },
        "/api/quote-templates/{id}/archive": {
            "parameters": [
                {
                    "in": "path",
                    "name": "id",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Quote Templates"
                ],
                "summary": "Vorlage archivieren (`archived_at` setzen)",
                "responses": {
                    "200": {
                        "description": "Archiviert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/QuoteTemplate"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/quote-templates/{id}/unarchive": {
            "parameters": [
                {
                    "in": "path",
                    "name": "id",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Quote Templates"
                ],
                "summary": "Vorlage reaktivieren (`archived_at` löschen)",
                "responses": {
                    "200": {
                        "description": "Reaktiviert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/QuoteTemplate"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/public/quotes/{token}": {
            "parameters": [
                {
                    "in": "path",
                    "name": "token",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "description": "32-Zeichen-Hex aus dem Mail-Link"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Public-Quote ansehen (Mini-Homepage)",
                "description": "Token-basierter Lookup über den globalen Pointer-Index in der\nControl-Plane. Setzt `viewed_at` beim ersten Aufruf. Antwort\nenthält Property-Branding-Felder für die Public-Page.\n**Kein Bearer-Token erforderlich.**\n",
                "security": [],
                "responses": {
                    "200": {
                        "description": "Quote + Property-Branding",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PublicQuoteResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Token nicht gefunden"
                    }
                }
            }
        },
        "/api/public/quotes/{token}/accept": {
            "parameters": [
                {
                    "in": "path",
                    "name": "token",
                    "required": true,
                    "schema": {
                        "type": "string"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Public — Option annehmen",
                "description": "Gewählte Option-Reservation wird auf `booked` gesetzt + Folio\nangelegt, andere Optionen werden storniert, Quote auf `accepted`.\nLiefert die `booking_number` der gebuchten Reservation zurück.\n**Kein Bearer-Token erforderlich** — Authentifizierung via Token.\n",
                "security": [],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "option_id"
                                ],
                                "properties": {
                                    "option_id": {
                                        "type": "string",
                                        "format": "uuid"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Annahme bestätigt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "status": {
                                            "type": "string",
                                            "enum": [
                                                "accepted"
                                            ]
                                        },
                                        "booking_number": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Quote nicht im Status sent oder bereits abgelaufen"
                    }
                }
            }
        },
        "/api/public/quotes/{token}/decline": {
            "parameters": [
                {
                    "in": "path",
                    "name": "token",
                    "required": true,
                    "schema": {
                        "type": "string"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Quotes"
                ],
                "summary": "Public — Angebot ablehnen",
                "description": "Alle Option-Reservationen werden storniert, Quote auf `declined`.\nOptionaler Grund wird gespeichert.\n**Kein Bearer-Token erforderlich.**\n",
                "security": [],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "reason": {
                                        "type": "string",
                                        "maxLength": 500,
                                        "nullable": true
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Ablehnung bestätigt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "status": {
                                            "type": "string",
                                            "enum": [
                                                "declined"
                                            ]
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Quote nicht im Status sent"
                    }
                }
            }
        },
        "/api/apps": {
            "get": {
                "tags": [
                    "Apps"
                ],
                "summary": "Apps des aktiven Hotels auflisten",
                "responses": {
                    "200": {
                        "description": "Liste der Apps mit Subscription-Counts und Telemetrie.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/App"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Apps"
                ],
                "summary": "Neue App anlegen",
                "description": "Legt einen OAuth-Client an, verlinkt ihn mit dem aktiven Tenant.\nDer **Plain-Secret** wird in der Antwort einmalig zurueckgegeben.\n",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "minLength": 2,
                                        "maxLength": 200
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Neue App + einmaliger Plain-Secret",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/App"
                                        },
                                        "credentials": {
                                            "type": "object",
                                            "properties": {
                                                "client_id": {
                                                    "type": "string",
                                                    "format": "uuid"
                                                },
                                                "client_secret": {
                                                    "type": "string",
                                                    "description": "Plain-Text — nur einmal in der Antwort."
                                                }
                                            }
                                        },
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/apps/{app}": {
            "parameters": [
                {
                    "name": "app",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Apps"
                ],
                "summary": "App-Details mit Subscription-Liste",
                "responses": {
                    "200": {
                        "description": "App-Details",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AppDetail"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Nicht gefunden"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Apps"
                ],
                "summary": "App aktualisieren",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "minLength": 2,
                                        "maxLength": 200
                                    },
                                    "revoked": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "App-Details",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/AppDetail"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Apps"
                ],
                "summary": "App entfernen",
                "description": "Subscriptions werden geloescht, Pivot zum Tenant entfernt, OAuth-Client wird `revoked=true` markiert.",
                "responses": {
                    "200": {
                        "description": "App entfernt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/apps/{app}/rotate-secret": {
            "parameters": [
                {
                    "name": "app",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Apps"
                ],
                "summary": "Client-Secret rotieren",
                "description": "Erzeugt einen neuen Plain-Secret. Der alte Wert ist ab sofort ungueltig.",
                "responses": {
                    "200": {
                        "description": "Neuer Plain-Secret",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "id": {
                                                    "type": "string",
                                                    "format": "uuid"
                                                },
                                                "name": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "credentials": {
                                            "type": "object",
                                            "properties": {
                                                "client_id": {
                                                    "type": "string",
                                                    "format": "uuid"
                                                },
                                                "client_secret": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/apps/{app}/subscriptions": {
            "parameters": [
                {
                    "name": "app",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Subscriptions dieser App auflisten",
                "responses": {
                    "200": {
                        "description": "Liste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/WebhookSubscription"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Neue Subscription unter App anlegen",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "name",
                                    "url",
                                    "events"
                                ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 200
                                    },
                                    "url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "In Production nur HTTPS."
                                    },
                                    "events": {
                                        "type": "array",
                                        "minItems": 1,
                                        "items": {
                                            "type": "string",
                                            "description": "z.B. reservation.created"
                                        }
                                    },
                                    "is_active": {
                                        "type": "boolean",
                                        "default": true
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Subscription + Plain-Secret einmalig",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/WebhookSubscription"
                                        },
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/apps/{app}/subscriptions/{subscription}": {
            "parameters": [
                {
                    "name": "app",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                },
                {
                    "name": "subscription",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Subscription-Details",
                "responses": {
                    "200": {
                        "description": "Subscription",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/WebhookSubscription"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Subscription aktualisieren",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string"
                                    },
                                    "url": {
                                        "type": "string",
                                        "format": "uri"
                                    },
                                    "events": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    },
                                    "is_active": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Subscription",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/WebhookSubscription"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Subscription loeschen (cascade auf Deliveries)",
                "responses": {
                    "200": {
                        "description": "Geloescht",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/apps/{app}/subscriptions/{subscription}/rotate-secret": {
            "parameters": [
                {
                    "name": "app",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                },
                {
                    "name": "subscription",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Webhook-Secret rotieren",
                "description": "Erzeugt einen neuen HMAC-Secret. Der alte Wert ist ab sofort ungueltig.",
                "responses": {
                    "200": {
                        "description": "Neuer Secret",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/WebhookSubscription"
                                        },
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/webhooks/deliveries": {
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Delivery-Log (Read-Only)",
                "parameters": [
                    {
                        "name": "subscription_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "pending",
                                "delivered",
                                "failed",
                                "exhausted"
                            ]
                        }
                    },
                    {
                        "name": "event_type",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Liste der letzten 200 Deliveries",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/WebhookDelivery"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/webhooks/deliveries/{delivery}": {
            "parameters": [
                {
                    "name": "delivery",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Delivery-Detail mit Payload",
                "responses": {
                    "200": {
                        "description": "Delivery",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/WebhookDelivery"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/webhooks/deliveries/{delivery}/replay": {
            "parameters": [
                {
                    "name": "delivery",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Delivery erneut versuchen",
                "description": "Erzwingt einen weiteren Versuch fuer eine Delivery — auch fuer\n`exhausted`-Eintraege. Status wird zurueck auf `pending` gesetzt,\nder Job wird neu in die Queue gestellt.\n",
                "responses": {
                    "200": {
                        "description": "Delivery neu eingereiht",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/WebhookDelivery"
                                        },
                                        "message": {
                                            "type": "string"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Subscription inaktiv"
                    }
                }
            }
        },
        "/api/webhooks/events-catalog": {
            "get": {
                "tags": [
                    "Webhooks"
                ],
                "summary": "Liste verfuegbarer Event-Typen, gruppiert",
                "responses": {
                    "200": {
                        "description": "Event-Katalog",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "additionalProperties": {
                                                "type": "object",
                                                "additionalProperties": {
                                                    "type": "string"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "Access-Token aus der Login-Response. 24 Stunden gültig.\nIm Authorization-Header als `Bearer <token>` mitsenden.\n"
            }
        },
        "responses": {
            "Unauthorized": {
                "description": "Kein Token, ungültiger Token oder Token abgelaufen.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorResponse"
                        },
                        "example": {
                            "error": "unauthenticated",
                            "message": "Authentifizierung erforderlich."
                        }
                    }
                }
            },
            "Forbidden": {
                "description": "Token ist gültig, der User darf auf diese Ressource aber nicht zugreifen.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorResponse"
                        },
                        "example": {
                            "error": "forbidden",
                            "message": "Für diese Aktion fehlen dir die Rechte."
                        }
                    }
                }
            },
            "NotFound": {
                "description": "Ressource existiert nicht (oder wurde gelöscht).",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ErrorResponse"
                        },
                        "example": {
                            "error": "not_found",
                            "message": "Die angefragte Ressource wurde nicht gefunden."
                        }
                    }
                }
            },
            "ValidationFailed": {
                "description": "Validierungsfehler — der Request-Body entspricht nicht dem Schema oder verletzt fachliche Regeln (z. B. doppeltes Kürzel).",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationError"
                        },
                        "example": {
                            "message": "The given data was invalid.",
                            "errors": {
                                "code": [
                                    "Das Kürzel ist in diesem Account bereits vergeben."
                                ],
                                "name": [
                                    "Der Name darf nicht länger als 255 Zeichen sein."
                                ]
                            }
                        }
                    }
                }
            }
        },
        "schemas": {
            "HealthResponse": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string",
                        "example": "ok"
                    },
                    "time": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "service": {
                        "type": "string",
                        "example": "bookitly-hold"
                    }
                }
            },
            "LoginRequest": {
                "type": "object",
                "required": [
                    "email",
                    "password"
                ],
                "properties": {
                    "email": {
                        "type": "string",
                        "format": "email",
                        "example": "operator@example-hotel.de"
                    },
                    "password": {
                        "type": "string",
                        "format": "password",
                        "minLength": 6,
                        "description": "Dein Passwort — wird über HTTPS im Request-Body übertragen, nicht im Token persistiert."
                    }
                }
            },
            "LoginResponse": {
                "type": "object",
                "properties": {
                    "access_token": {
                        "type": "string",
                        "description": "Access-Token für den Authorization-Header (Bearer-Schema). Gültig 24 Stunden."
                    },
                    "token_type": {
                        "type": "string",
                        "enum": [
                            "Bearer"
                        ]
                    },
                    "expires_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "Ablaufzeitpunkt des Tokens als ISO-8601"
                    },
                    "user": {
                        "$ref": "#/components/schemas/User"
                    },
                    "active_tenant": {
                        "$ref": "#/components/schemas/TenantRef"
                    },
                    "api_base_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Base-URL für Business-Endpunkte (`/api/properties`, `/api/unit-groups`, …). Kann account-abhängig abweichen.",
                        "example": "https://api.hold.bookitly.de"
                    },
                    "shard_id": {
                        "type": "string",
                        "description": "Interne Referenz auf das API-Routing-Segment. Für Integratoren nicht relevant — die verbindliche Base-URL ist `api_base_url`."
                    },
                    "available_tenants": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TenantMembership"
                        }
                    }
                }
            },
            "SessionContext": {
                "type": "object",
                "properties": {
                    "user": {
                        "$ref": "#/components/schemas/User"
                    },
                    "active_tenant": {
                        "$ref": "#/components/schemas/TenantRef"
                    },
                    "api_base_url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "shard_id": {
                        "type": "string"
                    },
                    "available_tenants": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TenantMembership"
                        }
                    }
                }
            },
            "User": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "example": 1
                    },
                    "name": {
                        "type": "string",
                        "example": "Marco Pardun"
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    },
                    "email_verified_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "TenantRef": {
                "type": "object",
                "description": "Referenz auf einen Hotel-Account (Tenant)",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "slug": {
                        "type": "string",
                        "example": "hotel-musterhof"
                    },
                    "name": {
                        "type": "string",
                        "example": "Hotel Musterhof"
                    }
                }
            },
            "TenantMembership": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/TenantRef"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "role": {
                                "type": "string",
                                "example": "owner"
                            },
                            "is_default": {
                                "type": "boolean"
                            }
                        }
                    }
                ]
            },
            "Property": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 16,
                        "example": "HOT",
                        "description": "Kurzcode für das Hotel, unique pro Account. Nach dem Anlegen nicht mehr änderbar — externe Systeme referenzieren darüber."
                    },
                    "name": {
                        "type": "string",
                        "example": "Hotel Musterhof"
                    },
                    "short_description": {
                        "type": "string",
                        "nullable": true
                    },
                    "primary_language": {
                        "type": "string",
                        "enum": [
                            "de",
                            "en",
                            "fr",
                            "es",
                            "it",
                            "nl"
                        ],
                        "default": "de",
                        "description": "Hotelsprache. Übersetzbare Entities (Services, Altersgruppen …) werden\nin dieser Sprache plus Englisch als Sekundärsprache gepflegt. Wenn die\nHotelsprache bereits `en` ist, reicht eine Sprachversion.\n"
                    },
                    "address": {
                        "$ref": "#/components/schemas/Address"
                    },
                    "contact": {
                        "$ref": "#/components/schemas/Contact"
                    },
                    "star_rating": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 1,
                        "maximum": 5,
                        "description": "Sterne-Klassifizierung (1–5), null = keine Angabe"
                    },
                    "tax_number": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 40,
                        "example": "115/5123/00025",
                        "description": "Steuernummer, vom zuständigen Finanzamt vergeben"
                    },
                    "vat_id": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 40,
                        "example": "DE123456789",
                        "description": "Umsatzsteuer-Identifikationsnummer (EU-weit)"
                    },
                    "booking_display_mode": {
                        "type": "string",
                        "enum": [
                            "night",
                            "day"
                        ],
                        "default": "night",
                        "description": "Darstellung von Buchungen im Zimmerplan:\n- 'night' (Standard): Anreise- und Abreisetag werden als halbe\n  Zellen gezeichnet; zwei Buchungen am Wechseltag im gleichen\n  Zimmer sind sichtbar.\n- 'day': Anreise- und Abreisetag sind volle Zellen\n  (Ferienwohnungen, Tages-basierte Buchungen).\nBeeinflusst nur die Anzeige, nicht die Preisberechnung.\n"
                    },
                    "hero_image_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500,
                        "description": "Großes Bild oben auf der Public-Angebots-Seite"
                    },
                    "description_text": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000,
                        "description": "Begrüßungs-Text unter dem Hero"
                    },
                    "logo_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "brand_accent_color": {
                        "type": "string",
                        "default": "#94A597",
                        "description": "Hex-Farbe (#RRGGBB) für Buttons und Highlights auf der Mini-Homepage"
                    },
                    "footer_terms_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "footer_privacy_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "footer_revocation_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "footer_imprint_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "PropertyInput": {
                "type": "object",
                "required": [
                    "code",
                    "name"
                ],
                "description": "Eingabe-Schema für Anlegen und Update von Properties. Beim Update wird\n`code` nicht verändert (administrative Festlegung).\n",
                "properties": {
                    "code": {
                        "type": "string",
                        "maxLength": 16
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "short_description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "address": {
                        "$ref": "#/components/schemas/Address"
                    },
                    "contact": {
                        "$ref": "#/components/schemas/Contact"
                    },
                    "star_rating": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 1,
                        "maximum": 5
                    },
                    "tax_number": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 40
                    },
                    "vat_id": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 40
                    },
                    "booking_display_mode": {
                        "type": "string",
                        "enum": [
                            "night",
                            "day"
                        ]
                    },
                    "hero_image_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "description_text": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "logo_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "brand_accent_color": {
                        "type": "string",
                        "nullable": true,
                        "description": "Hex-Farbe wie #94A597"
                    },
                    "footer_terms_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "footer_privacy_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "footer_revocation_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    },
                    "footer_imprint_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 500
                    }
                }
            },
            "Address": {
                "type": "object",
                "nullable": true,
                "description": "Postadresse des Hotels",
                "properties": {
                    "company": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255,
                        "description": "Empfänger-Zeile auf der Briefpost (erste Zeile, oft gleich dem Hotelnamen)",
                        "example": "Hotel Musterhof"
                    },
                    "street": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255,
                        "example": "Musterstraße 1"
                    },
                    "postal_code": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 20,
                        "example": "10115"
                    },
                    "city": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 100,
                        "example": "Berlin"
                    },
                    "country": {
                        "type": "string",
                        "nullable": true,
                        "minLength": 2,
                        "maxLength": 2,
                        "description": "ISO-3166-1 alpha-2 Ländercode",
                        "example": "DE"
                    }
                }
            },
            "Contact": {
                "type": "object",
                "nullable": true,
                "description": "Kontaktdaten des Hotels. E-Mail Allgemein und Rezeption bewusst getrennt.",
                "properties": {
                    "phone": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 40,
                        "example": "+49 30 12345678"
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true,
                        "maxLength": 255,
                        "description": "Allgemeines Hauptpostfach — Rechnungen, allgemeine Anfragen",
                        "example": "info@example-hotel.de"
                    },
                    "reception_email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true,
                        "maxLength": 255,
                        "description": "E-Mail der Rezeption — Reservierungen, Gast-Anfragen, Check-In-Kommunikation",
                        "example": "rezeption@example-hotel.de"
                    },
                    "website": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "maxLength": 255,
                        "example": "https://example-hotel.de"
                    }
                }
            },
            "UnitGroup": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 16,
                        "example": "DZK",
                        "description": "Kurzcode, unique innerhalb der Property (z.B. DZK fuer Doppelzimmer Komfort)"
                    },
                    "name": {
                        "type": "string",
                        "example": "Doppelzimmer Komfort"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "default_occupancy": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20,
                        "example": 2,
                        "description": "Standard-Belegung in Anzahl Personen"
                    },
                    "max_occupancy": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20,
                        "example": 3
                    },
                    "min_occupancy": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20,
                        "example": 1
                    },
                    "attributes": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "string",
                            "maxLength": 40
                        },
                        "description": "Feature-Tags wie \"balkon\", \"meerblick\", \"non_smoking\", \"barrierefrei\"",
                        "example": [
                            "balkon",
                            "non_smoking"
                        ]
                    },
                    "size_sqm": {
                        "type": "number",
                        "format": "float",
                        "nullable": true,
                        "minimum": 1,
                        "maximum": 10000,
                        "example": 22.5,
                        "description": "Zimmergroesse in Quadratmetern"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999,
                        "example": 10,
                        "description": "Reihenfolge bei Anzeige in UI und Booking-Engine"
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "UnitGroupInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "code",
                    "name"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 16
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "default_occupancy": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20
                    },
                    "max_occupancy": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20
                    },
                    "min_occupancy": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20
                    },
                    "attributes": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "string",
                            "maxLength": 40
                        }
                    },
                    "size_sqm": {
                        "type": "number",
                        "format": "float",
                        "nullable": true
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    }
                }
            },
            "Unit": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "number": {
                        "type": "string",
                        "maxLength": 16,
                        "example": "12",
                        "description": "Zimmernummer, unique innerhalb der Property"
                    },
                    "label": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255,
                        "description": "Optionales zusaetzliches Label"
                    },
                    "floor": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": -5,
                        "maximum": 100,
                        "description": "Stockwerk (0 = EG, -1 = UG, 1..N = Obergeschosse)",
                        "example": 1
                    },
                    "attributes": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "string",
                            "maxLength": 40
                        },
                        "description": "Override der UnitGroup-Attributes fuer dieses einzelne Zimmer"
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "Ob das Zimmer aktuell buchbar ist",
                        "example": true
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "UnitInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "unit_group_id",
                    "number"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "number": {
                        "type": "string",
                        "maxLength": 16
                    },
                    "label": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    },
                    "floor": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": -5,
                        "maximum": 100
                    },
                    "attributes": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "string",
                            "maxLength": 40
                        }
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    }
                }
            },
            "RatePlan": {
                "type": "object",
                "description": "Tarifplan, gehört zu einer Zimmerkategorie (UnitGroup).\n\n**Hierarchie:** Rate-Plans können voneinander abgeleitet\nsein. Child-Rates erben den Preis von der Parent-Rate und modifizieren ihn\nüber `price_delta_type` + `price_delta_value`. Nach dem Anlegen sind\n`parent_rate_plan_id`, `price_delta_type` und `code` immutable;\n`price_delta_value` bleibt editierbar.\n\n**Vertrieb:** `cancellation_policy_id` bindet eine wiederverwendbare Storno-\nRichtlinie, `channels` steuert die Vertriebskanäle, `min_guarantee_amount`\nist eine Preis-Untergrenze, die auch durch Delta-Berechnung nicht unterschritten\nwird.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "parent_rate_plan_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Optional — macht diese Rate zu einer abgeleiteten Child-Rate."
                    },
                    "price_delta_type": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "fixed_amount",
                            "percent"
                        ],
                        "description": "Nur bei Child-Rates gesetzt. Bestimmt wie `price_delta_value` interpretiert wird."
                    },
                    "price_delta_value": {
                        "type": "number",
                        "nullable": true,
                        "description": "Nur bei Child-Rates. Positiv = teurer, negativ = günstiger. Bei `fixed_amount`\nin EUR, bei `percent` als Prozentpunkte (z.B. -10 = 10% Rabatt).\n",
                        "example": -10
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 16,
                        "example": "FLEX"
                    },
                    "name": {
                        "type": "string",
                        "example": "Flexibel"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "board": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "NB",
                            "BB",
                            "HB",
                            "FB",
                            "AI"
                        ],
                        "description": "NB=NoMeals, BB=Breakfast, HB=Halbpension, FB=Vollpension, AI=AllInclusive"
                    },
                    "cancellation_policy_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Referenz auf eine Storno-Richtlinie. `null` = Standard-Kulanz."
                    },
                    "channels": {
                        "type": "array",
                        "description": "Vertriebskanäle, auf denen diese Rate verkauft wird.\n- `direct`: Telefon/Email/Walk-in, eigene Website (nicht IBE)\n- `ibe`: Internet Booking Engine (Bookitly Stay)\n- `cm`: Channel Manager (Booking.com, Expedia, …)\n",
                        "items": {
                            "type": "string",
                            "enum": [
                                "direct",
                                "ibe",
                                "cm"
                            ]
                        },
                        "example": [
                            "direct",
                            "ibe"
                        ]
                    },
                    "min_guarantee_amount": {
                        "type": "number",
                        "nullable": true,
                        "description": "Preis-Untergrenze in EUR. Wird von Delta-Berechnung abgeleiteter Child-Rates\nnicht unterschritten. `null` = keine Untergrenze.\n",
                        "example": 79
                    },
                    "is_public": {
                        "type": "boolean",
                        "description": "Oeffentliche Rate (im Booking-Engine sichtbar)"
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "Zeitpunkt der Archivierung. `null` = aktiv."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "RatePlanInput": {
                "type": "object",
                "required": [
                    "unit_group_id",
                    "code",
                    "name"
                ],
                "properties": {
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "parent_rate_plan_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Macht die Rate zur Child einer Parent-Rate. Nur beim Anlegen setzbar."
                    },
                    "price_delta_type": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "fixed_amount",
                            "percent"
                        ],
                        "description": "Pflicht wenn `parent_rate_plan_id` gesetzt ist."
                    },
                    "price_delta_value": {
                        "type": "number",
                        "nullable": true,
                        "description": "Pflicht wenn `parent_rate_plan_id` gesetzt ist. Positiv/Negativ erlaubt."
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 16
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "board": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "NB",
                            "BB",
                            "HB",
                            "FB",
                            "AI"
                        ]
                    },
                    "cancellation_policy_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "channels": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "enum": [
                                "direct",
                                "ibe",
                                "cm"
                            ]
                        },
                        "description": "Default `[direct, ibe]` wenn nicht angegeben."
                    },
                    "min_guarantee_amount": {
                        "type": "number",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 99999.99
                    },
                    "is_public": {
                        "type": "boolean"
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    }
                }
            },
            "Amenity": {
                "type": "object",
                "description": "Ein Zimmermerkmal aus dem Katalog des aktiven Tenants. Merkmale sind\nkategorisiert (Sanitär/Komfort/Ausstattung/Barrierefreiheit/Aussicht/\nSonstiges) und können Zimmerkategorien oder einzelnen Zimmern zugeordnet\nwerden.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 32,
                        "example": "balcony",
                        "description": "Maschinenlesbarer Slug, unique pro Tenant, nach dem Anlegen nicht mehr änderbar"
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 160,
                        "example": "Balkon"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000,
                        "description": "Optionaler Hinweistext zur Bedeutung des Merkmals"
                    },
                    "category": {
                        "type": "string",
                        "enum": [
                            "bathroom",
                            "comfort",
                            "accessibility",
                            "equipment",
                            "view",
                            "other"
                        ],
                        "description": "Gruppierung für die UI-Darstellung:\n- `bathroom` — Sanitär (Dusche, Badewanne, Bidet)\n- `comfort` — Komfort (Balkon, Klimaanlage, Schreibtisch)\n- `equipment` — Ausstattung (WLAN, Flachbild-TV, Safe)\n- `accessibility` — Barrierefreiheit\n- `view` — Aussicht (Meerblick, Bergblick)\n- `other` — Sonstiges\n",
                        "example": "comfort"
                    },
                    "icon": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 64,
                        "description": "Optionaler Icon-Name (z.B. Lucide-Icon-Key wie \"armchair\", \"wifi\")"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999,
                        "description": "Reihenfolge bei Anzeige innerhalb einer Kategorie"
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "Ob das Merkmal in Pickern angeboten wird"
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "AmenityInput": {
                "type": "object",
                "required": [
                    "code",
                    "name"
                ],
                "properties": {
                    "code": {
                        "type": "string",
                        "maxLength": 32,
                        "pattern": "^[a-z0-9][a-z0-9_-]*$",
                        "description": "Slug — Kleinbuchstaben, Zahlen, Unterstrich, Bindestrich. Das Frontend erzeugt diesen Wert automatisch aus dem Namen."
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 160
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "category": {
                        "type": "string",
                        "enum": [
                            "bathroom",
                            "comfort",
                            "accessibility",
                            "equipment",
                            "view",
                            "other"
                        ]
                    },
                    "icon": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 64
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    },
                    "is_active": {
                        "type": "boolean"
                    }
                }
            },
            "AmenitySyncInput": {
                "type": "object",
                "required": [
                    "amenity_ids"
                ],
                "description": "Setzt die komplette Merkmal-Liste einer UnitGroup oder Unit (PUT-Semantik — nicht dabei = entfernt).",
                "properties": {
                    "amenity_ids": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "example": [
                            "019da213-2e5f-725a-a06e-533e64a9aff4",
                            "019da213-3f01-72b8-ae60-1c5382a1d1c2"
                        ]
                    }
                }
            },
            "CancellationPolicy": {
                "type": "object",
                "description": "Storno-Richtlinie — wiederverwendbares Regelwerk für Ratenpläne.\nMehrere Raten können dieselbe Policy nutzen\n(z.B. „Flexibel\" für alle Flex-Tarife, „Nicht stornierbar\" für Sparpreise).\n\n**Stornierungsfrist:** Entweder Vorlaufzeit in Monaten/Tagen\n(`free_until_months` + `free_until_days`), ODER Cut-off-Uhrzeit am\nReferenztag (`free_until_hours` als Uhrzeit 0-23). Die Kombination beider\nModi ist fachlich selten und wird in der UI ausgeschlossen. `free_until_reference`\nist `null` → nicht kostenfrei stornierbar.\n\n**Strafe:** Bei `penalty_type: first_night` wird automatisch der Tagespreis\nder ersten gebuchten Nacht einbehalten, `penalty_value` ist dann `null`.\nBei `percent` ist `penalty_value` ein Prozentwert 0-100, bei `fixed` ein\nEUR-Betrag.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 32,
                        "pattern": "^[A-Z0-9][A-Z0-9_-]*$",
                        "example": "ARR",
                        "description": "Großbuchstaben, Zahlen, Unterstrich, Bindestrich. Immutable nach Anlegen."
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 160,
                        "example": "Anreise bis 18 Uhr"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "free_until_reference": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "before_arrival",
                            "after_booking"
                        ],
                        "description": "Bezugspunkt für die Stornierungsfrist.\n- `before_arrival`: Frist bezieht sich auf die Anreise\n- `after_booking`: Frist bezieht sich auf den Buchungszeitpunkt\n- `null`: Nicht kostenfrei stornierbar (strict)\n"
                    },
                    "free_until_months": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 36,
                        "description": "Monate Vorlaufzeit vor/nach dem Referenzpunkt."
                    },
                    "free_until_days": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 365,
                        "description": "Tage Vorlaufzeit vor/nach dem Referenzpunkt."
                    },
                    "free_until_hours": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 23,
                        "description": "Cut-off-**Uhrzeit** (0-23, nicht Stunden-Delta). Beispiel:\n`hours=18, months=0, days=0, ref=before_arrival` = „Bis 18:00 Uhr\nam Anreisetag kostenfrei stornierbar\".\n"
                    },
                    "penalty_type": {
                        "type": "string",
                        "enum": [
                            "percent",
                            "fixed",
                            "first_night"
                        ],
                        "description": "- `percent`: `penalty_value` ist Prozent vom Buchungswert (0-100)\n- `fixed`: `penalty_value` ist EUR-Betrag\n- `first_night`: Tagespreis der ersten Nacht (`penalty_value` ist null)\n"
                    },
                    "penalty_value": {
                        "type": "number",
                        "nullable": true,
                        "minimum": 0,
                        "description": "Wert zum `penalty_type`. Bei `first_night` immer `null`."
                    },
                    "limit_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 1,
                        "maximum": 365,
                        "description": "Begrenzt die Stornogebühr auf X Nächte. `null` = gesamte Aufenthaltsdauer.\nRelevant bei `percent` und `fixed` für Buchungen > X Nächte.\n"
                    },
                    "tax_rate_key": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "standard",
                            "reduced",
                            "zero"
                        ],
                        "description": "MwSt.-Satz, mit dem die Stornogebühr abgerechnet wird.\n- `standard`: 19 % (DE Regelsatz)\n- `reduced`: 7 % (DE ermäßigt)\n- `zero`: 0 % (ohne MwSt.)\n"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "CancellationPolicyInput": {
                "type": "object",
                "required": [
                    "code",
                    "name",
                    "penalty_type"
                ],
                "properties": {
                    "code": {
                        "type": "string",
                        "maxLength": 32,
                        "pattern": "^[A-Z0-9][A-Z0-9_-]*$"
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 160
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "free_until_reference": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "before_arrival",
                            "after_booking"
                        ]
                    },
                    "free_until_months": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 36
                    },
                    "free_until_days": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 365
                    },
                    "free_until_hours": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 23
                    },
                    "penalty_type": {
                        "type": "string",
                        "enum": [
                            "percent",
                            "fixed",
                            "first_night"
                        ]
                    },
                    "penalty_value": {
                        "type": "number",
                        "nullable": true,
                        "minimum": 0
                    },
                    "limit_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 1,
                        "maximum": 365
                    },
                    "tax_rate_key": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "standard",
                            "reduced",
                            "zero"
                        ]
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 9999
                    }
                }
            },
            "DailyRate": {
                "type": "object",
                "description": "Tagespreis für einen RatePlan an einem Datum. Überschreibt die\nDefault-Berechnung (Parent-Preis + Delta). Nur dort gesetzt, wo explizit\nvon einem abweichenden Preis gearbeitet wird.\n",
                "properties": {
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "date": {
                        "type": "string",
                        "format": "date",
                        "example": "2026-06-15"
                    },
                    "price": {
                        "type": "number",
                        "minimum": 0,
                        "example": 129.5
                    }
                }
            },
            "DailyRateBulkInput": {
                "type": "object",
                "required": [
                    "items"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 5000,
                        "items": {
                            "type": "object",
                            "required": [
                                "rate_plan_id",
                                "date",
                                "price"
                            ],
                            "properties": {
                                "rate_plan_id": {
                                    "type": "string",
                                    "format": "uuid"
                                },
                                "date": {
                                    "type": "string",
                                    "format": "date"
                                },
                                "price": {
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 99999.99
                                }
                            }
                        }
                    }
                }
            },
            "DashboardReservationRow": {
                "type": "object",
                "description": "Schlanke Reservation-Zeile für Dashboard-Listen.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "booking_number": {
                        "type": "string"
                    },
                    "status": {
                        "type": "string"
                    },
                    "guest_name": {
                        "type": "string"
                    },
                    "unit_group_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "assigned_unit_number": {
                        "type": "string",
                        "nullable": true
                    },
                    "adults": {
                        "type": "integer"
                    },
                    "children": {
                        "type": "integer"
                    },
                    "nights": {
                        "type": "integer"
                    },
                    "arrival": {
                        "type": "string",
                        "format": "date"
                    },
                    "departure": {
                        "type": "string",
                        "format": "date"
                    }
                }
            },
            "RoomplanReservation": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "booking_number": {
                        "type": "string"
                    },
                    "external_reference": {
                        "type": "string",
                        "nullable": true
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "booked",
                            "checked_in",
                            "checked_out"
                        ]
                    },
                    "option_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Nur wenn status=option gesetzt."
                    },
                    "channel": {
                        "type": "string",
                        "nullable": true
                    },
                    "booked_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "assigned_unit_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "assigned_unit_number": {
                        "type": "string",
                        "nullable": true
                    },
                    "arrival": {
                        "type": "string",
                        "format": "date"
                    },
                    "departure": {
                        "type": "string",
                        "format": "date"
                    },
                    "nights": {
                        "type": "integer"
                    },
                    "adults": {
                        "type": "integer"
                    },
                    "children": {
                        "type": "integer"
                    },
                    "guest_name": {
                        "type": "string"
                    },
                    "guest_first_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "guest_last_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "guest_company_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "guest_email": {
                        "type": "string",
                        "nullable": true
                    },
                    "guest_phone": {
                        "type": "string",
                        "nullable": true
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "unit_group_code": {
                        "type": "string",
                        "nullable": true
                    },
                    "unit_group_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "rate_plan_code": {
                        "type": "string",
                        "nullable": true
                    },
                    "rate_plan_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "cancellation_policy_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "cancellation_policy_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "group_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "group_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "group_occasion": {
                        "type": "string",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "guest_requests": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "DailyAvailability": {
                "type": "object",
                "description": "Verfügbare Zimmer einer UnitGroup an einem Datum.",
                "properties": {
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "count": {
                        "type": "integer",
                        "minimum": 0,
                        "example": 12
                    }
                }
            },
            "DailyAvailabilityBulkInput": {
                "type": "object",
                "required": [
                    "items"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 5000,
                        "items": {
                            "type": "object",
                            "required": [
                                "unit_group_id",
                                "date",
                                "count"
                            ],
                            "properties": {
                                "unit_group_id": {
                                    "type": "string",
                                    "format": "uuid"
                                },
                                "date": {
                                    "type": "string",
                                    "format": "date"
                                },
                                "count": {
                                    "type": "integer",
                                    "minimum": 0,
                                    "maximum": 9999
                                }
                            }
                        }
                    }
                }
            },
            "DailyRestriction": {
                "type": "object",
                "description": "Restriktionen für einen RatePlan an einem Datum — für Yield-Management\nund OTA-Sync.\n",
                "properties": {
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "min_stay": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365,
                        "description": "Mindestnächte. `null` = keine Untergrenze."
                    },
                    "max_stay": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365,
                        "description": "Maximale Nächte. `null` = unbegrenzt."
                    },
                    "closed_for_arrival": {
                        "type": "boolean",
                        "description": "CTA — kein Check-In an diesem Tag möglich."
                    },
                    "closed_for_departure": {
                        "type": "boolean",
                        "description": "CTD — kein Check-Out an diesem Tag möglich."
                    },
                    "stop_sell": {
                        "type": "boolean",
                        "description": "Rate an diesem Tag komplett geschlossen."
                    }
                }
            },
            "DailyRestrictionBulkInput": {
                "type": "object",
                "required": [
                    "items"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 5000,
                        "items": {
                            "type": "object",
                            "required": [
                                "rate_plan_id",
                                "date"
                            ],
                            "properties": {
                                "rate_plan_id": {
                                    "type": "string",
                                    "format": "uuid"
                                },
                                "date": {
                                    "type": "string",
                                    "format": "date"
                                },
                                "min_stay": {
                                    "type": "integer",
                                    "nullable": true,
                                    "minimum": 0,
                                    "maximum": 365
                                },
                                "max_stay": {
                                    "type": "integer",
                                    "nullable": true,
                                    "minimum": 0,
                                    "maximum": 365
                                },
                                "closed_for_arrival": {
                                    "type": "boolean"
                                },
                                "closed_for_departure": {
                                    "type": "boolean"
                                },
                                "stop_sell": {
                                    "type": "boolean"
                                }
                            }
                        }
                    }
                }
            },
            "ErrorResponse": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "string",
                        "example": "invalid_credentials"
                    },
                    "message": {
                        "type": "string",
                        "example": "E-Mail oder Passwort ist falsch."
                    }
                }
            },
            "ValidationError": {
                "type": "object",
                "properties": {
                    "message": {
                        "type": "string"
                    },
                    "errors": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "Service": {
                "type": "object",
                "description": "Zusatzleistung pro Property. Mehrsprachig (Hotelsprache + Englisch),\nmit Verfügbarkeit, Preis, Distribution-Kanälen und optionalen\nLimitierungen. Detaillierte MwSt-Aufteilung erfolgt über die\nverknüpften `service_tax_configurations` (eigener Endpoint).\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 32,
                        "example": "BRKF",
                        "description": "Immutable nach Anlegen. Eindeutig pro Property."
                    },
                    "name_primary": {
                        "type": "string",
                        "maxLength": 160,
                        "description": "Anzeigename in der Hotelsprache der Property."
                    },
                    "name_en": {
                        "type": "string",
                        "maxLength": 160,
                        "description": "Anzeigename auf Englisch."
                    },
                    "description_primary": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "description_en": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "availability_mode": {
                        "type": "string",
                        "enum": [
                            "daily",
                            "on_arrival",
                            "once_per_stay"
                        ]
                    },
                    "offered_weekdays": {
                        "type": "array",
                        "nullable": true,
                        "description": "Tage der Woche (0 = Mo … 6 = So), an denen der Service angeboten wird.\n`null` oder leer = jeder Tag.\n",
                        "items": {
                            "type": "integer",
                            "minimum": 0,
                            "maximum": 6
                        }
                    },
                    "served_next_day": {
                        "type": "boolean",
                        "description": "Für Frühstück etc. — gebucht zur Nacht, serviert am Folgetag."
                    },
                    "price_type": {
                        "type": "string",
                        "enum": [
                            "per_room",
                            "per_person"
                        ]
                    },
                    "price_amount": {
                        "type": "number",
                        "format": "float",
                        "minimum": 0
                    },
                    "channels": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "enum": [
                                "direct",
                                "ibe",
                                "cm"
                            ]
                        }
                    },
                    "tax_rate_key": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "standard",
                            "reduced",
                            "zero"
                        ],
                        "description": "Fallback-MwSt-Satz, falls keine detaillierte `service_tax_configuration`\ngepflegt ist. Bei MwSt-Split-Konfig hat diese Vorrang.\n"
                    },
                    "served_for_age_group_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Wenn gesetzt, wird der Service nur an Gäste der angegebenen Altersgruppe\nvermarktet (z.B. Kindermenü nur für „Kind 4–11\"). Beim Löschen der\nAltersgruppe wird dieser Verweis auf NULL gesetzt.\n"
                    },
                    "restriction_min_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365
                    },
                    "restriction_max_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365
                    },
                    "restriction_valid_from": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "restriction_valid_to": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer"
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "ServiceInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "code",
                    "name_primary",
                    "name_en"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 32,
                        "description": "Wird serverseitig NICHT uppercase-normalisiert; der Client schickt uppercase."
                    },
                    "name_primary": {
                        "type": "string",
                        "maxLength": 160
                    },
                    "name_en": {
                        "type": "string",
                        "maxLength": 160
                    },
                    "description_primary": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "description_en": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "availability_mode": {
                        "type": "string",
                        "enum": [
                            "daily",
                            "on_arrival",
                            "once_per_stay"
                        ]
                    },
                    "offered_weekdays": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "integer",
                            "minimum": 0,
                            "maximum": 6
                        }
                    },
                    "served_next_day": {
                        "type": "boolean"
                    },
                    "price_type": {
                        "type": "string",
                        "enum": [
                            "per_room",
                            "per_person"
                        ]
                    },
                    "price_amount": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 99999.99
                    },
                    "channels": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "enum": [
                                "direct",
                                "ibe",
                                "cm"
                            ]
                        }
                    },
                    "tax_rate_key": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "standard",
                            "reduced",
                            "zero"
                        ]
                    },
                    "served_for_age_group_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "restriction_min_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365
                    },
                    "restriction_max_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365
                    },
                    "restriction_valid_from": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "restriction_valid_to": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0
                    }
                }
            },
            "ServiceUpdateInput": {
                "type": "object",
                "description": "`code` und `property_id` sind immutable und werden nicht akzeptiert.\nAlle anderen Felder sind optional (PATCH-Semantik).\n",
                "properties": {
                    "name_primary": {
                        "type": "string",
                        "maxLength": 160
                    },
                    "name_en": {
                        "type": "string",
                        "maxLength": 160
                    },
                    "description_primary": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "description_en": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "availability_mode": {
                        "type": "string",
                        "enum": [
                            "daily",
                            "on_arrival",
                            "once_per_stay"
                        ]
                    },
                    "offered_weekdays": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "integer",
                            "minimum": 0,
                            "maximum": 6
                        }
                    },
                    "served_next_day": {
                        "type": "boolean"
                    },
                    "price_type": {
                        "type": "string",
                        "enum": [
                            "per_room",
                            "per_person"
                        ]
                    },
                    "price_amount": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 99999.99
                    },
                    "channels": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "enum": [
                                "direct",
                                "ibe",
                                "cm"
                            ]
                        }
                    },
                    "tax_rate_key": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "standard",
                            "reduced",
                            "zero"
                        ]
                    },
                    "served_for_age_group_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "restriction_min_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365
                    },
                    "restriction_max_nights": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365
                    },
                    "restriction_valid_from": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "restriction_valid_to": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0
                    }
                }
            },
            "ServiceTaxComponent": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "position": {
                        "type": "integer"
                    },
                    "component_type": {
                        "type": "string",
                        "enum": [
                            "food",
                            "beverage",
                            "wellness",
                            "spa",
                            "parking",
                            "other"
                        ]
                    },
                    "allocation_type": {
                        "type": "string",
                        "enum": [
                            "fixed_amount",
                            "percent"
                        ],
                        "description": "`fixed_amount`: `allocation_value` in EUR, Summe = service.price_amount.\n`percent`: `allocation_value` in Prozent 0–100, Summe = 100.\n"
                    },
                    "allocation_value": {
                        "type": "number",
                        "description": "EUR-Betrag (bei fixed_amount) oder Prozent (bei percent)."
                    },
                    "tax_rate_key": {
                        "type": "string",
                        "enum": [
                            "standard",
                            "reduced",
                            "zero"
                        ]
                    }
                }
            },
            "ServiceTaxConfiguration": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "service_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "valid_from": {
                        "type": "string",
                        "format": "date",
                        "description": "Ab wann diese Konfiguration gilt."
                    },
                    "components": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ServiceTaxComponent"
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "ServiceTaxConfigurationInput": {
                "type": "object",
                "required": [
                    "valid_from",
                    "components"
                ],
                "properties": {
                    "valid_from": {
                        "type": "string",
                        "format": "date"
                    },
                    "components": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 20,
                        "items": {
                            "type": "object",
                            "required": [
                                "component_type",
                                "allocation_type",
                                "allocation_value",
                                "tax_rate_key"
                            ],
                            "properties": {
                                "component_type": {
                                    "type": "string",
                                    "enum": [
                                        "food",
                                        "beverage",
                                        "wellness",
                                        "spa",
                                        "parking",
                                        "other"
                                    ]
                                },
                                "allocation_type": {
                                    "type": "string",
                                    "enum": [
                                        "fixed_amount",
                                        "percent"
                                    ]
                                },
                                "allocation_value": {
                                    "type": "number",
                                    "minimum": 0
                                },
                                "tax_rate_key": {
                                    "type": "string",
                                    "enum": [
                                        "standard",
                                        "reduced",
                                        "zero"
                                    ]
                                }
                            }
                        }
                    }
                }
            },
            "AgeGroup": {
                "type": "object",
                "description": "Altersgruppe pro Property. `min_age` und `max_age` sind beide nullable\nfür offene Grenzen: z.B. Erwachsene `min_age=18, max_age=null` (ab 18).\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 32,
                        "description": "Immutable nach Anlegen. Eindeutig pro Property."
                    },
                    "name_primary": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "name_en": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "min_age": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 130
                    },
                    "max_age": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 130
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer"
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "AgeGroupInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "code",
                    "name_primary",
                    "name_en"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "code": {
                        "type": "string",
                        "maxLength": 32
                    },
                    "name_primary": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "name_en": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "min_age": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 130
                    },
                    "max_age": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 130
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0
                    }
                }
            },
            "AgeGroupUpdateInput": {
                "type": "object",
                "description": "`code` und `property_id` sind immutable. `max_age` muss ≥ `min_age` sein.\n",
                "properties": {
                    "name_primary": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "name_en": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "min_age": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 130
                    },
                    "max_age": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 130
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "position": {
                        "type": "integer",
                        "minimum": 0
                    }
                }
            },
            "Guest": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "first_name": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "last_name": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true,
                        "maxLength": 180
                    },
                    "phone": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 40
                    },
                    "birth_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "nationality": {
                        "type": "string",
                        "nullable": true,
                        "description": "ISO-3166-1 alpha-2 (z.B. DE, FR, US)",
                        "minLength": 2,
                        "maxLength": 2
                    },
                    "language": {
                        "type": "string",
                        "nullable": true,
                        "description": "ISO-639-1 (z.B. de, en, fr)",
                        "minLength": 2,
                        "maxLength": 2
                    },
                    "address": {
                        "type": "object",
                        "nullable": true,
                        "properties": {
                            "street": {
                                "type": "string",
                                "nullable": true
                            },
                            "postal_code": {
                                "type": "string",
                                "nullable": true
                            },
                            "city": {
                                "type": "string",
                                "nullable": true
                            },
                            "country": {
                                "type": "string",
                                "minLength": 2,
                                "maxLength": 2,
                                "nullable": true
                            }
                        }
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "GuestInput": {
                "type": "object",
                "required": [
                    "first_name",
                    "last_name"
                ],
                "properties": {
                    "first_name": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "last_name": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true,
                        "maxLength": 180
                    },
                    "phone": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 40
                    },
                    "birth_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "nationality": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 2,
                        "nullable": true
                    },
                    "language": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 2,
                        "nullable": true
                    },
                    "address": {
                        "type": "object",
                        "nullable": true,
                        "properties": {
                            "street": {
                                "type": "string",
                                "nullable": true,
                                "maxLength": 255
                            },
                            "postal_code": {
                                "type": "string",
                                "nullable": true,
                                "maxLength": 20
                            },
                            "city": {
                                "type": "string",
                                "nullable": true,
                                "maxLength": 100
                            },
                            "country": {
                                "type": "string",
                                "minLength": 2,
                                "maxLength": 2,
                                "nullable": true
                            }
                        }
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    }
                }
            },
            "Folio": {
                "type": "object",
                "description": "Sammeltopf für Posten. Gehört entweder zu einer **Reservation**\n(`reservation_id` gesetzt, `group_id` NULL — typischer Gast-Folio)\n**oder** zu einer **Gruppe** (`group_id` gesetzt, `reservation_id`\nNULL — Gruppen-Folio ab Paket 4.3). DB-CHECK erzwingt, dass genau\neines von beiden gesetzt ist. Summen + paid_total werden on-the-fly\nberechnet — Teil-Refunds gehen mit `effective_amount` ein.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "reservation_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Gesetzt bei Reservation-Folio, NULL bei Gruppen-Folio"
                    },
                    "group_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Gesetzt bei Gruppen-Folio (Paket 4.3), NULL bei Reservation-Folio"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "label": {
                        "type": "string",
                        "example": "Gast-Folio"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "open",
                            "closed"
                        ]
                    },
                    "closed_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "description": "Inklusive History-Einträge aus Charge-Transfers"
                    },
                    "total_gross": {
                        "type": "number",
                        "format": "float",
                        "description": "Brutto-Summe aktiver Charges"
                    },
                    "total_net": {
                        "type": "number",
                        "format": "float"
                    },
                    "total_tax": {
                        "type": "number",
                        "format": "float"
                    },
                    "paid_total": {
                        "type": "number",
                        "format": "float",
                        "description": "Summe wirksamer Zahlungen (amount - refunded_amount pro Payment)"
                    },
                    "open_balance": {
                        "type": "number",
                        "format": "float",
                        "description": "total_gross − paid_total. Kann negativ sein bei Überzahlung."
                    },
                    "is_paid": {
                        "type": "boolean",
                        "description": "open_balance ≤ 0"
                    },
                    "charges": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Charge"
                        }
                    },
                    "payments": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Payment"
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Charge": {
                "type": "object",
                "description": "Einzelner Posten in einem Folio. Brutto ist die primäre Zahl\n(Hotellerie-Standard), Netto und MwSt werden daraus berechnet.\nGevoidete Charges bleiben in der DB (GoBD), zählen aber nicht\nin den Folio-Summen.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "folio_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "type": {
                        "type": "string",
                        "enum": [
                            "accommodation",
                            "service",
                            "manual",
                            "discount"
                        ]
                    },
                    "description": {
                        "type": "string"
                    },
                    "service_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "quantity": {
                        "type": "number",
                        "format": "float"
                    },
                    "unit_price_gross": {
                        "type": "number",
                        "format": "float"
                    },
                    "amount_gross": {
                        "type": "number",
                        "format": "float"
                    },
                    "amount_net": {
                        "type": "number",
                        "format": "float"
                    },
                    "tax_rate": {
                        "type": "number",
                        "format": "float",
                        "example": 7
                    },
                    "tax_amount": {
                        "type": "number",
                        "format": "float"
                    },
                    "service_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "voided_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "voided_reason": {
                        "type": "string",
                        "nullable": true
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "true wenn nicht gevoided"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "ChargeInput": {
                "type": "object",
                "required": [
                    "type",
                    "description",
                    "quantity",
                    "unit_price_gross",
                    "tax_rate",
                    "service_date"
                ],
                "properties": {
                    "type": {
                        "type": "string",
                        "enum": [
                            "service",
                            "manual",
                            "discount"
                        ],
                        "description": "accommodation wird nur vom System erzeugt"
                    },
                    "description": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "service_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "quantity": {
                        "type": "number",
                        "format": "float",
                        "minimum": 0.01
                    },
                    "unit_price_gross": {
                        "type": "number",
                        "format": "float",
                        "description": "Bei discount automatisch negativ gemacht"
                    },
                    "tax_rate": {
                        "type": "number",
                        "format": "float",
                        "minimum": 0,
                        "maximum": 100
                    },
                    "service_date": {
                        "type": "string",
                        "format": "date"
                    }
                }
            },
            "UnitBlock": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "unit_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "from_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "to_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "reason": {
                        "type": "string",
                        "maxLength": 60
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "UnitBlockInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "unit_id",
                    "from_date",
                    "to_date",
                    "reason"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "unit_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "from_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "to_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "reason": {
                        "type": "string",
                        "maxLength": 60
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "Payment": {
                "type": "object",
                "description": "Zahlungseingang auf ein Folio (Einzel- oder Gruppen-Folio).\nBetrag immer positiv. Erstattungen werden GoBD-konform als\nMutation dokumentiert (`refunded_at`, `refunded_amount`,\n`refund_method`, `refunded_reason`) — Payment bleibt in der DB.\n\n**Partial-Refund (Paket 3.10):** wenn nur ein Teil erstattet\nwurde, ist `refunded_amount` kleiner als `amount`. Der wirksame\nBeitrag am Folio ist `effective_amount = amount - refunded_amount`.\nMehrere Teil-Refunds kumulieren im `refunded_amount` und werden\nchronologisch in `refunded_reason` protokolliert.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "folio_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "invoice_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "method": {
                        "type": "string",
                        "enum": [
                            "cash",
                            "credit_card",
                            "debit_card",
                            "bank_transfer",
                            "invoice",
                            "voucher",
                            "other"
                        ]
                    },
                    "method_label": {
                        "type": "string",
                        "example": "Bar"
                    },
                    "amount": {
                        "type": "number",
                        "format": "float"
                    },
                    "currency": {
                        "type": "string",
                        "example": "EUR"
                    },
                    "reference": {
                        "type": "string",
                        "nullable": true
                    },
                    "received_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "refunded_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "Zeitpunkt der (ggf. Teil-)Erstattung"
                    },
                    "refunded_amount": {
                        "type": "number",
                        "format": "float",
                        "nullable": true,
                        "description": "Kumulativer erstatteter Betrag (kann < amount sein bei Teil-Refund)"
                    },
                    "refund_method": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "cash",
                            "credit_card",
                            "debit_card",
                            "bank_transfer",
                            "invoice",
                            "voucher",
                            "other"
                        ],
                        "description": "Methode der letzten Refund-Aktion"
                    },
                    "refund_method_label": {
                        "type": "string",
                        "nullable": true,
                        "example": "Bar"
                    },
                    "refunded_reason": {
                        "type": "string",
                        "nullable": true,
                        "description": "Chronologische Historie aller Refund-Aktionen"
                    },
                    "effective_amount": {
                        "type": "number",
                        "format": "float",
                        "description": "amount - refunded_amount — wirksamer Beitrag zum Folio"
                    },
                    "is_active": {
                        "type": "boolean",
                        "description": "true wenn noch nicht (voll) erstattet"
                    },
                    "is_fully_refunded": {
                        "type": "boolean"
                    },
                    "is_partially_refunded": {
                        "type": "boolean"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "PaymentInput": {
                "type": "object",
                "required": [
                    "method",
                    "amount"
                ],
                "properties": {
                    "method": {
                        "type": "string",
                        "enum": [
                            "cash",
                            "credit_card",
                            "debit_card",
                            "bank_transfer",
                            "invoice",
                            "voucher",
                            "other"
                        ]
                    },
                    "amount": {
                        "type": "number",
                        "format": "float",
                        "minimum": 0.01
                    },
                    "currency": {
                        "type": "string",
                        "example": "EUR",
                        "default": "EUR"
                    },
                    "reference": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 200
                    },
                    "received_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Default: jetzt"
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "invoice_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Optionale Zuordnung zu einer Rechnung dieses Folios (Paket 3.7d).\nErmöglicht präzise Zuordnung z. B. bei Split-Rechnungen\n(Firma vs. Gast). Ohne Zuordnung zählt die Zahlung am\nFolio-Saldo, aber an keiner spezifischen Rechnung.\n"
                    }
                }
            },
            "Invoice": {
                "type": "object",
                "description": "Rechnung mit fortlaufender, fiskalisch eindeutiger Nummer.\nSchneidet eine Teilmenge von Charges eines Folios ab\n(über Charge.invoice_id). Storno erfolgt über eine zweite\nRechnung mit reverses_invoice_id-Verweis und Negativ-Summen.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "folio_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "invoice_number": {
                        "type": "string",
                        "description": "Format wird pro Property konfiguriert",
                        "example": "LEB-2026-0001"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "issued",
                            "cancelled",
                            "reversal"
                        ]
                    },
                    "issued_at": {
                        "type": "string",
                        "format": "date"
                    },
                    "recipient_name": {
                        "type": "string"
                    },
                    "recipient_address": {
                        "type": "object",
                        "nullable": true,
                        "properties": {
                            "street": {
                                "type": "string",
                                "nullable": true
                            },
                            "postal_code": {
                                "type": "string",
                                "nullable": true
                            },
                            "city": {
                                "type": "string",
                                "nullable": true
                            },
                            "country": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    },
                    "recipient_email": {
                        "type": "string",
                        "nullable": true
                    },
                    "total_gross": {
                        "type": "number",
                        "format": "float"
                    },
                    "total_net": {
                        "type": "number",
                        "format": "float"
                    },
                    "total_tax": {
                        "type": "number",
                        "format": "float"
                    },
                    "reverses_invoice_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "cancelled_by_invoice_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "is_reversal": {
                        "type": "boolean"
                    },
                    "is_cancelled": {
                        "type": "boolean"
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "last_sent_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "last_sent_to": {
                        "type": "string",
                        "nullable": true
                    },
                    "sent_count": {
                        "type": "integer"
                    },
                    "paid_total": {
                        "type": "number",
                        "format": "float"
                    },
                    "open_balance": {
                        "type": "number",
                        "format": "float"
                    },
                    "is_paid": {
                        "type": "boolean"
                    },
                    "charges": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Charge"
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "InvoiceInput": {
                "type": "object",
                "required": [
                    "charge_ids"
                ],
                "properties": {
                    "charge_ids": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "minItems": 1,
                        "description": "IDs der Charges, die auf diese Rechnung kommen sollen. Müssen zum Folio gehören, aktiv und noch keiner Rechnung zugeordnet sein."
                    },
                    "recipient": {
                        "type": "object",
                        "description": "Optionaler Empfänger-Override (z.B. für Firmen-Rechnung). Default ist der primary_guest der Reservation.",
                        "properties": {
                            "name": {
                                "type": "string",
                                "nullable": true,
                                "maxLength": 200
                            },
                            "email": {
                                "type": "string",
                                "nullable": true,
                                "format": "email",
                                "maxLength": 200
                            },
                            "address": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                    "street": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "postal_code": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "city": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "country": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "Reservation": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "booking_number": {
                        "type": "string",
                        "description": "Automatisch generiert, Format <PROPERTY_CODE>-<YY>-<NNNN>.",
                        "example": "LLB-26-0001"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "group_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Optionale Zuordnung zu einer ReservationGroup (Paket 4.1).\nNULL bei Einzelreservierungen. Wird per attach/detach-Endpoints\nder Gruppe gesetzt oder beim Quick-Create mit group_id-Prop.\n"
                    },
                    "group": {
                        "type": "object",
                        "nullable": true,
                        "description": "Nur bei show() — komprimierter Gruppen-Ref.",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "name": {
                                "type": "string"
                            },
                            "status": {
                                "type": "string"
                            }
                        }
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "assigned_unit_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Zugewiesenes Zimmer. Optional — kann beim Anlegen null bleiben und\nerst beim Check-in zugewiesen werden.\n"
                    },
                    "primary_guest_id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "FK auf guests — Hauptbuchender."
                    },
                    "arrival": {
                        "type": "string",
                        "format": "date"
                    },
                    "departure": {
                        "type": "string",
                        "format": "date"
                    },
                    "nights": {
                        "type": "integer",
                        "nullable": true
                    },
                    "adults": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20
                    },
                    "children": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 20
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "booked",
                            "checked_in",
                            "checked_out",
                            "cancelled",
                            "no_show"
                        ]
                    },
                    "option_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Ablaufdatum, wenn status=option. Wenn überschritten, zählt die\nReservation in der Availability-Suche nicht mehr als belegt.\nConfirm bringt sie auf status=booked.\n"
                    },
                    "channel": {
                        "type": "string",
                        "enum": [
                            "direct",
                            "ibe",
                            "cm"
                        ]
                    },
                    "external_reference": {
                        "type": "string",
                        "nullable": true,
                        "description": "Externe Buchungsnummer (z.B. Booking.com-ID)."
                    },
                    "booked_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "primary_guest": {
                        "type": "object",
                        "description": "Nur bei Detail-Abruf mitgeladen.",
                        "nullable": true,
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "first_name": {
                                "type": "string"
                            },
                            "last_name": {
                                "type": "string"
                            },
                            "email": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    },
                    "additional_guests": {
                        "type": "array",
                        "description": "Nur bei Detail-Abruf mitgeladen.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "string",
                                    "format": "uuid"
                                },
                                "guest_id": {
                                    "type": "string",
                                    "format": "uuid"
                                },
                                "age_group_id": {
                                    "type": "string",
                                    "format": "uuid",
                                    "nullable": true
                                },
                                "position": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "ReservationInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "unit_group_id",
                    "rate_plan_id",
                    "primary_guest_id",
                    "arrival",
                    "departure"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "assigned_unit_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "primary_guest_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "arrival": {
                        "type": "string",
                        "format": "date"
                    },
                    "departure": {
                        "type": "string",
                        "format": "date",
                        "description": "Muss nach `arrival` liegen (422 wenn nicht)."
                    },
                    "adults": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20
                    },
                    "children": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 20
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "booked",
                            "checked_in",
                            "checked_out",
                            "cancelled",
                            "no_show"
                        ]
                    },
                    "option_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Ablaufdatum der Option. Nur relevant wenn status=option. Nach\ndem Datum wird die Buchung in der Availability-Suche ignoriert.\n"
                    },
                    "channel": {
                        "type": "string",
                        "enum": [
                            "direct",
                            "ibe",
                            "cm"
                        ]
                    },
                    "external_reference": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 120
                    },
                    "booked_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "additional_guests": {
                        "type": "array",
                        "description": "Optional. Begleiter als Pivot-Einträge.",
                        "items": {
                            "type": "object",
                            "required": [
                                "guest_id"
                            ],
                            "properties": {
                                "guest_id": {
                                    "type": "string",
                                    "format": "uuid"
                                },
                                "age_group_id": {
                                    "type": "string",
                                    "format": "uuid",
                                    "nullable": true
                                }
                            }
                        }
                    }
                }
            },
            "ReservationUpdateInput": {
                "type": "object",
                "description": "`booking_number` und `property_id` sind immutable. Alle anderen Felder\noptional (PATCH-Semantik).\n",
                "properties": {
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "assigned_unit_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "primary_guest_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "arrival": {
                        "type": "string",
                        "format": "date"
                    },
                    "departure": {
                        "type": "string",
                        "format": "date"
                    },
                    "adults": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20
                    },
                    "children": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 20
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "booked",
                            "checked_in",
                            "checked_out",
                            "cancelled",
                            "no_show"
                        ]
                    },
                    "option_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "channel": {
                        "type": "string",
                        "enum": [
                            "direct",
                            "ibe",
                            "cm"
                        ]
                    },
                    "external_reference": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 120
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    }
                }
            },
            "ReservationGroup": {
                "type": "object",
                "description": "Container über mehrere Einzelreservationen. Hält den Organisator\n(Guest, typisch Firma mit `company_name`), einen optionalen Anlass\n(Hochzeit, Tagung, Konferenz … plus Freitext) und optional ein\nVeranstaltungsdatum, das unabhängig vom An-/Abreisezeitraum der\nGäste ist. Jede Einzelreservation bleibt autonom und bekommt ihr\neigenes Folio; zusätzlich existiert ein **Gruppen-Folio** für\ngruppenweite Posten.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 200,
                        "example": "Hochzeit Müller-Schmidt 15.06.26"
                    },
                    "occasion": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 60,
                        "description": "Anlass — freier String. Typische Preset-Werte (werden\nim Frontend in Labels übersetzt): wedding, conference,\nmeeting, birthday, event, congress, company_party,\nbus_group, excursion_group, cycling_group, other.\nAndere Freitexte werden 1:1 übernommen.\n"
                    },
                    "occasion_label": {
                        "type": "string",
                        "nullable": true,
                        "description": "Deutsches Label für Preset-Keys, sonst der Freitext."
                    },
                    "event_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Tag der eigentlichen Veranstaltung. Unabhängig vom\nAn-/Abreisezeitraum der Gäste — Hochzeit am Samstag,\nGäste kommen Donnerstag bis Montag.\n"
                    },
                    "organizer_guest_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Hauptkontakt / Rechnungsempfänger. Typisch eine Firma (Guest mit company_name)."
                    },
                    "organizer": {
                        "type": "object",
                        "nullable": true,
                        "description": "Nur wenn geladen — komprimierte Guest-Ref.",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "first_name": {
                                "type": "string",
                                "nullable": true
                            },
                            "last_name": {
                                "type": "string",
                                "nullable": true
                            },
                            "company_name": {
                                "type": "string",
                                "nullable": true
                            },
                            "email": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "confirmed",
                            "in_house",
                            "completed",
                            "cancelled"
                        ],
                        "description": "Persistierter Status. 'option' = Gruppe ist als Option\ngehalten (z.B. Firmen-Veranstaltungs-Anfrage, 20 Zimmer\nbis Datum X vorgemerkt).\n"
                    },
                    "option_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Ablaufdatum der Gruppen-Option. Nach dem Datum kann die\nGruppe automatisch verfallen oder manuell bestätigt werden.\n"
                    },
                    "derived_status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "confirmed",
                            "in_house",
                            "completed",
                            "cancelled"
                        ],
                        "description": "Aus den Mitgliedern abgeleitet: `cancelled` wenn alle\nstorniert, `in_house` bei min. einem checked_in,\n`completed` wenn alle checked_out, `confirmed` wenn alle\nbooked+, sonst persistierter Wert.\n"
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "reservation_count": {
                        "type": "integer"
                    },
                    "active_reservation_count": {
                        "type": "integer"
                    },
                    "min_arrival": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Früheste Anreise unter Mitgliedern (ausgenommen cancelled)."
                    },
                    "max_departure": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "reservations": {
                        "type": "array",
                        "description": "Nur bei show() — Mitglieds-Reservationen.",
                        "items": {
                            "$ref": "#/components/schemas/Reservation"
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "ReservationGroupInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "name"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 200
                    },
                    "occasion": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 60
                    },
                    "event_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "organizer_guest_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "confirmed",
                            "in_house",
                            "completed",
                            "cancelled"
                        ]
                    },
                    "option_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    }
                }
            },
            "ReservationGroupUpdateInput": {
                "type": "object",
                "description": "Alle Felder optional — PATCH-Semantik.",
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 200
                    },
                    "occasion": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 60
                    },
                    "event_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "organizer_guest_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "inquiry",
                            "option",
                            "confirmed",
                            "in_house",
                            "completed",
                            "cancelled"
                        ]
                    },
                    "option_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    }
                }
            },
            "BulkReservationInput": {
                "type": "object",
                "description": "Bulk-Anlage von N identischen Reservations innerhalb einer Gruppe\n(Paket 4.2b). Alle Reservations bekommen aufsteigende Buchungs-\nnummern, denselben Haupt-Gast (z. B. Firma oder Reiseveranstalter),\nund ihre jeweiligen Einzel-Folios inkl. Accommodation-Charges.\n",
                "required": [
                    "count",
                    "arrival",
                    "departure",
                    "unit_group_id",
                    "rate_plan_id",
                    "primary_guest_id",
                    "adults"
                ],
                "properties": {
                    "count": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 50
                    },
                    "arrival": {
                        "type": "string",
                        "format": "date"
                    },
                    "departure": {
                        "type": "string",
                        "format": "date"
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "primary_guest_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "adults": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 20
                    },
                    "children": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 20,
                        "default": 0
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    }
                }
            },
            "ChargeTaxComponent": {
                "type": "object",
                "description": "MwSt-Komponente eines Charges — bei Services mit Tax-Split wird\npro Komponente (Speise 7 % + Getränk 19 % etc.) ein eigener\nEintrag erzeugt. Summiert sich zu den Charge-Totals.\n",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "charge_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "label": {
                        "type": "string",
                        "example": "Speisen"
                    },
                    "tax_rate": {
                        "type": "number",
                        "format": "float",
                        "example": 7
                    },
                    "amount_gross": {
                        "type": "number",
                        "format": "float"
                    },
                    "amount_net": {
                        "type": "number",
                        "format": "float"
                    },
                    "amount_tax": {
                        "type": "number",
                        "format": "float"
                    }
                }
            },
            "InvoiceCreateInput": {
                "type": "object",
                "description": "Body für POST /api/folios/{folio}/invoices (Paket 3.7 + 3.10).\nDrei Wege, den Empfänger festzulegen:\n\n1. **recipient_guest_id** (empfohlen) — Guest-ID aus der DB.\n   Empfänger-Snapshot wird gezogen: Firma zuerst, dann\n   \"z. Hd. Max Mustermann\" wenn Person dran. Adresse + Email\n   aus dem Guest.\n2. **recipient** (Ad-hoc) — freie Felder für Sonderfälle\n   ohne DB-Eintrag.\n3. Default (keine der beiden) — primary_guest der Reservation.\n\nrecipient_guest_id hat Vorrang.\n",
                "required": [
                    "charge_ids"
                ],
                "properties": {
                    "charge_ids": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "minItems": 1
                    },
                    "recipient_guest_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Guest aus der DB — Empfänger-Snapshot wird dort gezogen."
                    },
                    "recipient": {
                        "type": "object",
                        "description": "Ad-hoc-Empfänger ohne DB-Eintrag.",
                        "properties": {
                            "name": {
                                "type": "string",
                                "nullable": true,
                                "maxLength": 200
                            },
                            "email": {
                                "type": "string",
                                "nullable": true,
                                "format": "email",
                                "maxLength": 200
                            },
                            "address": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                    "street": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "postal_code": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "city": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "country": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "Role": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "slug": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "is_system": {
                        "type": "boolean"
                    },
                    "permissions": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "user_count": {
                        "type": "integer"
                    }
                }
            },
            "RoleInput": {
                "type": "object",
                "properties": {
                    "slug": {
                        "type": "string",
                        "pattern": "^[a-z][a-z0-9-]{1,39}$"
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 80
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "permissions": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "Membership": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "kind": {
                        "type": "string",
                        "enum": [
                            "user"
                        ]
                    },
                    "email": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "role_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "role_slug": {
                        "type": "string",
                        "nullable": true
                    },
                    "role_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "role_is_system": {
                        "type": "boolean"
                    },
                    "role_display_name": {
                        "type": "string"
                    },
                    "permission_overrides": {
                        "type": "object",
                        "properties": {
                            "granted": {
                                "type": "array",
                                "items": {
                                    "type": "string"
                                }
                            },
                            "revoked": {
                                "type": "array",
                                "items": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "has_overrides": {
                        "type": "boolean"
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "is_default": {
                        "type": "boolean"
                    },
                    "last_login_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "PendingInvitation": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "kind": {
                        "type": "string",
                        "enum": [
                            "invitation"
                        ]
                    },
                    "email": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "role_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "role_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "expires_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "invitation_id": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            },
            "OposBucket": {
                "type": "object",
                "properties": {
                    "key": {
                        "type": "string",
                        "enum": [
                            "not_due",
                            17,
                            830,
                            3060,
                            "60_plus"
                        ]
                    },
                    "label": {
                        "type": "string"
                    },
                    "count": {
                        "type": "integer"
                    },
                    "sum": {
                        "type": "number"
                    },
                    "rows": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/OposInvoice"
                        }
                    }
                }
            },
            "OposInvoice": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "folio_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "invoice_number": {
                        "type": "string"
                    },
                    "issued_at": {
                        "type": "string",
                        "format": "date"
                    },
                    "due_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "recipient_name": {
                        "type": "string"
                    },
                    "total_gross": {
                        "type": "number"
                    },
                    "paid_total": {
                        "type": "number"
                    },
                    "open_balance": {
                        "type": "number"
                    },
                    "is_overdue": {
                        "type": "boolean"
                    },
                    "days_overdue": {
                        "type": "integer",
                        "nullable": true
                    },
                    "reservation": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true
                            },
                            "booking_number": {
                                "type": "string",
                                "nullable": true
                            },
                            "arrival": {
                                "type": "string",
                                "format": "date",
                                "nullable": true
                            },
                            "departure": {
                                "type": "string",
                                "format": "date",
                                "nullable": true
                            }
                        }
                    },
                    "property": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true
                            },
                            "code": {
                                "type": "string",
                                "nullable": true
                            },
                            "name": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    }
                }
            },
            "FinanceSummary": {
                "type": "object",
                "properties": {
                    "open_sum": {
                        "type": "number"
                    },
                    "open_count": {
                        "type": "integer"
                    },
                    "overdue_sum": {
                        "type": "number"
                    },
                    "overdue_count": {
                        "type": "integer"
                    },
                    "oldest_due_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "oldest_days_overdue": {
                        "type": "integer",
                        "nullable": true
                    }
                }
            },
            "Dunning": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "invoice_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "level": {
                        "type": "integer"
                    },
                    "title": {
                        "type": "string"
                    },
                    "fee_amount": {
                        "type": "number"
                    },
                    "fee_charge_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "sent_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "sent_to_email": {
                        "type": "string",
                        "nullable": true
                    },
                    "open_balance_at_send": {
                        "type": "number"
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "DunningEligible": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "invoice_number": {
                        "type": "string"
                    },
                    "recipient_name": {
                        "type": "string"
                    },
                    "recipient_email": {
                        "type": "string",
                        "nullable": true
                    },
                    "issued_at": {
                        "type": "string",
                        "format": "date"
                    },
                    "due_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "days_overdue": {
                        "type": "integer"
                    },
                    "open_balance": {
                        "type": "number"
                    },
                    "current_level": {
                        "type": "integer"
                    },
                    "last_dunning_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "next_stage": {
                        "type": "object",
                        "properties": {
                            "level": {
                                "type": "integer"
                            },
                            "title": {
                                "type": "string"
                            },
                            "fee_amount": {
                                "type": "number"
                            },
                            "days_after_due": {
                                "type": "integer"
                            }
                        }
                    },
                    "property": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true
                            },
                            "code": {
                                "type": "string",
                                "nullable": true
                            },
                            "name": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    },
                    "reservation": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true
                            },
                            "booking_number": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    }
                }
            },
            "DunningHistoryRow": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Dunning"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "invoice": {
                                "type": "object",
                                "properties": {
                                    "id": {
                                        "type": "string",
                                        "format": "uuid",
                                        "nullable": true
                                    },
                                    "invoice_number": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "recipient_name": {
                                        "type": "string",
                                        "nullable": true
                                    },
                                    "due_date": {
                                        "type": "string",
                                        "format": "date",
                                        "nullable": true
                                    }
                                }
                            },
                            "reservation": {
                                "type": "object",
                                "properties": {
                                    "id": {
                                        "type": "string",
                                        "format": "uuid",
                                        "nullable": true
                                    },
                                    "booking_number": {
                                        "type": "string",
                                        "nullable": true
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            "DunningStage": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "level": {
                        "type": "integer"
                    },
                    "days_after_due": {
                        "type": "integer"
                    },
                    "fee_amount": {
                        "type": "number"
                    },
                    "title": {
                        "type": "string",
                        "maxLength": 80
                    },
                    "body_template": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "DunningStageInput": {
                "type": "object",
                "required": [
                    "level",
                    "days_after_due",
                    "fee_amount",
                    "title"
                ],
                "properties": {
                    "level": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 99
                    },
                    "days_after_due": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 365
                    },
                    "fee_amount": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 10000
                    },
                    "title": {
                        "type": "string",
                        "maxLength": 80
                    },
                    "body_template": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 4000
                    }
                }
            },
            "PaymentForInvoice": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "method": {
                        "type": "string",
                        "enum": [
                            "cash",
                            "credit_card",
                            "debit_card",
                            "bank_transfer",
                            "invoice",
                            "voucher",
                            "other"
                        ]
                    },
                    "amount": {
                        "type": "number"
                    },
                    "currency": {
                        "type": "string"
                    },
                    "reference": {
                        "type": "string",
                        "nullable": true
                    },
                    "received_at": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "refunded_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "refunded_amount": {
                        "type": "number",
                        "nullable": true
                    },
                    "refund_method": {
                        "type": "string",
                        "nullable": true
                    },
                    "refunded_reason": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "CashBook": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "name": {
                        "type": "string"
                    },
                    "opening_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "opening_balance": {
                        "type": "number"
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "current_balance": {
                        "type": "number"
                    }
                }
            },
            "CashBookEntry": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "entry_no": {
                        "type": "integer"
                    },
                    "booking_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "booking_time": {
                        "type": "string",
                        "nullable": true
                    },
                    "type": {
                        "type": "string",
                        "enum": [
                            "income",
                            "expense"
                        ]
                    },
                    "amount": {
                        "type": "number"
                    },
                    "description": {
                        "type": "string"
                    },
                    "reference": {
                        "type": "string",
                        "nullable": true
                    },
                    "payment_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "counter_entry_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "voided_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "voided_reason": {
                        "type": "string",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "CashBookClosing": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "closing_date": {
                        "type": "string",
                        "format": "date"
                    },
                    "system_balance": {
                        "type": "number"
                    },
                    "counted_balance": {
                        "type": "number"
                    },
                    "difference": {
                        "type": "number"
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "closed_by_user_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "closed_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "CashBookDay": {
                "type": "object",
                "properties": {
                    "cash_book": {
                        "$ref": "#/components/schemas/CashBook"
                    },
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "start_balance": {
                        "type": "number"
                    },
                    "end_balance": {
                        "type": "number"
                    },
                    "is_closed": {
                        "type": "boolean"
                    },
                    "entries": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/CashBookEntry"
                        }
                    },
                    "closing": {
                        "$ref": "#/components/schemas/CashBookClosing",
                        "nullable": true
                    }
                }
            },
            "Quote": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "quote_number": {
                        "type": "string",
                        "description": "Q-YYYY-NNNN",
                        "example": "Q-2026-0042"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "draft",
                            "sent",
                            "accepted",
                            "declined",
                            "expired",
                            "withdrawn"
                        ]
                    },
                    "is_expired": {
                        "type": "boolean"
                    },
                    "recipient_name": {
                        "type": "string"
                    },
                    "recipient_email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true
                    },
                    "recipient_phone": {
                        "type": "string",
                        "nullable": true
                    },
                    "recipient_address": {
                        "type": "object",
                        "nullable": true,
                        "properties": {
                            "street": {
                                "type": "string",
                                "nullable": true
                            },
                            "postal_code": {
                                "type": "string",
                                "nullable": true
                            },
                            "city": {
                                "type": "string",
                                "nullable": true
                            },
                            "country": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    },
                    "greeting_text": {
                        "type": "string",
                        "nullable": true
                    },
                    "internal_notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "option_hold_days": {
                        "type": "integer",
                        "enum": [
                            3,
                            7,
                            14
                        ]
                    },
                    "language": {
                        "type": "string",
                        "enum": [
                            "de",
                            "en"
                        ],
                        "description": "Sprache der Mini-Homepage und Mail"
                    },
                    "valid_until": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "prepayment_amount": {
                        "type": "number",
                        "nullable": true
                    },
                    "prepayment_note": {
                        "type": "string",
                        "nullable": true
                    },
                    "viewed_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "sent_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "accepted_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "accepted_option_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "declined_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "declined_reason": {
                        "type": "string",
                        "nullable": true
                    },
                    "expired_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "withdrawn_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "withdrawn_reason": {
                        "type": "string",
                        "nullable": true
                    },
                    "created_by_user_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "sent_by_user_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "plain_token": {
                        "type": "string",
                        "description": "Plaintext-Token, nur direkt nach POST /quotes oder POST /quotes/{id}/send. NIE persistiert.",
                        "nullable": true
                    },
                    "options": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/QuoteOption"
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "QuoteOption": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "position": {
                        "type": "integer"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "price_override": {
                        "type": "number",
                        "nullable": true
                    },
                    "reservation_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "reservation": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "booking_number": {
                                "type": "string"
                            },
                            "unit_group_id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "rate_plan_id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "arrival": {
                                "type": "string",
                                "format": "date"
                            },
                            "departure": {
                                "type": "string",
                                "format": "date"
                            },
                            "nights": {
                                "type": "integer"
                            },
                            "adults": {
                                "type": "integer"
                            },
                            "children": {
                                "type": "integer"
                            },
                            "status": {
                                "type": "string"
                            },
                            "option_until": {
                                "type": "string",
                                "format": "date",
                                "nullable": true
                            }
                        }
                    }
                }
            },
            "QuoteInput": {
                "type": "object",
                "required": [
                    "property_id",
                    "recipient_name",
                    "option_hold_days",
                    "options"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "recipient_name": {
                        "type": "string",
                        "maxLength": 200
                    },
                    "recipient_email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true
                    },
                    "recipient_phone": {
                        "type": "string",
                        "nullable": true
                    },
                    "recipient_address": {
                        "type": "object",
                        "nullable": true,
                        "properties": {
                            "street": {
                                "type": "string",
                                "nullable": true
                            },
                            "postal_code": {
                                "type": "string",
                                "nullable": true
                            },
                            "city": {
                                "type": "string",
                                "nullable": true
                            },
                            "country": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    },
                    "greeting_text": {
                        "type": "string",
                        "nullable": true
                    },
                    "internal_notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "option_hold_days": {
                        "type": "integer",
                        "enum": [
                            3,
                            7,
                            14
                        ]
                    },
                    "language": {
                        "type": "string",
                        "enum": [
                            "de",
                            "en"
                        ],
                        "description": "Default: Property-Primärsprache"
                    },
                    "prepayment_amount": {
                        "type": "number",
                        "nullable": true
                    },
                    "prepayment_note": {
                        "type": "string",
                        "nullable": true
                    },
                    "options": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 5,
                        "items": {
                            "$ref": "#/components/schemas/QuoteOptionInput"
                        }
                    }
                }
            },
            "QuoteOptionInput": {
                "type": "object",
                "required": [
                    "unit_group_id",
                    "rate_plan_id",
                    "arrival",
                    "departure",
                    "adults"
                ],
                "properties": {
                    "position": {
                        "type": "integer",
                        "nullable": true
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "price_override": {
                        "type": "number",
                        "nullable": true
                    },
                    "unit_group_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "rate_plan_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "arrival": {
                        "type": "string",
                        "format": "date"
                    },
                    "departure": {
                        "type": "string",
                        "format": "date"
                    },
                    "adults": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 10
                    },
                    "children": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 10,
                        "default": 0
                    },
                    "primary_guest_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    }
                }
            },
            "QuoteUpdateInput": {
                "type": "object",
                "properties": {
                    "recipient_name": {
                        "type": "string",
                        "maxLength": 200
                    },
                    "recipient_email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true
                    },
                    "recipient_phone": {
                        "type": "string",
                        "nullable": true
                    },
                    "recipient_address": {
                        "type": "object",
                        "nullable": true
                    },
                    "greeting_text": {
                        "type": "string",
                        "nullable": true
                    },
                    "internal_notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "option_hold_days": {
                        "type": "integer",
                        "enum": [
                            3,
                            7,
                            14
                        ]
                    },
                    "language": {
                        "type": "string",
                        "enum": [
                            "de",
                            "en"
                        ]
                    },
                    "prepayment_amount": {
                        "type": "number",
                        "nullable": true
                    },
                    "prepayment_note": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "QuoteSendInput": {
                "type": "object",
                "required": [
                    "recipient_email"
                ],
                "properties": {
                    "recipient_email": {
                        "type": "string",
                        "format": "email"
                    },
                    "subject": {
                        "type": "string",
                        "maxLength": 255,
                        "nullable": true
                    },
                    "message": {
                        "type": "string",
                        "maxLength": 5000,
                        "nullable": true,
                        "description": "Optionale persoenliche Nachricht im Mail-Body"
                    }
                }
            },
            "PublicQuoteResponse": {
                "type": "object",
                "properties": {
                    "quote": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "quote_number": {
                                "type": "string"
                            },
                            "status": {
                                "type": "string",
                                "enum": [
                                    "draft",
                                    "sent",
                                    "accepted",
                                    "declined",
                                    "expired",
                                    "withdrawn"
                                ]
                            },
                            "is_expired": {
                                "type": "boolean"
                            },
                            "language": {
                                "type": "string",
                                "enum": [
                                    "de",
                                    "en"
                                ]
                            },
                            "recipient_name": {
                                "type": "string"
                            },
                            "greeting_text": {
                                "type": "string",
                                "nullable": true
                            },
                            "option_hold_days": {
                                "type": "integer"
                            },
                            "valid_until": {
                                "type": "string",
                                "format": "date",
                                "nullable": true
                            },
                            "prepayment_amount": {
                                "type": "number",
                                "nullable": true
                            },
                            "prepayment_note": {
                                "type": "string",
                                "nullable": true
                            },
                            "sent_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true
                            },
                            "accepted_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true
                            },
                            "declined_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true
                            },
                            "expired_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true
                            },
                            "withdrawn_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true
                            },
                            "options": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/QuoteOption"
                                }
                            }
                        }
                    },
                    "property": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "format": "uuid"
                            },
                            "name": {
                                "type": "string"
                            },
                            "hero_image_url": {
                                "type": "string",
                                "nullable": true
                            },
                            "description_text": {
                                "type": "string",
                                "nullable": true
                            },
                            "logo_url": {
                                "type": "string",
                                "nullable": true
                            },
                            "brand_accent_color": {
                                "type": "string",
                                "example": "#94A597"
                            },
                            "contact": {
                                "type": "object",
                                "nullable": true
                            },
                            "address": {
                                "type": "object",
                                "nullable": true
                            },
                            "footer_terms_url": {
                                "type": "string",
                                "nullable": true
                            },
                            "footer_privacy_url": {
                                "type": "string",
                                "nullable": true
                            },
                            "footer_revocation_url": {
                                "type": "string",
                                "nullable": true
                            },
                            "footer_imprint_url": {
                                "type": "string",
                                "nullable": true
                            }
                        }
                    }
                }
            },
            "QuoteTemplate": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "property_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "name": {
                        "type": "string",
                        "example": "Hochzeit"
                    },
                    "greeting_text_de": {
                        "type": "string",
                        "nullable": true,
                        "description": "Anschreiben in Deutsch"
                    },
                    "greeting_text_en": {
                        "type": "string",
                        "nullable": true,
                        "description": "Anschreiben in Englisch"
                    },
                    "archived_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "QuoteTemplateInput": {
                "type": "object",
                "required": [
                    "name"
                ],
                "properties": {
                    "property_id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Pflicht beim Anlegen, beim PATCH unveränderlich"
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 120
                    },
                    "greeting_text_de": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 10000
                    },
                    "greeting_text_en": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 10000
                    }
                }
            },
            "App": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "name": {
                        "type": "string"
                    },
                    "revoked": {
                        "type": "boolean"
                    },
                    "is_default": {
                        "type": "boolean"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "linked_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "subscriptions_count": {
                        "type": "integer"
                    },
                    "subscriptions_active": {
                        "type": "integer"
                    },
                    "last_success_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "last_failure_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "consecutive_failures": {
                        "type": "integer"
                    }
                }
            },
            "AppDetail": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/App"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "subscriptions": {
                                "type": "array",
                                "items": {
                                    "$ref": "#/components/schemas/WebhookSubscription"
                                }
                            }
                        }
                    }
                ]
            },
            "WebhookSubscription": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "app_id": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "name": {
                        "type": "string"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "events": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "is_active": {
                        "type": "boolean"
                    },
                    "secret": {
                        "type": "string",
                        "description": "Nur bei Create + RotateSecret in der Antwort.",
                        "nullable": true
                    },
                    "last_success_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "last_failure_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "consecutive_failures": {
                        "type": "integer"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "WebhookDelivery": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Identisch mit X-Bookitly-Delivery-Header. Idempotenz-Schluessel."
                    },
                    "subscription_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "event_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "event_type": {
                        "type": "string"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "pending",
                            "delivered",
                            "failed",
                            "exhausted"
                        ]
                    },
                    "attempt_count": {
                        "type": "integer"
                    },
                    "next_attempt_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "delivered_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "last_response_status": {
                        "type": "integer",
                        "nullable": true
                    },
                    "last_response_body": {
                        "type": "string",
                        "nullable": true,
                        "description": "Auf 4 KB getruncated."
                    },
                    "last_error": {
                        "type": "string",
                        "nullable": true
                    },
                    "payload": {
                        "type": "object",
                        "description": "Vollstaendiger JSON-Body wie an den Empfaenger geschickt — id, event, occurred_at, tenant_slug, data."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            }
        }
    }
}
