# Formatbeschreibung des Salonexports

Fassung vom 8. November 2026 · Schemafassung 2

Diese Seite beschreibt Aufbau und Inhalt des Salonexports von Tagano: Datei, Datentypen, alle Datenbereiche mit ihren Feldern, Verknüpfungen und Grenzen. Sie ist das Online-Register der Datenstrukturen und Datenformate nach Art. 26 Buchst. b der EU-Datenverordnung (Verordnung (EU) 2023/2854). Wie du exportierst und wie ein Anbieterwechsel abläuft, erklärt die Seite „Datenexport und Anbieterwechsel“.

## 1 Datei und Aufbau

- Der Export ist eine einzelne JSON-Datei (RFC 8259) in UTF-8 mit dem Namen `tagano-salon-export.json`. Er ist kein ZIP-Archiv und enthält keine Bilddateien.
- Die Datei enthält ein JSON-Objekt mit 51 Feldern. Alle Felder sind in jedem Export vorhanden, auch wenn sie leer sind: leere Listen als `[]`, leere Einstellungen meist als `{}`, fehlende Werte als `null` oder bei Textfeldern als leerer Text `""`.
- `format` hat den Wert `easybook-salon-export-v2`, `schema_version` den Wert `2`. `exported_at` ist der Erstellungszeitpunkt. `scope` ist ein erläuternder Text zu Umfang und Ausschlüssen, kein Datenbereich.
- Der Export ist eine Momentaufnahme der vorhandenen Daten. Bereits gelöschte Daten werden nicht wiederhergestellt. Er ist keine Datenbanksicherung. Ein gesondertes JSON-Schema und eine Signatur der Gesamtdatei werden nicht mitgeliefert.
- Die Reihenfolge von Feldern und Datensätzen ist nicht festgelegt. Verknüpfe Datensätze über ihre Kennungen, nicht über ihre Position.

| Gruppe | Felder |
| --- | --- |
| Kopf | `format`, `schema_version`, `exported_at`, `scope` |
| Vollständigkeit | `separate_files`, `omitted_records` |
| Salon, Team und Leistungen | `salon`, `accounts`, `employees`, `services`, `service_categories`, `roster`, `opening_hours`, `salon_closures`, `resource_planning`, `notices`, `staff_notifications`, `push_devices` |
| Kunden und Termine | `customers`, `appointment_guests`, `treatment_notes`, `appointment_series`, `appointments`, `history` |
| Nachrichten und Buchungsunterlagen | `booking_mail`, `account_mail`, `booking_legal_records` |
| Verträge und Abrechnung | `billing_agreements`, `plan_agreements`, `trial_offer`, `agreements`, `registration_agreements`, `contract_acceptances`, `governance_notices`, `subprocessor_releases`, `subprocessor_changes`, `price_campaigns`, `price_changes`, `provider_terminations`, `customer_contract_ends`, `provider_switch_cases` |
| Datenschutz und Löschung | `appointment_retention`, `additional_retention`, `deletion_evidence`, `privacy_actions`, `requests`, `salon_holds`, `inactivity_schedules`, `inactivity_reminders`, `salon_deletion_cases`, `deletion_confirmations` |

## 2 Abruf und Übergabe

- Den Export erstellt der Betreiber des Salons nach erneuter Eingabe seines Passworts. Im Browser: Einstellungen → Datenschutz → Datenrückgabe und Vertragsende → Vollständigen Salonexport herunterladen. In der App: Datenschutz verwalten → Daten und Nachweise exportieren → Alle Salondaten → JSON-Datei speichern. Teammitglieder haben keinen Zugriff auf den Gesamtexport.
- Der Export ist auch nach Ende von Test oder Abo verfügbar, solange der Salon besteht.
- Einen eigenen Zugang für den neuen Anbieter gibt es nicht, also keine Schnittstelle, keinen Download-Link und keine automatische Übertragung zwischen Anbietern. Der Betreiber übergibt die Datei auf einem mit dem neuen Anbieter abgestimmten, geschützten Weg. Tagano-Passwörter oder Zugangsdaten muss er dafür nicht weitergeben. Unterstützung beim Wechsel stimmst du mit uns über <kontakt@tagano.de> ab.
- Auskünfte zu einzelnen Kunden, Mitarbeitern oder Gästen haben einen anderen Umfang und eigene Formate. Diese Seite beschreibt nur den Salonexport.

## 3 Grenzen des Exports

**Gesondert übergebene Dateien.** Gespeicherte Mitarbeiterbilder sind nicht in der Datei enthalten. Der Export nennt sie in `separate_files` und wird trotzdem vollständig erstellt.

**Ausgelassene Datensätze.** Datensätze, die sich nicht eindeutig deinem Salon zuordnen lassen, gibt der Export nicht aus. Er nennt sie mit Kennung und Grund in `omitted_records`. Die gespeicherten Originaldaten bleiben dabei unverändert. Frei eingegebene Texte kann der Export nicht darauf prüfen, welche Personen darin erwähnt sind.

**Nicht enthalten sind:**

- Passwörter und Passwort-Hashes, Anmelde-, Sitzungs- und Push-Token sowie verwendbare Schlüssel zur Buchungsverwaltung oder zum Widerruf
- Zahlungs- und Checkout-Links, vollständige Karten- oder PayPal-Daten, Ereignisarchive und interne Parameter des Zahlungsanbieters sowie vollständige Rechnungsakten
- Vergleichswerte zur Erkennung mehrfacher Tests
- anbieterweite Administrator- und Analyseberechtigungen von Tagano, vollständige Einladungs- und Sitzungsverläufe, Geräte-Token und persönliche Vorschau-Einstellungen
- Wartungsankündigungen, Reichweitenzahlen von Tagano sowie Betriebs- und Sicherheitsprotokolle
- Support- und Kontaktvorgänge, externe Postfächer und Rechnungen
- bereits gelöschte Daten, auch bereinigte E-Mail-Kopien und Hinweise; Löschnachweise sind keine Kopien der gelöschten Daten. Noch gespeicherte E-Mail-Daten sind bis zu ihrer Bereinigung enthalten, auch wenn ihre Frist schon abgelaufen ist
- Daten anderer Salons, der Quellcode von Tagano, Datenbanksicherungen und vertrauliche Konfiguration

Gespeicherte Bilder, Supportunterlagen und Rechnungen übergeben wir auf Anfrage gesondert. Schreib dazu an <kontakt@tagano.de>; Umfang und geschützten Übergabeweg stimmen wir im Einzelfall ab. Einzelne Vertrags-, Registrierungs- und Löschweisungsnachweise kannst du außerdem im Betreiberkonto herunterladen.

## 4 Datentypen, Zeiten und Einheiten

| Typ | Darstellung |
| --- | --- |
| Text | JSON-Zeichenkette |
| Ganzzahl | JSON-Zahl ohne Nachkommastellen |
| Wahrheitswert | `true` oder `false` |
| Datum | Text im Format `YYYY-MM-DD` |
| Zeitstempel | Text nach ISO 8601 (RFC 3339) mit Zeitzonenangabe, z. B. `2026-11-06T12:34:56.123Z` |
| UUID | Text nach RFC 9562 mit Bindestrichen |
| Prüfsumme | Text; kennzeichnet einen gespeicherten Dokumentstand und verschlüsselt keine Daten |
| Objekt | JSON-Objekt |
| Liste | JSON-Array |

- Zeitstempel werden nicht in Ortszeit umgerechnet. In gespeicherten Schnappschüssen behalten sie ihre ursprüngliche Genauigkeit und Schreibweise.
- Termine: `date`, `hour` und `minute` geben Tag und Uhrzeit in der Ortszeit Europe/Berlin (IANA-Zeitzonendatenbank) an, ohne Zeitzonenangabe. Beachte bei der Übernahme Sommer- und Winterzeit. Der Kundenbesuch endet nach `duration_minutes`; Vor- und Nachbereitung können darüber hinausgehen.
- Öffnungszeiten und Dienstplan: Uhrzeiten als Text `HHMM`, z. B. `0900`; ältere Werte auch `HH:MM`. Uhrzeiten reichen von 00:00 bis 23:59. Leere Dienstplanzeiten sind möglich und können auf Wochenplan oder Öffnungszeiten verweisen.
- Dauern, Phasen und Einwirkzeiten stehen in Minuten, `cancellation_hours`, `rescheduling_hours` und `reminder_hours` in Stunden, Lösch-, Aufbewahrungs- und Testfristen in Tagen.
- Preise und Aufschläge sind Ganzzahlen in Cent. Beträge mit eigenem Währungsfeld stehen in der kleinsten Einheit dieser Währung; der Währungscode folgt ISO 4217 in Kleinbuchstaben, z. B. `eur`.
- `Stundenlohn` und `Monatslohn` sind historische Ganzzahlen ohne festgelegte Einheit. Interpretiere sie nicht als Cent.
- Mengen und Mischverhältnisse in Rezepturen sind freie Texte.

Gespeicherte Dokumente und Schnappschüsse werden in ihrer historischen Struktur ausgegeben. Ältere Fassungen können Felder auslassen oder zusätzliche enthalten. Ein fehlendes Feld bedeutet nicht `null`. Verwirf unbekannte Felder beim Import nicht stillschweigend.

## 5 Kennungen und Verknüpfungen

Kennungen sind die dauerhaften Kennungen aus Tagano. Sie werden für den Export nicht neu vergeben. Sie gelten im Zusammenhang mit dem jeweiligen Datenbereich, nicht als allgemeine Kennungen für andere Systeme.

| Feld | verweist auf |
| --- | --- |
| `salon.owner_account_id`, `employees.user_id`, `history.actor_user_id`, `staff_notifications.recipient_id`, `push_devices.session__user_id` | `accounts.id` |
| `appointments.KundenID_id`, `appointment_guests.customer_id`, `treatment_notes.customer_id`, `booking_mail.customer_id` | `customers.KundenID` |
| `appointments.mitarbeiterID_id`, `appointments.planning_employee_ids`, `roster.mitarbeiterID_id`, `staff_notifications.employee_id` | `employees.ID` |
| `appointments.service_ids`, `employees.excluded_service_ids` | `services.LeistungID` |
| Schlüssel in `services.employee_price_adjustments` | `employees.ID`, nach Umwandlung des Texts in eine Ganzzahl |
| `services.category_id` | `service_categories.id` |
| `appointments.series_id` | `appointment_series.id` |
| `appointment_guests.appointment_id`, `treatment_notes.appointment_id`, `history.appointment_id`, `booking_mail.appointment_id`, `staff_notifications.appointment_id` | `appointments.TerminID` |
| `treatment_notes.guest_id` | `appointment_guests.id` |
| `booking_legal_records.appointment_id` und `customer_id`, `requests.customer_id` und `employee_id` | Termine, Kunden bzw. Mitarbeiter |
| `subprocessor_changes.release_id` | `subprocessor_releases.id` |
| `notice_id` in `subprocessor_changes`, `inactivity_reminders`, `price_changes` und `provider_terminations` | `governance_notices.id` |
| `inactivity_reminders.schedule_id` | `inactivity_schedules.id` |
| `price_changes.campaign_id` | `price_campaigns.id` |
| `customer_contract_ends.source_reference` | je nach `kind`: `price_changes.id`, `subprocessor_changes.id` oder `provider_switch_cases.reference` |
| `provider_switch_cases.workflow.contract_end_reference` | `customer_contract_ends.id` |
| `deletion_confirmations.closure_id` | `salon_deletion_cases.id` |

- Historische Verweise, etwa auf gelöschte Leistungen, Kategorien oder Konten, können ohne Gegenstück sein. Verknüpfe sie nicht mit einem anderen aktuellen Datensatz.
- Schnappschüsse enthalten bewusst die Namen, Preise und Zuordnungen des damaligen Zeitpunkts.
- Auf ausgelassene Datensätze kann noch verwiesen werden. Werte `omitted_records` deshalb vor der Übernahme aus.
- `contract_acceptances.release_id` bezeichnet die angenommene Vertragsfassung; ihr Inhalt steht vollständig im Annahmedokument.

## 6 Datenbereiche und Felder

„oder null“ bedeutet, dass das Feld den Wert `null` haben kann. Felder, deren Aufbau Abschnitt 7 beschreibt, sind mit „siehe 7“ gekennzeichnet.

### `separate_files` – gesondert herauszugebende Dateien (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `kind` | Text | derzeit `employee_image` |
| `employee_id` | Ganzzahl | Mitarbeiter |
| `status` | Text | fester Hinweis „gesondert herauszugeben“ |
| `requires_separate_secure_return` | Wahrheitswert | `true`: Übergabe auf gesondertem, geschütztem Weg |

Bilddaten, Dateinamen, Speicherpfade und Download-Schlüssel werden nicht ausgegeben.

### `omitted_records` – ausgelassene Datensätze (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `area` | Text | betroffener Bereich, z. B. `appointments`, `history` oder `treatment_notes`; außerdem `employee_account_links` (Kontoverknüpfung eines Mitarbeiters), `employee_service_exclusions` (Leistungsausschluss), `employee_weekly_schedules` (Wochenplan) und `customer_contract_end_evidence` (Nachweis eines Vertragsendes) |
| `id` | Text | Kennung des eigenen Datensatzes; `configuration` für die Ressourcenkonfiguration |
| `reason` | Text | `needs_review` (zur Prüfung markiert), `unclear_relation` (Zuordnung oder übergeordneter Datensatz unklar), `foreign_or_unsafe_embedded_reference` (fremder oder unsicherer Verweis in gespeicherten Zusatzdaten), `foreign_account_relation` (fremde Kontoverknüpfung) oder `foreign_service_relation` (fremder Leistungsbezug) |
| `status` | Text | fester Hinweis „zur manuellen Zuordnungsprüfung ausgelassen“ |

Ein Datensatz kann mit mehreren Gründen mehrfach erscheinen. Fehlt ein ungeklärter Termin, fehlen auch seine Gäste, sein Verlauf, seine Termin-E-Mails und Buchungsunterlagen. Bei einer unsicheren Mitarbeiterbeziehung bleibt der Mitarbeiter erhalten: `user_id` wird `null`, fremde Leistungsausschlüsse fehlen, ein unsicherer Wochenplan erscheint als `[]`. Eine Ressourcenkonfiguration mit fremden Verweisen erscheint als `{}`. Ist bei einem Vertragsende ein Nachweis unsicher, fehlt dieser Nachweis; bei `basis` fehlt dann das ganze Objekt. Der Vorgang und die übrigen Nachweise bleiben. Gehört der auslösende Vorgang zu einem anderen Salon, fehlt der ganze Vertragsende-Datensatz. Jede solche Auslassung steht in `omitted_records`. Eine leere Liste heißt, dass die Zuordnungsprüfung nichts ausgelassen hat. Sie heißt nicht, dass gesondert übergebene oder ausgeschlossene Daten in der Datei enthalten sind.

### `salon` – Salon und Buchungseinstellungen (Objekt)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `owner_account_id` | Ganzzahl oder null | Betreiberkonto |
| `customerCompanyName` | Text | Firmen- bzw. Salonname |
| `customerFirstName` | Text | Vorname der vertretenden Person |
| `customerLastName` | Text | Nachname der vertretenden Person |
| `customerEmail` | Text | E-Mail-Adresse des Betreibers, zugleich Salonkennung |
| `customerGender` | Text | Anrede bzw. Geschlecht der vertretenden Person |
| `public_phone` | Text | öffentliche Telefonnummer |
| `address_line` | Text | Straße und Hausnummer |
| `postal_code` | Text | Postleitzahl mit führenden Nullen |
| `city` | Text | Ort |
| `federal_state` | Text | Code des Bundeslands |
| `holiday_region` | Text | Code der Feiertagsregion |
| `embed_origins` | Text | erlaubte Websites für die eingebettete Buchung, als Text |
| `booking_legal_name` | Text | rechtlicher Name des Salons für Buchungsunterlagen |
| `booking_imprint_text` | Text | Impressum des Salons |
| `booking_payment_text` | Text | Zahlungs- und Buchungsbedingungen des Salons |
| `booking_accessibility_text` | Text | Barrierefreiheitstext des Salons |
| `booking_legal_version` | Text | Version dieser Buchungstexte |
| `booking_legal_reviewed_at` | Zeitstempel oder null | bestätigte Prüfung dieser Texte |
| `privacy_policy_url` | Text | Adresse der Datenschutzhinweise des Salons |
| `privacy_notice_text` | Text | Datenschutzhinweis des Salons |
| `privacy_notice_version` | Text | Version dieses Hinweises |
| `online_booking_enabled` | Wahrheitswert | Onlinebuchung eingeschaltet |
| `customer_cancellation_enabled` | Wahrheitswert | Stornierung durch Kunden erlaubt |
| `customer_rescheduling_enabled` | Wahrheitswert | Verschiebung durch Kunden erlaubt |
| `cancellation_hours` | Ganzzahl | Vorlauf für Stornierungen in Stunden |
| `rescheduling_hours` | Ganzzahl | Vorlauf für Verschiebungen in Stunden |
| `reminder_enabled` | Wahrheitswert | Terminerinnerungen eingeschaltet |
| `reminder_hours` | Ganzzahl | Vorlauf der Erinnerung in Stunden |
| `android_push_preview_allowed` | Wahrheitswert | Detailvorschau in Android-Pushnachrichten erlaubt, standardmäßig `false` |

### `accounts` – Konten von Betreiber und Team (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kontokennung |
| `email` | Text | Anmelde-E-Mail-Adresse |
| `salon_role` | Text | `owner` (Betreiber) oder `employee` (Teammitglied) |
| `is_active` | Wahrheitswert | Konto aktiv |
| `date_joined` | Zeitstempel | Kontoanlage |
| `email_verification_required` | Wahrheitswert | E-Mail-Bestätigung vor dem Zugang erforderlich |
| `email_verified_at` | Zeitstempel oder null | E-Mail-Bestätigung |

Ob ein Zugang nutzbar ist, ergibt sich aus `is_active`, der E-Mail-Bestätigung und bei Teammitgliedern aus `employees.active` und `processing_restricted_at`. Eine archivierte oder gesperrte Zuordnung ist keine Zugangsfreigabe.

### `employees` – Mitarbeiter, auch archivierte (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `ID` | Ganzzahl | Mitarbeiterkennung |
| `user_id` | Ganzzahl oder null | Konto |
| `Personalnummer` | Ganzzahl | Personalnummer |
| `Vorname` | Text | Vorname |
| `Nachname` | Text | Nachname |
| `Geschlecht` | Text | Geschlecht |
| `Beschreibung` | Text | Beschreibung |
| `Email` | Text | E-Mail-Adresse |
| `Telefon` | Text | Telefonnummer |
| `Stundenlohn` | Ganzzahl | historisches Lohnfeld ohne festgelegte Einheit |
| `Monatslohn` | Ganzzahl | historisches Lohnfeld ohne festgelegte Einheit |
| `Geburtsdatum` | Datum oder null | Geburtsdatum |
| `Farbe` | Text | Kalenderfarbe, meist als Hex-Farbcode |
| `active` | Wahrheitswert | für die Planung aktiv |
| `archived_at` | Zeitstempel oder null | Archivierung |
| `deletion_hold` | Wahrheitswert | Löschsperre gesetzt |
| `processing_restricted_at` | Zeitstempel oder null | Beginn einer Verarbeitungseinschränkung |
| `weekly_schedule` | Liste | Wochenpläne, siehe 7 |
| `excluded_service_ids` | Liste von Ganzzahlen | Leistungen, die die Person nicht ausführt |

### `services` – Leistungen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `LeistungID` | Ganzzahl | Leistungskennung |
| `name` | Text | Name |
| `preis` | Ganzzahl | aktueller Grundpreis in Cent |
| `dauer` | Ganzzahl | Grunddauer in Minuten |
| `active` | Wahrheitswert | Leistung aktiv |
| `category_id` | Ganzzahl oder null | Kategorie |
| `processing_minutes` | Ganzzahl | Einwirkzeit in Minuten |
| `finish_minutes` | Ganzzahl | Abschlusszeit in Minuten |
| `workflow` | Objekt | Ablauf in Schritten, siehe 7 |
| `guest_count` | Ganzzahl | behandelte Personen, meist 1 oder 2 |
| `employee_price_adjustments` | Objekt | Aufpreise je Mitarbeiter, siehe 7 |

### `service_categories` – Leistungskategorien (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kategoriekennung |
| `name` | Text | Name |
| `position` | Ganzzahl | Sortierposition |

### `roster` – Dienstplaneinträge (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `dienstID` | Ganzzahl | Kennung |
| `dienstDate` | Datum | Tag |
| `dienstStart` | Text | Beginn, siehe Abschnitt 4 |
| `dienstEnd` | Text | Ende, siehe Abschnitt 4 |
| `anwesend` | Wahrheitswert | anwesend |
| `urlaub` | Wahrheitswert | abwesend, ohne Angabe eines Grundes |
| `mitarbeiterID_id` | Ganzzahl | Mitarbeiter |
| `deletion_hold` | Wahrheitswert | Löschsperre gesetzt |

### `opening_hours` – Öffnungszeiten und Ausnahmen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `weekday` | Ganzzahl | 0 = Montag bis 6 = Sonntag |
| `open` | Text | Öffnung, siehe Abschnitt 4 |
| `close` | Text | Schließung, siehe Abschnitt 4 |
| `closed` | Wahrheitswert | geschlossen |
| `ExceptionDate` | Datum oder null | Ausnahmetag; `null` für die Wochenregel |

### `salon_closures` – Schließzeiten (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `first_day` | Datum | erster Schließtag, einschließlich |
| `last_day` | Datum | letzter Schließtag, einschließlich |

### `resource_planning` – Räume, Plätze und Geräte (Objekt)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `revision` | Ganzzahl | Stand der Einstellungen |
| `configuration` | Objekt | Konfiguration, siehe 7 |

### `notices` – Salonhinweise (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `Alert` | Wahrheitswert | Anzeigekennzeichen |
| `AlertHeader` | Text | Überschrift |
| `AlertBody` | Text | Hinweistext |
| `date_added` | Zeitstempel | Anlage |

### `staff_notifications` – Hinweise an Team und Betreiber (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `recipient_id` | Ganzzahl | Empfängerkonto |
| `employee_id` | Ganzzahl oder null | Mitarbeiter |
| `appointment_id` | Ganzzahl oder null | Termin |
| `kind` | Text | Art des Hinweises |
| `dates` | Liste von Texten | betroffene Tage, gegebenenfalls leer |
| `created_at` | Zeitstempel | Erstellung |
| `read_at` | Zeitstempel oder null | gelesen |

### `push_devices` – registrierte Geräte (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `session__user_id` | Ganzzahl | Konto; der doppelte Unterstrich gehört zum Feldnamen |
| `platform` | Text | Plattform |
| `updated_at` | Zeitstempel | letzte Aktualisierung |

### `customers` – Kundenkartei (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `KundenID` | Ganzzahl | Kundenkennung |
| `FirstName` | Text | Vorname |
| `LastName` | Text | Nachname |
| `Email` | Text | E-Mail-Adresse |
| `Gender` | Text | Anrede bzw. Geschlecht |
| `City` | Text | Ort |
| `Mobiltelefon` | Text | Mobilnummer |
| `Festnetz` | Text | Festnetznummer |
| `privacy_touched_at` | Zeitstempel | letzte für die Aufbewahrung maßgebliche Aktivität |
| `deletion_hold` | Wahrheitswert | Löschsperre gesetzt |
| `processing_restricted_at` | Zeitstempel oder null | Beginn einer Verarbeitungseinschränkung |
| `online_booking_blocked` | Wahrheitswert | Onlinebuchung für diesen Kunden gesperrt |

### `appointment_guests` – weitere Gäste eines Termins (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Gastkennung |
| `appointment_id` | Ganzzahl | Termin |
| `customer_id` | Ganzzahl oder null | Kunde; `null` ohne Kundenkartei |
| `name` | Text | Name |
| `email` | Text | E-Mail-Adresse |
| `phone` | Text | Telefonnummer |
| `processing_restricted_at` | Zeitstempel oder null | Beginn einer Verarbeitungseinschränkung |

### `treatment_notes` – Notizen und Rezepturen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Notizkennung |
| `kind` | Text | `note` oder `recipe` |
| `text` | Text | Notiztext, gegebenenfalls leer |
| `recipe` | Objekt | Rezeptur, bei Notizen `{}`; siehe 7 |
| `created_at` | Zeitstempel | Anlage |
| `treatment_date` | Datum oder null | Behandlungstag |
| `appointment_id` | Ganzzahl oder null | Termin; bei Gastnotizen der Termin des Gastes |
| `is_general_hint` | Wahrheitswert | allgemeiner Hinweis ohne Behandlungstag |
| `customer_id` | Ganzzahl oder null | Kunde |
| `guest_id` | Ganzzahl oder null | Gast |

Eine Notiz gehört genau einem Kunden oder einem Gast. Ist der Termin gelöscht, kann `appointment_id` `null` sein.

### `appointment_series` – Terminserien (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | UUID | Serienkennung |
| `start_date` | Datum | Beginn |
| `interval_weeks` | Ganzzahl | Abstand in Wochen |
| `occurrence_count` | Ganzzahl | vorgesehene Anzahl Termine |

Die vorhandenen Einzeltermine stehen in `appointments`. Gelöschte Termine werden nicht rekonstruiert.

### `appointments` – Termine, auch stornierte und abgeschlossene (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `TerminID` | Ganzzahl | Terminkennung |
| `date` | Datum | Termintag in Ortszeit |
| `hour` | Ganzzahl | Startstunde 0 bis 23 in Ortszeit |
| `minute` | Ganzzahl | Startminute 0 bis 59 |
| `KundenID_id` | Ganzzahl | Hauptkunde |
| `mitarbeiterID_id` | Ganzzahl | federführender Mitarbeiter |
| `duration_minutes` | Ganzzahl | Besuchsdauer in Minuten |
| `total_price_cents` | Ganzzahl | Gesamtpreis in Cent |
| `service_snapshot` | Liste | Leistungen zum Buchungszeitpunkt, siehe 7 |
| `phase_snapshot` | Liste | Ablaufphasen, siehe 7 |
| `planning_snapshot` | Objekt | Personal- und Ressourcenplanung, siehe 7 |
| `seat_id` | Text | Platzkennung, leer ohne Platz |
| `seat_name` | Text | Platzname zum Buchungszeitpunkt |
| `booking_gender` | Text | bei der Buchung gewählte Zielgruppe |
| `second_guest_erased` | Wahrheitswert | Gastdaten wurden gelöscht |
| `needs_review` | Wahrheitswert | ungeklärte Zuordnung; ausgegebene Termine haben `false` |
| `status` | Text | `booked`, `cancelled`, `completed` oder `no_show` |
| `revision` | Ganzzahl | Änderungsstand |
| `changed_at` | Zeitstempel | letzte Änderung |
| `cancelled_at` | Zeitstempel oder null | Stornierung |
| `cancellation_reason` | Text | Stornierungsgrund, gegebenenfalls leer |
| `deletion_hold` | Text | Löschsperre: leer, `tax`, `dispute` oder `request`; hier ein Text, kein Wahrheitswert |
| `service_ids` | Liste von Ganzzahlen | verknüpfte Leistungen |
| `planning_employee_ids` | Liste von Ganzzahlen | weitere eingeplante Mitarbeiter |
| `series_id` | UUID oder null | Terminserie |
| `series_index` | Ganzzahl oder null | Position in der Serie, ab 0 |
| `series_baseline_revision` | Ganzzahl oder null | Ausgangsstand zur Erkennung einzelner Änderungen |
| `series_exception` | Wahrheitswert | Serientermin wurde einzeln geändert |

### `history` – Änderungsverlauf der Termine (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `appointment_id` | Ganzzahl | Termin |
| `revision` | Ganzzahl | Änderungsstand |
| `action` | Text | Art des Ereignisses; keine abschließende Werteliste |
| `actor` | Text | handelnde Rolle, z. B. `owner`, `customer` oder `system` |
| `actor_user_id` | Ganzzahl oder null | handelndes Konto |
| `created_at` | Zeitstempel | Zeitpunkt |
| `before` | Objekt | Zustand vorher, bei Neuanlage gegebenenfalls `{}`; siehe 7 |
| `after` | Objekt | Zustand nachher, siehe 7 |

### `booking_mail` – Termin-E-Mails (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `appointment_id` | Ganzzahl | Termin |
| `kind` | Text | `confirmation`, `changed`, `cancelled`, `reminder` oder `released` |
| `revision` | Ganzzahl | Terminstand der Nachricht |
| `customer_id` | Ganzzahl oder null | empfangender Kunde |
| `recipient` | Text | Empfängeradresse |
| `snapshot` | Objekt | Termininhalt der Nachricht, keine fertige E-Mail; siehe 7 |
| `created_at` | Zeitstempel | Erstellung |
| `expires_at` | Zeitstempel | Ablauf |
| `sent_at` | Zeitstempel oder null | Versand; kein Nachweis, dass die Nachricht gelesen wurde |
| `discarded_at` | Zeitstempel oder null | verworfen |
| `attempts` | Ganzzahl | Versandversuche |
| `last_error` | Text | Fehlercode, gegebenenfalls leer |

### `account_mail` – Konto-E-Mails (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `kind` | Text | Art, z. B. `verify`, `reset`, `invite`, `trial` oder `notice` |
| `recipient` | Text | Empfängeradresse |
| `created_at` | Zeitstempel | Erstellung |
| `sent_at` | Zeitstempel oder null | Versand |
| `discarded_at` | Zeitstempel oder null | verworfen |

### `booking_legal_records` – Buchungsunterlagen und Widerrufe (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `appointment_id` | Ganzzahl oder null | Termin |
| `customer_id` | Ganzzahl oder null | Kunde |
| `kind` | Text | `contract` (Buchungsunterlagen) oder `withdrawal` (Widerruf) |
| `recipient` | Text | Empfängeradresse |
| `document` | Text | vollständiger Dokumenttext |
| `created_at` | Zeitstempel | Erstellung |
| `resolved_at` | Zeitstempel oder null | Erledigung |
| `sent_at` | Zeitstempel oder null | Versand |
| `discarded_at` | Zeitstempel oder null | verworfen |

### `billing_agreements` – Tarif- und Bestellvereinbarungen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `reference` | UUID | Vorgangsreferenz |
| `kind` | Text | Art der Vereinbarung |
| `account_identity` | Objekt | `email`, `company`, `first_name` und `last_name` (Texte) bei der Annahme |
| `document` | Text | Vereinbarungstext |
| `version` | Text | Version |
| `accepted_at` | Zeitstempel | Annahme |

### `plan_agreements` – angenommene Tarifbestellungen und -wechsel (Objekt)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `existing_offer_preserved` | Wahrheitswert | früheres Team-Angebot erhalten |
| `checkouts` | Liste | Tarifbestellungen |
| `changes` | Liste | Tarifwechsel |

Einträge in `checkouts`:

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `plan_code` | Text | Tarif |
| `plan_terms_version` | Text | Version der Tarifbedingungen |
| `plan_terms_text` | Text | angenommener Tariftext |
| `plan_terms_accepted_at` | Zeitstempel | Annahme |
| `first_charge_at` | Zeitstempel oder null | erste Fälligkeit |
| `state` | Text | Bestellstand; kein Zahlungsnachweis |

Einträge in `changes`:

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `target_code` | Text | Zieltarif |
| `amount_due` | Ganzzahl | fälliger Betrag in der kleinsten Währungseinheit |
| `currency` | Text | Währung, z. B. `eur` |
| `terms_version` | Text | Version der Wechselbedingungen |
| `terms_text` | Text | angenommener Wechseltext |
| `accepted_at` | Zeitstempel | Annahme |
| `state` | Text | Wechselstand |

### `trial_offer` – kostenloser Test (Objekt)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `consumed_at` | Zeitstempel oder null | Test verbraucht |
| `local_start` | Zeitstempel oder null | Beginn des Tests ohne Zahlungsdaten |
| `local_end` | Zeitstempel oder null | zugesagtes Testende |
| `local_terms_version` | Text oder null | Version der Testbedingungen |
| `evidence` | Liste | Zeitnachweise mit `created_at` (Zeitstempel), `consumed_at` (Zeitstempel oder null) und `retain_until` (Zeitstempel, Aufbewahrungsende) |
| `acceptances` | Liste | Testannahmen aus Bestellungen mit `trial_days` (Ganzzahl, Testdauer in Tagen), `trial_terms_version` (Text) und `trial_terms_accepted_at` (Zeitstempel oder null) |

### `agreements` – AV-Vertragsannahmen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `version` | Text | Vertragsversion |
| `digest` | Prüfsumme | SHA-256 des Vertragsdokuments |
| `document` | Objekt | Vertragsdokument, siehe 7 |
| `accepted_at` | Zeitstempel | Annahme |
| `invalidated_at` | Zeitstempel oder null | Ablösung |

### `registration_agreements` – Registrierungsnachweise (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `account_identity` | Objekt | `email`, `company`, `first_name` und `last_name` (Texte) bei der Registrierung |
| `document` | Objekt | Registrierungsdokument, siehe 7 |
| `document_digest` | Prüfsumme | SHA-256 des Dokuments |
| `accepted_at` | Zeitstempel | Annahme |
| `test_mode` | Wahrheitswert | lokale Testannahme, nicht der kostenlose Test eines Salons |

### `contract_acceptances` – Annahmen neuer Vertragsfassungen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `release_id` | Ganzzahl | angenommene Fassung |
| `actor_id` | Ganzzahl oder null | annehmendes Konto |
| `document` | Objekt | angenommener Stand, siehe 7 |
| `digest` | Prüfsumme | Prüfsumme des angenommenen Stands |
| `accepted_at` | Zeitstempel | Annahme |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende |

### `governance_notices` – Ankündigungen von Tagano (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `category` | Text | z. B. `price`, `subprocessors`, `termination` oder `inactivity` |
| `reference` | Text | Vorgangsreferenz |
| `recipient` | Text | Empfänger |
| `subject` | Text | Betreff |
| `body` | Text | Nachrichtentext |
| `digest` | Prüfsumme | Prüfsumme des Inhalts |
| `created_at` | Zeitstempel | Anlage |
| `sent_at` | Zeitstempel oder null | Versand; `null` ist kein Versandnachweis |
| `cancelled_at` | Zeitstempel oder null | Aufhebung |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende |

### `subprocessor_releases` – Dienstleisterlisten (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `version` | Text | Version |
| `providers` | Liste | Dienstleister mit `name`, `address`, `purpose`, `data`, `countries` und `transfer_basis` (Texte) |
| `digest` | Prüfsumme | Prüfsumme der Liste |
| `starts_at` | Zeitstempel | vorgesehener Beginn |
| `created_at` | Zeitstempel | Anlage |
| `announced_at` | Zeitstempel oder null | Ankündigung |
| `activated_at` | Zeitstempel oder null | Aktivierung |

Enthalten sind nur Fassungen, auf die ein Vorgang deines Salons verweist.

### `subprocessor_changes` – Dienstleisteränderungen für deinen Salon (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `release_id` | Ganzzahl | Dienstleisterliste |
| `notice_id` | Ganzzahl | Ankündigung |
| `authorization` | Text | `notice` (Information) oder `explicit` (ausdrückliche Genehmigung) |
| `approved_at` | Zeitstempel oder null | Genehmigung |
| `objected_at` | Zeitstempel oder null | Widerspruch |
| `objection_channel` | Text | Weg des Widerspruchs, z. B. `account` oder `email`; sonst leer |
| `objection_reference` | Text | Nachweisreferenz |
| `objection` | Text | Widerspruchstext |
| `actor_id` | Ganzzahl oder null | Betreiberkonto |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende |

### `price_campaigns` – Preisänderungen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | UUID | Kennung |
| `plan_code` | Text | Tarif |
| `old_amount` | Ganzzahl | bisheriger Betrag in der kleinsten Währungseinheit |
| `new_amount` | Ganzzahl | neuer Betrag in derselben Einheit |
| `currency` | Text | Währung, z. B. `eur` |
| `effective_at` | Zeitstempel | Wirksamkeit |
| `kind` | Text | Art, regulär `price` |
| `state` | Text | Bearbeitungsstand |
| `created_at` | Zeitstempel | Anlage |

Enthalten sind nur Preisänderungen, die deinen Salon betreffen.

### `price_changes` – Umsetzung einer Preisänderung für deinen Salon (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | UUID | Kennung |
| `campaign_id` | UUID | Preisänderung |
| `notice_id` | Ganzzahl oder null | Ankündigung |
| `effective_period_start` | Zeitstempel oder null | erster betroffener Abrechnungszeitraum |
| `state` | Text | Bearbeitungsstand |
| `checked_at` | Zeitstempel oder null | letzte Prüfung |
| `last_error` | Text | Prüf- oder Fehlercode |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende |

### `provider_terminations` – Kündigungen durch Tagano (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | UUID | Kennung |
| `end_at` | Zeitstempel | Vertragsende |
| `notice_id` | Ganzzahl oder null | Kündigungsnachricht |
| `created_at` | Zeitstempel | Anlage |
| `reason` | Text | Anlass |
| `state` | Text | Bearbeitungsstand |
| `checked_at` | Zeitstempel oder null | letzte Prüfung |
| `last_error` | Text | Prüf- oder Fehlercode |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende |

### `customer_contract_ends` – Kündigungen des Salons zu einem besonderen Termin (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | UUID | Kennung |
| `kind` | Text | Anlass: `price`, `subprocessor` oder `switch` |
| `source_reference` | Text | auslösender Vorgang, siehe Abschnitt 5 |
| `request_reference` | Text | Nachweis des Kundenauftrags |
| `received_at` | Zeitstempel | Eingang des Auftrags |
| `end_at` | Zeitstempel | Vertragsende |
| `created_at` | Zeitstempel | Anlage |
| `state` | Text | z. B. `draft`, `applying`, `scheduled`, `manual_review` oder `completed` |
| `checked_at` | Zeitstempel oder null | letzte Prüfung |
| `last_error` | Text | Prüf- oder Fehlercode |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende |
| `evidence` | Objekt | Nachweise zum Vertragsende, siehe 7 |

### `provider_switch_cases` – Anbieterwechsel (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `reference` | UUID | Vorgangsreferenz |
| `started_at` | Zeitstempel | Beginn |
| `completed_at` | Zeitstempel oder null | Abschluss |
| `retrieval_until` | Zeitstempel oder null | Ende der Abrufphase |
| `workflow` | Objekt | Fristen, Übergabe und Verlauf, siehe 7 |

### `appointment_retention` – automatische Terminlöschung (Liste mit höchstens einem Eintrag)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `enabled` | Wahrheitswert | eingeschaltet |
| `days` | Ganzzahl | Aufbewahrung in Tagen nach dem Termin |
| `revision` | Ganzzahl | Stand der Weisung |
| `accepted_at` | Zeitstempel oder null | Annahme |
| `terms_version` | Text | Version der Löschbedingungen |
| `terms_digest` | Prüfsumme | SHA-256 dieser Bedingungen |
| `effective_at` | Zeitstempel oder null | wirksam ab |
| `last_run_at` | Zeitstempel oder null | letzter Lauf |
| `last_deleted_count` | Ganzzahl | beim letzten Lauf gelöschte Termine |

### `additional_retention` – weitere Löschfristen (Liste mit höchstens einem Eintrag)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `enabled` | Wahrheitswert | eingeschaltet |
| `customer_days` | Ganzzahl | Frist für inaktive Kunden in Tagen; 0 = aus |
| `roster_days` | Ganzzahl | Frist für vergangene Dienstplaneinträge in Tagen; 0 = aus |
| `staff_days` | Ganzzahl | Frist nach Archivierung von Mitarbeitern in Tagen; 0 = aus |
| `revision` | Ganzzahl | Stand der Weisung |
| `digest` | Prüfsumme | SHA-256 des angenommenen Stands |
| `accepted_at` | Zeitstempel oder null | Annahme |
| `effective_at` | Zeitstempel oder null | wirksam ab |
| `last_run_at` | Zeitstempel oder null | letzter Lauf |
| `last_result` | Objekt | `{}` oder `customers`, `roster` und `staff` mit der Anzahl gelöschter Datensätze |

### `deletion_evidence` – Lösch-, Sperr- und Datenschutznachweise (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `action` | Text | Art des Vorgangs |
| `created_at` | Zeitstempel | Zeitpunkt |
| `details` | Objekt | Einzelheiten je Vorgangsart, siehe 7 |
| `appointment_count` | Ganzzahl | betroffene Termine |

Der Nachweis über den gerade erstellten Export erscheint erst im nächsten Export.

### `privacy_actions` – Auskünfte und Löschungen zu Kunden (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `action` | Text | `export` oder `delete` |
| `customer_reference` | Ganzzahl | Kundenkennung, gegebenenfalls eines gelöschten Kunden |
| `appointment_count` | Ganzzahl | betroffene Termine |
| `created_at` | Zeitstempel | Zeitpunkt |

### `requests` – Anfragen betroffener Personen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `reference` | UUID | Referenz |
| `customer_id` | Ganzzahl oder null | Kunde |
| `employee_id` | Ganzzahl oder null | Mitarbeiter |
| `kind` | Text | `access`, `erase`, `rectify`, `restrict`, `objection` oder `portability` |
| `received_at` | Zeitstempel | Eingang |
| `due_at` | Zeitstempel | Frist |
| `identity_verified_at` | Zeitstempel oder null | Identität geprüft |
| `closed_at` | Zeitstempel oder null | Abschluss |
| `outcome` | Text | Ergebnis, z. B. `fulfilled`, `partly_fulfilled`, `refused` oder `withdrawn`; leer, solange offen |

### `salon_holds` – salonweite Sperren (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `kind` | Text | `deletion` (Löschsperre) oder `processing` (Verarbeitungssperre) |
| `reference` | UUID | Vorgangsreferenz |
| `created_at` | Zeitstempel | Beginn |
| `released_at` | Zeitstempel oder null | Aufhebung; `null`, solange die Sperre besteht |

### `inactivity_schedules` – vorgemerkte Löschung bei Inaktivität (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `accepted_at` | Zeitstempel oder null | maßgebliche Vertragsannahme |
| `cycle` | UUID | Berechnungsrunde |
| `anchor_at` | Zeitstempel oder null | Beginn der Frist |
| `anchor_kind` | Text | Art des Fristbeginns, z. B. Ende des Tests oder des Abos |
| `last_paid_period_end` | Zeitstempel oder null | Ende des letzten bezahlten Zeitraums |
| `cancellation_confirmed_at` | Zeitstempel oder null | bestätigtes Vertragsende |
| `due_at` | Zeitstempel oder null | geplanter Löschtermin |
| `state` | Text | `waiting`, `scheduled`, `cancelled`, `manual_review` oder `completed` |
| `review_reasons` | Liste von Texten | Prüfgründe |
| `reviewed_at` | Zeitstempel oder null | manuelle Prüfung |
| `completed_at` | Zeitstempel oder null | Löschung abgeschlossen |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende des Nachweises |
| `updated_at` | Zeitstempel | letzte Bearbeitung |

### `inactivity_reminders` – Erinnerungen vor der Löschung (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `schedule_id` | Ganzzahl | Vormerkung |
| `cycle` | UUID | Berechnungsrunde, gegebenenfalls eine frühere |
| `days_before` | Ganzzahl | Vorlauf in Tagen, regulär 30 oder 7 |
| `notice_id` | Ganzzahl oder null | Nachricht |
| `target_at` | Zeitstempel | vorgesehener Zeitpunkt |

### `salon_deletion_cases` – Salonlöschung (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `state` | Text | Bearbeitungsstand |
| `requested_at` | Zeitstempel | Löschauftrag |
| `execute_after` | Zeitstempel | frühester Ausführungszeitpunkt |
| `completed_at` | Zeitstempel oder null | Löschung ausgeführt |
| `blocked_reason` | Text | Hinderungsgrund |
| `provider_record` | Objekt | Abschlussnachweis, siehe 7 |
| `retain_until` | Zeitstempel oder null | Aufbewahrungsende |

Nach vollständiger Löschung gibt es keinen Salonexport mehr. Abgeschlossene Löschvorgänge erscheinen deshalb normalerweise nicht.

### `deletion_confirmations` – Löschbestätigungen (Liste)

| Feld | Typ | Bedeutung |
| --- | --- | --- |
| `id` | Ganzzahl | Kennung |
| `reference` | UUID | Referenz |
| `closure_id` | Ganzzahl oder null | Löschvorgang |
| `recipient` | Text | Empfänger |
| `subject` | Text | Betreff |
| `body` | Text | Text der Bestätigung |
| `digest` | Prüfsumme | Prüfsumme des Inhalts |
| `remaining` | Liste | Restbestände, siehe 7 |
| `deleted_at` | Zeitstempel | Löschung |
| `created_at` | Zeitstempel | Anlage |
| `retain_until` | Zeitstempel | Aufbewahrungsende |
| `sent_at` | Zeitstempel oder null | Versand |
| `delivery_reference` | Text | Versandreferenz |
| `delivery_state` | Text | `pending`, `sent` oder `manual_review` |

Eine Bestätigung entsteht erst nach der Löschung. Im Export eines bestehenden Salons ist die Liste normalerweise leer; nach der Löschung erhältst du die Bestätigung per E-Mail.

## 7 Verschachtelte Strukturen

### `employees.weekly_schedule`

Liste von Wochenplänen mit `from` (Datum, Beginn der Gültigkeit) und `days` (Liste mit sieben Tagen, Index 0 = Montag bis 6 = Sonntag). Jeder Tag hat `present` (Wahrheitswert) sowie `start` und `end` (Text `HHMM` oder leer). Es gilt der jüngste Plan mit `from` am oder vor dem jeweiligen Datum. Die Liste kann leer sein. Spätere Änderungen der Öffnungszeiten ändern gespeicherte Wochenpläne nicht.

### `services.employee_price_adjustments`

Objekt mit der Mitarbeiterkennung als Text-Schlüssel und dem Aufpreis in Cent als Ganzzahl ab 0. Fehlt ein Mitarbeiter, gilt kein Aufpreis. Ältere Daten können Aufpreise von 0 und frühere Mitarbeiter enthalten.

### `services.workflow`

`{}` bei einfachen oder älteren Leistungen. Sonst: `version` (Ganzzahl, 1), `kind` (`simple` oder `multi`) und `steps` (Liste). Ein Schritt enthält:

- `name` (Text) und `kind`: `treatment` (Behandlung), `processing` (Einwirkzeit) oder `buffer` (Puffer)
- `minutes` (Ganzzahl, 1 bis 1.440)
- `staff`: `same` (die federführende Person), `any` (jede geeignete und verfügbare Person, auch die federführende) oder `none` (kein Personal)
- `employee_ids` (Liste von Ganzzahlen; leer = keine Eingrenzung)
- `resources` (Liste von Anforderungen mit `ids`, einer Liste alternativer Ressourcenkennungen, und `quantity`, der Anzahl auszuwählender Ressourcen)
- `customer_present` (Wahrheitswert; `false` = Vor- oder Nachbereitung außerhalb der Besuchsdauer)
- optional `staff_count` (gleichzeitig benötigte Personen; fehlt das Feld, gilt 0 bei `none`, sonst 1) und `source_service_id` (kopierte Ursprungsleistung, gegebenenfalls gelöscht)

### `treatment_notes.recipe`

`product`, `shade`, `amount`, `developer` und `mixing_ratio` (Texte, gegebenenfalls leer) sowie `processing_minutes` (Ganzzahl oder null). Ältere Rezepturen können weniger Felder enthalten. Werte eine fehlende Angabe nicht als 0.

### `appointments.service_snapshot`

Liste der Leistungen zum Buchungszeitpunkt mit `id`, `name`, `duration` (Minuten), `category_id` (Ganzzahl oder null), `guest_count`, `base_price_cents`, `surcharge_cents` (Mitarbeiteraufschlag) und `price_cents`. Ältere Einträge enthalten nur `id`, `name`, `duration`, `price_cents` und gegebenenfalls `category_id`. Es gelten die gespeicherten Preise, nicht der heutige Katalogpreis.

### `appointments.phase_snapshot`

Liste der Ablaufphasen, bei älteren Terminen gegebenenfalls leer. `start` und `end` sind Minuten ab Terminbeginn; das Ende zählt nicht mit.

- Standardform: `kind` (`treatment`, `processing` oder `finish`), `start`, `end`, `service_id` und `name`. Während `processing` ist die Person frei, Kunde und Platz bleiben belegt.
- Flexible Form, erkennbar an `workflow: true`: die Felder eines Ablaufschritts aus `services.workflow` sowie `start`, `end`, `service_id` und `service_name`. `start` kann bei Vorbereitung negativ sein, `end` nach dem Besuchsende liegen. `kind` ist `treatment`, `processing` oder `buffer`, in älteren Daten auch `finish`.

Verwende die gespeicherten Phasen und ersetze sie nicht durch den heutigen Ablauf der Leistung.

### `appointments.planning_snapshot`

`{}` bei älteren Standardterminen. Sonst: `version` (1), `staff`, `resources`, `seat_id`, `seat_name` und `phases` (Kopie der Phasen).

- `staff`: `employee_id`, `start`, `end` (Minuten ab Terminbeginn), `step` (Phasenindex ab 0) und `name` (damaliger Name). Mehrere Einträge je Phase sind möglich.
- `resources`: `resource_id` (Text), `start`, `end`, `units` (derzeit 1), `step` und `name`. `step` = `-1` bedeutet Belegung über den gesamten Ablauf einschließlich Puffer. Räume sind ebenfalls Ressourcen.

### `resource_planning.configuration`

`{}` ist möglich. Sonst: `enabled` und `women_area` (Wahrheitswerte), `seats` (Liste) sowie optional `resources` (Liste) und `service_order` (Liste von Leistungskennungen, auch nicht mehr vorhandener).

- Platz: `id` und `name` (Texte), `zone` (`general` oder `women`), `service_ids`, `category_ids` und `employee_ids` (Listen von Ganzzahlen), optional `room_id`. Erlaubt ist eine Leistung, wenn sie selbst oder ihre Kategorie genannt ist; sind beide Listen leer, gilt keine Beschränkung. Eine leere `employee_ids`-Liste bedeutet keine Beschränkung.
- Ressource: `id` und `name` (Texte), `kind` (`room`, `place` oder `device`), `room_id` (bei Räumen leer, sonst der zugehörige Raum), `capacity` (Räume 1 bis 100, sonst 1), `active` (Wahrheitswert) und `zone`.

Platz- und Ressourcenkennungen sind dauerhafte Texte.

### `history.before`, `history.after` und `booking_mail.snapshot`

Historischer Terminzustand mit `date` (Datum), `time` (Text `HH:MM`, Ortszeit), `status`, `cancellation_reason`, `customer_id` und `employee_id` (Ganzzahl oder null), `employee` (damaliger Name), `employee_ids`, `services` (wie `service_snapshot`), `duration` (Minuten), `price_cents`, `phases` (wie `phase_snapshot`), `planning` (wie `planning_snapshot`), `seat_id`, `seat_name` und `booking_gender`.

Nach Löschungen oder Einschränkungen können diese Angaben verkürzt sein: `employee_id` kann `null` sein, Listen können verkürzt sein, Namen können durch einen neutralen Ersatztext ersetzt sein. In `planning.staff` kann zusätzlich `employee_name` stehen. Werte solche Einträge nicht als aktuelle Zuordnung. Betroffene E-Mail-Kopien können ganz fehlen.

### `agreements.document`

Historischer AV-Vertrag mit `version`, `salon` (`company`, `representative`, `email`, `address`, `postal_code`, `city`), `provider` (`provider_name`, `provider_business_name`, `provider_address`, `privacy_contact`; in Testständen `{}`), `contract` (Vertragstext), `tom` (technische und organisatorische Maßnahmen), `subprocessors` (Liste mit `name`, `address`, `purpose`, `data`, `countries`, `transfer_basis`; bei Zeilen aus der Vertragsanlage zusätzlich `source_cells` mit den fünf ursprünglichen Tabellenzellen), `backup_retention_days` (Ganzzahl) und `acceptance` (Annahmeerklärung). Einzelne ältere Fassungen enthalten zusätzlich `release_scope` und `private_notice`. Nach Annahme einer neuen Fassung kommen `annex2` und `full_text` hinzu; `full_text` ist der vollständige AV-Vertrag mit beiden Anlagen.

### `registration_agreements.document`

`test_mode` (Wahrheitswert), `provider` (wie oben), `terms` und `privacy` (jeweils `version`, `text`, `digest`), `acceptance`, `business_declaration` und `privacy_notice` (Texte), bei einzelnen älteren Fassungen `release_scope` und `private_notice`. Registrierungen nach Veröffentlichung einer neuen Vertragsfassung enthalten zusätzlich `avv` (`version`, `contract`, `tom`, `annex2`, `full_text`, `subprocessors`), `release_id`, `release_digest` und `source_documents`. `source_documents` enthält die Schlüssel `imprint`, `privacy`, `terms`, `avv`, `switching` und `accessibility`, jeweils mit `filename`, `version`, `text` (vollständiger Originaltext) und `sha256`. Ältere Nachweise werden nicht nachträglich geändert.

### `contract_acceptances.document`

`release` (Version), `release_digest`, `terms` (`version`, `text`), `avv` (`version`, `contract`, `tom`, `annex2`, `full_text`, `subprocessors`, `salon`, `provider`, `backup_retention_days`, `acceptance`; Unterformen wie bei `agreements.document`) und `capabilities` (Liste der angenommenen Vertragsmerkmale). Neuere Annahmen enthalten zusätzlich `source_documents` wie oben.

### `deletion_evidence.details`

Inhalt je nach `action`:

- `instruction`: `enabled`, `days`, `effective_at`, `preview_count`, `document`, `digest` und `acknowledgements` (Liste der bestätigten Erklärungen). `document` enthält `version`, `paragraphs` (Liste von Texten), `acknowledgements` (`authority`, `reviewed`, `instructed`), `avv_url`, `avv_version` und je nach Fassung `provider_release_digest`, `provider`, `release_scope` und `private_notice`.
- `automatic`: `days`, `appointment_ids`; `manual`: `appointment_ids`; `customer_erasure`: `customer_id`, `appointment_ids`
- `hold_changed`: `appointment_id`, `before` und `after` (Sperrgründe als Text)
- `data_instruction`: `version`, `terms`, `periods` (`customer_days`, `roster_days`, `staff_days`), `enabled`, `digest`, `revision`, `counts` (`customers`, `roster`, `staff`); `data_cleanup`: `counts`, `revision`
- `data_hold`: `model` (`customer`, `employee` oder `roster`), `id`, `hold`
- `processing_restriction`: `model`, `id`, `reference`, `restricted`, `informed_before_lift`, `recipients_reviewed`
- `closure_requested`: `execute_after`, `returned_or_waived`
- `guest_export` und `guest_erasure`: `guest_id`; `guest_restriction`: `guest_id`, `enabled`
- `notice_published`: `version`, `digest`; `notice_link_updated`: `digest`
- `inactivity_expired`: `due_at`, `accepted_at`, `anchor_kind`, `cycle`
- `paused`, `data_paused`, `closure_cancelled` und `salon_export`: `{}`

Historische Texte in diesen Nachweisen dürfen beim Import nicht durch heutige Fassungen ersetzt werden.

### `provider_switch_cases.workflow`

`{}` bei älteren Vormerkungen. Sonst:

- `version` (1; unabhängig von `schema_version`) und `kind`: `provider` (Wechsel zu einem anderen Anbieter), `own_system` (eigene Systeme) oder `delete` (nur Löschung)
- `request_reference`, `owner_id` (Betreiberkonto), `received_at` (Eingang) und `accepted_at` (zugrunde liegende Vertragsannahme)
- `notice_end` (Ende der Ankündigungsfrist), `transition_deadline` (geltende Übergangsfrist), `exception_notice_due` (Frist für eine Begründung, falls der Wechsel technisch nicht möglich ist) und `maximum_alternative_end` (späteste alternative Frist)
- `extension_used` (Wahrheitswert: Verlängerung auf Kundenwunsch genutzt)
- `fees`: Liste vereinbarter Wechselentgelte mit `amount_cents`, `direct_cost_cents`, `service_at`, `agreed_at` (oder null) und `agreement_reference`; keine Rechnung
- `events`: Bearbeitungsverlauf mit `at`, `actor`, `action` (`request`, `exception`, `extension`, `fee`, `handover` oder `completed`) und `details`
- je nach Verlauf `exception` (`reason`, `sent_at`, `notice_reference`, `alternate_end`), `extension` (`until`, `customer_reference`, `reason`), `handover` (`sent_at`, `delivery_reference`, `verification_reference`), `contract_end_reference`, `contract_end_at` und `actual_completion_at` (Abschluss des Wechsels, Beginn der Abrufphase)

In `events` enthält `details` bei `request` den Wert `customer_confirmed`, bei `completed` `end_reference` und `retrieval_until`, sonst das jeweilige Objekt. Übertragene Dateien sind nicht eingebettet.

### `customer_contract_ends.evidence`

`{}`, solange kein Nachweis vorliegt. Sonst je nach Vorgang: `basis` (`source`, `notice_id`, `sent_at`, `objected_at`, `request_reference`, `kind`, `owner_id`), `settlement_reference` und `final_settlement_reference` (geprüfte Abrechnung), `actual_subscription_end` (tatsächliches Aboende beim Zahlungsanbieter), `late_end_acknowledged` und `late_end_resolution_reference` (verspätetes Aboende geprüft und ausgeglichen) sowie `no_subscription` (kein bezahltes Abo). Referenzen sind Kennungen; die zugrunde liegenden Unterlagen sind nicht eingebettet.

### `salon_deletion_cases.provider_record`

Häufig `{}`. Bei Löschung wegen Inaktivität `trigger` (`inactivity`) und `inactivity_cycle`. Bei Löschung nach einem Anbieterwechsel `trigger` (`provider_switch`), `switch_reference`, `request_reference`, `return_reference`, `operator` und `switch_workflow` (wie `provider_switch_cases.workflow`). Der Abschlussnachweis kann `company`, `owner_email`, `stripe_customer_id`, `stripe_subscription_id`, `subscription_status` und `purpose` enthalten. Das sind Belegreferenzen, keine Zugangsschlüssel.

### `deletion_confirmations.remaining`

Liste der Restbestände mit `category` (`backups`, `contract_and_deletion_evidence`, `invoices`, je nach Fall auch `recovery_journal`, `trial_comparison` oder `confirmation_mail_queue`), `presence` (`retained` = bei uns vorhanden, `conditional_external` = möglicherweise bei einem externen Dienst), `description`, `reason`, `duration` (Frist in Worten) und `until` (Zeitstempel oder null). `null` bedeutet, dass sich kein konkreter Termin bestimmen lässt, nicht unbegrenzte Aufbewahrung.

## 8 Versionierung

Ändert sich der Aufbau des Exports, erhöhen wir `schema_version` und aktualisieren diese Seite. Schemafassung 2 ergänzt gegenüber Fassung 1 die Bereiche `separate_files` und `omitted_records`, Salonrollen, Leistungsausschlüsse, Terminserien und weitere eingeplante Mitarbeiter, Vertragsannahmen und Ankündigungen sowie Dienstleister-, Preis-, Kündigungs-, Inaktivitäts-, Wechsel- und Löschvorgänge und salonweite Sperren.
