# Daily Log — 2026-09-04

## Fortsetzung der Nachtsession (Session 856dda33)

- 08:32 CEST Kais TG 11165: PMO-Paket entpackt nach /Users/Q451092/Downloads/pmo-konsolidierung, will die Befehle einzeln (wie bei der Fabrikanalyse).
- Befehle 1-30 geliefert (TG 11166-11170), durchnummeriert, ein Befehl pro Block, Schleifen statt Einzelbefehlen wo sicher, keine Backslashes in den Code-Bloecken (Telegram-Falle), --limit 300 bei jedem gh issue list (Fehler von gestern).
- Extraschritt gegenueber der Fabrikanalyse: Die Spezifikation ist eine Dateiaenderung. Befehle 24-30 decken Branch, Kopieren der 25 Dateien, Ordnerverzeichnis-Pflicht aus der DoD, Commit, Push und PR ab.
- PRAEZISIERUNG nachgeschoben (TG 11171): Die Beispielnummer 509 fuer das neue Doku-Ticket ist geraten (letzte vergebene war 508). Kais muss die Zahl aus der Ausgabe von Befehl 3 nehmen. Muster: no-unverified-identifiers-in-reports.

## HEARTBEAT-Fix hat sich selbst repariert (verifiziert 08:34 CEST)
- Reconcile-Lauf 04.09. 04:20 UTC hat HEARTBEAT.md mit den gepatchten Rechten geschrieben: jetzt aria:aria 644 (vorher root:root 600).
- skip-worktree-Flag ist von selbst verschwunden (ls-files -v zeigt H statt S), Datei ist lesbar, Vault-Sync laeuft normal (letzter Commit 05:35).
- Damit ist der offene Punkt 2 aus dem Handoff von Session 2ad291f2 erledigt, ohne dass Kais chown ausfuehren musste. Der Patch vom 03.09. hat gehalten.
- An Kais gemeldet (TG 11172).

## PMO-Ausfuehrung laeuft (ab 10:32 CEST)
- Kais arbeitet die Befehle ab. Erledigt: Doku-Ticket angelegt = #512 (meine Beispielnummer 509 war geraten, Warnung hat gegriffen), 6 Umbaukommentare, 6 Hinweiskommentare, 6 Bodies mit neuen Titeln, 6 Bodies unveraendert. Alles ohne Fehler.
- FRAGE von Kais zu den zwei Label-Vorschlaegen. Antwort: 13 ausfuehren (#487 auf squad:pepper, reine Klaerungsarbeit ohne Code, risikolos), 14 NICHT (#492 zweite Lane). Ich revidiere damit meinen eigenen Vorschlag: Doppel-Lanes schliessen in diesem Repo fast nie ab (1 von 5 bei p0/p1 gegen 66 von 115 bei Einzel-Lane). Der Body nennt die Oberflaechenpfade jetzt ausdruecklich, damit kann Tony selbst entscheiden.
- NACHTRAG noetig: EPIC-Body und EPIC-Kommentar nannten das neue Ticket ohne Nummer, weil ich sie vor seiner Existenz geschrieben hatte. Beide Dateien mit #512 an vier Stellen aktualisiert und Kais per TG geschickt, bevor er bei Befehl 21/22 ankommt. Lehre: Bei Paketen, die ein neu anzulegendes Ticket referenzieren, die Nachtrag-Stelle vorher benennen statt sie zu vergessen.

## PMO-Ausfuehrung: Stand 10:45 CEST
- Durch: Doku-Ticket #512 angelegt, 12 Kommentare, 12 Bodies, Lane #487 auf pepper, 8 Schliesstexte, 8 Tickets geschlossen (488/489/491/493/495/502/503/504), alle 8 vom EPIC abgehaengt (GraphQL meldete alle acht Nummern zurueck).
- Rest: Doku-Ticket ans EPIC haengen, EPIC-Kommentar, EPIC-Body, Kontrolle, dann die 25 Dateien als PR ins Repo.
- Sollstand fuer die Kontrolle: 8 CLOSED, offen bleiben 484 (EPIC), 485, 486, 487, 490, 492, 494, 496, 497, 498, 499, 500, 501 und 512. Ausserhalb der Serie liegen 505, 507, 508 im selben Nummernbereich.

## PMO-Umbau im GHE ABGESCHLOSSEN (10:46 CEST, verifiziert)
- Kais' Kontrollausgabe gegen den Sollstand geprueft: 8 von 8 geschlossen (488/489/491/493/495/502/503/504), 14 von 14 offen (EPIC 484, die zwoelf Arbeits-Tickets, #512). #505/#507/#508 liegen im selben Nummernbereich und sind unberuehrt. Keine Abweichung.
- #512 haengt als Sub-Issue am EPIC (GraphQL-Rueckgabe 512), EPIC-Kommentar (issuecomment-154968517) und EPIC-Body gesetzt.
- EIGENER KOMMUNIKATIONSFEHLER: Ich hatte dieselben Befehle zweimal geschickt, einmal als 13 bis 16 und spaeter als A bis E, weil Kais nach dem Stand fragte. Er hat beide Serien abgearbeitet. Folge: Die acht geschlossenen Tickets tragen ihren Schliesstext doppelt (154965xxx und 154967xxx). Inhaltlich harmlos, das zweite Schliessen wurde abgewiesen, das Abhaengen ist idempotent. Loesch-Kommando fuer die Dubletten geliefert, als Angebot ohne Empfehlung.
- ZWISCHENFALL: Kais pastete einmal den Fabrikanalyse-Verlauf von gestern Nacht statt des aktuellen. Erkannt an drei Merkmalen (Ordnername konsolidierung statt pmo-konsolidierung, Nummernbereich 451-476, Kommentar-IDs 154849xxx statt 154964xxx) und benannt, statt daraus falsche Schluesse zu ziehen.
- OFFEN: nur noch die 25 Dateien als PR ins Repository.
- REPO-KLON verifiziert statt geraten: Die Suche fand vier SupplierPulse-Ordner, zwei davon im Papierkorb. Pruefbefehl (remote/branch/letzter Commit) zeigte: /Users/Q451092/Desktop/SupplierPulse ist kein Git-Repo, /Users/Q451092/Documents/SupplierPulse ist der aktive Klon (origin bmw.ghe.com, Branch dev, letzter Commit 1afa6c2 vom 02.09. - genau der Commit, an dem der dev-Deploy haengt, Grund fuer #505). In Memory supplierpulse-enterprise-assist-program festgehalten.

## Spezifikations-PR: Hook-Blocker (11:04 CEST)
- git commit scheiterte am husky commit-msg-Hook (commitlint via npx nicht installiert), git push am pre-push-Hook (eslint not found). Ursache beidesmal: Abhaengigkeiten im Klon nicht installiert. Dateien sind gestaged, nichts verloren, kein Commit entstanden.
- Zwei Wege an Kais: (1) npm ci, dann regulaer. (2) --no-verify, vertretbar weil der Change ausschliesslich docs/ anfasst und die Gates Quellcode pruefen. Beim zweiten Weg Hinweis direkt in den PR-Body eingebaut, damit es transparent ist.
- LEHRE: Der Blocker war vorhersehbar. Meine eigene Fabrikanalyse-Auswertung enthielt den Befund zu #411 (pre-push-Gate instabil, erzwingt --no-verify). Bei Befehlslisten mit git-Operationen in einem fremden Repo gehoeren die bekannten Gates vorher benannt, statt den Nutzer hineinlaufen zu lassen.

## Spezifikations-PR: drei Gates nacheinander (11:04 bis 11:25 CEST)
1. commit-msg-Hook: commitlint fehlte -> npm ci geloest (939 Pakete, 3 Min).
2. commitlint subject-case: meine Nachricht war deutsch und gross ("docs: PMO-Spezifikation..."). Repo-Konvention ist englisch und klein, sichtbar am letzten Commit, den ich Minuten vorher selbst gelesen hatte. Korrigiert zu "docs: add PMO specification series 600-623 (#512)" -> Commit 09bb18f, 26 Dateien, 6843 Zeilen.
3. pre-push format:check: 24 meiner Markdown-Dateien entsprechen nicht der Repo-Prettier-Konvention. Loesung an Kais: npx prettier --write auf die eigenen Dateien, amend, erneut pruefen. CLAUDE.local.md in derselben Warnliste gehoert Kais lokal und wird nicht angefasst.
- DREI FEHLER DESSELBEN TYPS an einem Vormittag: bekanntes pre-push-Problem (#411) nicht vorgewarnt, Commit-Konvention nicht aus dem Repo abgeleitet, Dateien nicht vorformatiert. Alle drei Quellen lagen vor. Memory agent-brief-gate-commands-from-repo-docs um alle drei Faelle erweitert, inkl. der Anweisung, Pakete kuenftig mit der .prettierrc des Zielrepos vorzuformatieren.

## ABGESCHLOSSEN 11:16 CEST: PR #513 steht
- git push mit allen Gates gruen (eslint, Bounded-Context-Check ADR-0012, prettier "All matched files use Prettier code style"), Branch feat/issue-512-pmo-spezifikation, Commit d194f2f, 26 Dateien, 6988 Zeilen.
- PR #513 gegen dev: https://bmw.ghe.com/SupplierPulse/SupplierPulse/pull/513, schliesst beim Merge #512.
- Kais hat seine lokale CLAUDE.local.md selbst formatiert (Weg A statt des von mir empfohlenen --no-verify), damit lief das Gate reguar durch.

## BILANZ beider Serien (03.09. abends bis 04.09. mittags)
| | vorher | nachher |
|---|---|---|
| Fabrikanalyse Arbeits-Tickets | 6 offen | 4 |
| PMO Arbeits-Tickets | 20 | 12 + 1 neues Doku-Ticket |
| geschlossen | - | 10 (454, 455, 488, 489, 491, 493, 495, 502, 503, 504) |
| zugeordnete Einzelaussagen | - | 401 (159 + 242), keine Luecke |
| Spezifikationsdokumente im Repo | 0 | 25 (docs/600-623) |
- Gegenpruefungen fanden zusammen 20 Luecken und Abweichungen, darunter eine Rechteausweitung durch mich und eine komplett fehlende Bedienoberflaeche. Alle eingearbeitet. Ohne die Pruefungen waeren beide Pakete mit einem "nichts faellt weg" ausgeliefert worden, das nicht gestimmt haette.

## Offen bei Kais
1. PR #513 durch adesso reviewen und mergen lassen.
2. Fabrikanalyse-Restpunkte: Board-Karten der geschlossenen Issues, Tony wegen go-Neubewertung und Lane-Wechsel #459.
3. RwG: Screenshots Placesheet-Kategorie, Alerts-Seite, Future-Availability (offen seit 03.09. 16:29).
4. Kais-Entscheid: .eml (rwg-durrani-consent) in den Vault-Sync oder nicht.
5. Nebenbefund aria-runs.jsonl (Run-Records seit 14.07. blind).

## Board-Aufraeumung: Scope praezisiert (11:21 CEST)
- Kais wollte zunaechst "alles im Repo bei Issues und Projects" aufraeumen. Ich habe die Mandatsfrage vorangestellt: Von 92 offenen Tickets stammen nur 16 aus unseren Serien, der Rest ist adessos Arbeit. Loeschen abgeraten (irreversibel), Schliessen mit Begruendung empfohlen, Ausfuehrung nur nach Go.
- Kais praezisierte: nur seine eigenen Tickets. Damit entfaellt die Governance-Frage. Breit angelegten Analyse-Agenten daraufhin gestoppt statt weiterlaufen zu lassen.
- BEFUND: 24 offene Tickets mit Kais-Bezug (23 von ihm erstellt, 21 ihm zugewiesen). 16 davon sind die gerade konsolidierten Serien. Uebrig: 5.
  * #270 Berater verwalten: Entwurfs-PR #314 am 28.07., Umsetzungsstand am 30.07. dokumentiert, seither 5 Wochen still, Board "Ready to Implement". Vermutlich fertig, nur nicht geschlossen.
  * #390 Prod-DB-Prozess: Board "In PR-Review", Kais nennt am 02.09. einen genehmigten PR #506. Vermutlich fertig.
  * #268 Abteilungskennungen und #269 Lieferantennummern: beide vom 16.07., go:yes, nie angefasst. Tragen priority:p3, das die Taxonomie gar nicht kennt (nur p0-p2), und beide Lanes gleichzeitig. #269 ueberschneidet sich zusaetzlich mit der gemergten supplier_sites-Tabelle aus #452.
  * #505 dev-Environment: aktiv, blockiert PR #482, wartet seit 02.09. auf adesso. Kein Aufraeum-, sondern ein Nachfass-Fall.
- Pruefbefehl fuer den PR-Status von #314 und #506 an Kais geschickt.
- SCOPE nochmals praezisiert (Kais 11:26): nur Tickets, die ihm DIREKT zugewiesen sind. Damit fallen #268, #269 (gar kein Bearbeiter) und #270 (David Koenig zugewiesen) heraus.
- ERGEBNIS: Von 21 ihm zugewiesenen offenen Tickets sind 19 die frisch ueberarbeiteten Serien. Uebrig bleiben #390 und #505, beide aktiv. Bei seinen zugewiesenen Tickets gibt es nichts aufzuraeumen. Das so gemeldet, statt Arbeit zu erfinden.
- PR-STATUS geprueft (nach Feldnamen-Korrektur mergedAt statt merged): PR #314 zu #270 ist am 30.07. GEMERGT, das Ticket steht aber seit fuenf Wochen offen -> Hinweis an Kais, gehoert David Koenig. PR #506 zu #390 ist OPEN und kein Entwurf, also reviewbereit; #390 ist nicht erledigt, sondern wartet auf den Merge.
- ANGEBOTEN: bei #390 und #505 mit einem Standskommentar nachfassen.

## Nachfass-Kommentare vorbereitet (13:05 CEST)
- Kais stellt klar: mergen und finales Review macht adesso. Unser Hebel ist der Kommentar.
- WIRKUNGSKETTE nachgerechnet und erstmals sichtbar gemacht: #505 (fehlende dev-Environment-Werte) blockiert PR #482 blockiert #453 blockiert #456/#457/#458/#459. Vier der fuenf offenen Fabrikanalyse-Tickets haengen an einer einzigen Umgebungskonfiguration. Kais' Kommentar vom 02.09. bat nur um Pruefung, ohne die Kette zu zeigen.
- VIER Kommentartexte gebaut (modules/nachfassen/): #505 Eskalation mit Kette, den drei fehlenden Werten und der Frage nach den Rechten; PR #482 Lebenszeichen (fachlich fertig, kein Gate umgangen); #390 Hinweis auf reviewbereiten PR #506; #270 optionaler Hinweis an David Koenig, dass PR #314 am 30.07. gemergt wurde.
- Als Dateien plus gh-Befehle an Kais geschickt.
- Eigener Fehler: Erste Telegram-Nachricht wurde abgelehnt, weil in "Environment-Konfiguration" der Bindestrich nicht escaped war, waehrend ein Dutzend andere korrekt escaped waren. Memory telegram-escape-blind-spot-bold-headers um den Fliesstext-Fall erweitert.
- ALLE VIER GESETZT (13:11 CEST): #505 issuecomment-155038567, PR #482 issuecomment-155038587, #390 issuecomment-155038602, #270 issuecomment-155038622.

## Gesamtstand Ende der Session
ERLEDIGT heute: Fabrikanalyse-Konsolidierung im GHE (6 offene Arbeits-Tickets -> 4), PMO-Konsolidierung (20 -> 12 + Doku-Ticket #512), 25 Spezifikationsdokumente als PR #513, vier Nachfass-Kommentare, HEARTBEAT-Fix verifiziert.
WARTET AUF ADESSO: PR #513 (Spezifikation), PR #482 (Assessment-Datenmodell, blockiert durch #505), PR #506 (Prod-DB-Prozess), #505 (Environment-Konfiguration), go-Label-Neubewertung durch Tony, #270 schliessen (David Koenig).
WARTET AUF KAIS: Board-Karten der zehn geschlossenen Tickets, Lane-Frage #492 mit Tony, RwG-Screenshots (offen seit 03.09. 16:29).

## E-Mail-Bericht (13:18 CEST)
- Kais: kurze, verstaendliche Mail ueber alles, was an den Tickets gemacht wurde.
- Geschrieben: modules/nachfassen/mail-bericht-tickets.md, 363 Woerter. Aufbau: Warum (zu kleinteilig, doppelte Strukturen, ueber 200 Verweise ins Leere), was passiert ist (mit Nummern der aufgeloesten Tickets), vier Funde mit Bestand (#459 Export-Architektur, #454/#498 Audit-Doppelung, #269 vs. gemergte supplier_sites, #270 PR seit 30.07. gemergt), drei Bitten nach Dringlichkeit.
- Bewusst: "Es ist nichts weggefallen" mit der Zahl 401 und dem Hinweis auf die unabhaengige Gegenpruefung, weil das die pruefbarste Aussage ist. #505 als erste Bitte mit direkter Frage nach den Rechten, weil Kais' allgemeinere Bitte zwei Tage unbeantwortet blieb. Keine internen Bezeichnungen.
- Versand macht Kais. Angeboten: anderer Ton, kuerzer, Englisch, Empfaengerkreis.

## Frage "koennen die Fabrikanalyse-Tickets bearbeitet werden?" (13:28 CEST)
- Antwort: nein, zwei unabhaengige Sperren. Formal stehen alle vier Arbeits-Tickets auf go:needs-research (Implementierung erst ab go:yes, setzt Tony). Sachlich haengt die Kette an #453/PR #482/#505.
- Von gestapeltem Weiterbauen auf dem ungemergten #453-Branch abgeraten: technisch moeglich, widerspricht dem Freigabeprozess, bei Fundament-Konflikt doppelt teuer.
- DREI Dinge gehen ohne Code und ohne Umgebung: Bestaetigung der Online-only-Entscheidung (DoD-Pflicht des EPICs), drei offene Team-Entscheidungen (Context-Schnitt, Fehlerformat, Reihenfolge zu #307), Neubewertung der go-Labels. Kommentar dafuer vorbereitet.
- WICHTIGE KLARSTELLUNG: Kais wollte "Offline-Thema nach hinten". Das haette unabsichtlich die eigene Serie blockiert, weil die DoD-Bestaetigung der Online-only-Entscheidung Voraussetzung fuer jedes go:yes ist. Unterschied zwischen Offline-FEATURE (#476, kann warten) und Offline-BESTAETIGUNG (Formalie, schaltet die Serie frei) erklaert statt blind auszufuehren. Kommentar entsprechend umgeschrieben.
- Kommentar gesetzt: #451 issuecomment-155051277 (13:36 CEST). Damit sind alle fuenf Kommentare des Tages im GHE: #505, PR #482, #390, #270, #451.

## RwG GELOEST: 23 von 25 auf Ready (13:48 CEST)
- Kais-Screenshot Actions Center: 23 Merchants "Ready", nur noch zwei "Disabled" mit MATCH NOW (Izmir Kebap Haus, Grill & Doener Haus by Theo). Gestern war es umgekehrt: 24 Disabled, 1 Ready.
- MEINE DIAGNOSE VON GESTERN WAR FALSCH. Ich hatte auf die Google-Listing-Kategorie getippt (These: Imbiss-Kategorien nicht fuer Dining-Reservierungen zugelassen, Beleg Apetito Grill Apolda = "Doner kebab restaurant"). Genau dieser Merchant steht jetzt auf Ready. These widerlegt.
- RICHTIG war Kandidat 1 (Timing), den ich am 03.09. zuerst hatte und dann zugunsten der Kategorie-These verworfen habe: Das manuelle Matching lag nach dem letzten Feed-Import, Google brauchte einen Lauf danach.
- BELEG aus CloudWatch: 03.09. 12:17 UTC manueller Trigger (25/25/118260), 04.09. 05:00 UTC regulaerer Lauf (25/25/118260), 04.09. 11:48 UTC Screenshot mit 23 Ready. Nebenbefund: Der Cron steht korrekt wieder auf 05:00 UTC, der Reset auf AppConfig v11 vom 03.09. hat gehalten.
- LEHRE: Ich habe eine funktionierende Hypothese (Timing) zugunsten einer spektakulaereren (Listing-Policy) verworfen, gestuetzt auf eine Websuche statt auf einen Test. Die einfache Erklaerung war die richtige, und der Test dafuer lief bereits (der Trigger von 12:17). Vor dem Verwerfen einer Hypothese pruefen, ob ihr Test noch laeuft.
- NAECHSTER SCHRITT fuer die zwei: im Actions Center MATCH NOW, danach genuegt der regulaere 05:00-UTC-Lauf. Kein manueller Trigger noetig.

## RwG: zweite Screenshot-Runde korrigiert meine Meldung (14:00 CEST)
- Kais' vollstaendiger Screenshot (TG 11269) zeigt bei BEIDEN gestoerten Merchants "Matched? = Yes". Meine Meldung "MATCH NOW / ungematcht" war falsch. Sofort korrigiert (TG 11270), bevor Kais nach dem Knopf sucht.
- Alle 25 Merchant-IDs jetzt bekannt. Damit war erstmals eine echte Gegenprobe gegen die laufende Population moeglich.

## Gegenprobe ueber alle 25 (Staging-API, read-only)
Endpunkte: GET /api/customer/settings/widget und GET /api/customer/reservation/slots/2026-09-05, je mit Header x-tenant-id. Beide ohne Auth, Tenant kommt aus dem Header (TenantHeaderInterceptor).

|                    | gestoert (2) | laufend (23) |
|---|---|---|
| Google-Place-ID    | 0 haben      | 1 hat        |
| Telefonnummer      | 0 haben      | 0 haben      |
| Strasse in Adresse | 1 von 2      | 23 von 23    |
| freie Zeitfenster  | 31 und 39    | 0 bis 43     |

- DRITTE FEHLDIAGNOSE VERHINDERT: Ich war dabei, "fehlende googlePlaceId" als Ursache zu melden (merchant-feed.processor.ts setzt matching_hints.place_id daraus). Die Gegenprobe zeigt: 22 der 23 laufenden Betriebe haben die auch nicht. Nur Restaurant Durrani hat eine.
- Availability ebenfalls widerlegt: beide Gestoerten haben Zeitfenster (31 und 39 am Freitag), waehrend Prime Kebab & Cigkoefte an dem Tag NULL hat und trotzdem Ready ist.
- Kein erreichbares Merkmal trennt die beiden von den anderen 23.

## Feed-Protokoll 04.09. 05:00 UTC sauber
- UploadFeedsCron queued alle 25 IDs, beide Gestoerten enthalten. Merchant 25, Service 25, Availability 118260. Keine Warnung zu den beiden (kein "Settings not found", "Address not set", "No tables found", "Schedule not set").
- Einzige Fehlerzeilen: 3x "Missing testing slot" mit fest verdrahteten PRODUKTIONS-Merchant-IDs (Google case 05341814) in logTestSlots(), die in Staging nicht existieren. Laeuft bei jedem Feed-Lauf, taeglich drei Fehlerzeilen Rauschen.

## Nebenbefunde (unabhaengig von der Stoerung)
1. Izmir Kebap Haus hat keine Strasse: Adresse ist nur "08340 Schwarzenberg/Erzgebirge". Geht so in den Merchant-Feed.
2. Keiner der 25 Betriebe hat eine Telefonnummer. merchant-feed.processor.ts sendet telephone: undefined fuer alle.
3. googlePlaceId ist ueber die Settings-API gar nicht setzbar: RestaurantSettingsRequest = Pick(email, phone, address), RestaurantSettingsResponse = Omit(googlePlaceId). Gesetzt wird sie nur beim Tenant-Seeding und im Admin-Onboarding-Formular. Wer sie beim Anlegen nicht setzt, kann sie spaeter nicht nachtragen.
4. Actions-Center-Zaehler sagt "1 - 50 of 50", sichtbar sind 25 Zeilen. Die 25 sind exakt unsere Staging-Tenants. Vermutung (ungeprueft): darunter die Produktions-Betriebe im selben Konto. Mein "23 von 25" gilt damit nur fuer die obere Haelfte.

## Stand
Ursache ist von unserer Seite nicht mehr eingrenzbar. Naechster Schritt liegt bei Kais: Detailansicht der zwei roten Zeilen im Actions Center, dort steht der Grundtext (bei ALIBABA war es "Business listing is not allowed for booking").

## RwG: Google nennt den Grund (14:16 CEST, TG 11272-11274)
- Kais schickte die Inventory-Details beider gestoerter Merchants plus ein Feed-Snippet.
- BEIDE haben exakt EINE Merchant Issue, identischer Text: "Business listing is not allowed for booking". Status RwG-E2E: Disabled. Merchant matched: Yes (mit Edit-Link).
- Das ist dieselbe Zeile, die am 03.09. bei ALIBABA stand. ALIBABA ist heute Ready. Die Meldung kann sich also aufloesen. Was NICHT gilt: meine Deutung vom 03.09., die daraus die Google-Kategorie machte. Der Text sagt nur, dass der VERKNUEPFTE Eintrag nicht buchbar ist (unbestaetigt, Dublette, geschlossen, oder schlicht der falsche Eintrag).

## NEUE SPUR: Quelldatei ist vom 01.09.
- Beide Detailseiten nennen als Source: Service_Feed_staging_1788238860.json = 01.09.2026 05:01:00 UTC.
- Seitdem liefen zwei weitere Service-Feeds: mein Trigger 03.09. 12:18 UTC und der regulaere Lauf 04.09. 05:01 UTC (= 1788498060).
- HYPOTHESE (ungeprueft): Wenn diese zwei Datensaetze noch auf der Datei vom 01.09. stehen, haben die neueren Laeufe sie nicht ersetzt. Das wuerde erklaeren, warum die anderen 23 nach dem frischen Feed auf Ready sprangen und diese zwei nicht.
- GEGENPROBE ANGEFORDERT (Lehre compare-broken-against-working-population sofort angewandt): Kais soll bei einem READY-Betrieb nachsehen, welche Quelldatei dort steht. Vom 04.09. -> Spur heiss. Auch vom 01.09. -> Feld bedeutet nichts, These faellt.
- Zweite Anforderung: Edit neben "Merchant matched" oeffnen, um zu sehen, MIT WELCHEM Google-Eintrag verknuepft ist. Bei Izmir Verdacht auf Fehltreffer, weil wir nur "08340 Schwarzenberg/Erzgebirge" ohne Strasse senden.
- Dritte Anforderung nachgeschoben: Reiter "Future Availability" oeffnen. Mein "sonst nichts" beruhte auf einer sichtbaren Tabelle, das habe ich gegenueber Kais praezisiert statt stehen zu lassen.

## Rating-Befund praezisiert
- Feed-Snippet (Theo) zeigt: "rating": {"value": 0, "number_of_ratings": "0"} - NICHT das leere {} aus meiner Notiz vom 03.09. Es existiert also ein Reviews-Datensatz mit 0/0.
- services-feed.processor.ts:100 sendet rating unbedingt: { number_of_ratings: reviews?.totalRatings.toString(), value: reviews?.rating }.
- Google will das Feld weggelassen haben, wenn keine Bewertungen vorliegen. Als URSACHE scheidet es hier aus (keine Beanstandung dazu gemeldet, nur die Listing-Zeile). Gehoert auf die Aufraeumliste, nicht in die Diagnose.

## RwG: Merchant-Detailseite Izmir (15:19 CEST, TG 11277/11278)
- EIGENE AUSSAGE WIDERLEGT: In der Services-Tabelle steht "Errors: 1". Mein "kein Service-Fehler" von 14:16 war falsch. Ich hatte den Satz um 14:20 bereits eingeschraenkt, jetzt ist er widerlegt. An Kais gemeldet.
- Auch der MERCHANT-Feed haengt am 1. September: Merchant_Feed_staging_1788238800.json = 01.09.2026 05:00:00 UTC, Service_Feed_staging_1788238860.json = 01.09. 05:01:00 UTC. Beide Ebenen, keine Spur der Laeufe vom 03.09. und 04.09.
- GEGENPROBE FEHLT WEITERHIN: Kais hat die Ready-Merchant-Seite noch nicht geschickt. Ohne sie bleibt die Feed-These unbewiesen. Nicht als Befund melden.
- ZAEHLER-BEOBACHTUNG ZURUECKGENOMMEN: Auf der Merchant-Seite steht bei den Services "1 - 10 of 10" ueber genau EINER Zeile. Derselbe Unsinn wie "1 - 50 of 50" ueber 25 Zeilen in der Liste. Der Zaehler zaehlt nicht mit. Meine Vermutung, es lägen 25 Produktions-Betriebe unter der Liste, ist damit hinfaellig und wurde bei Kais zurueckgenommen.
- NEU auf der Merchant-Seite: Feld "Placesheet" mit Link auf den verknuepften Google-Eintrag. Das ist der entscheidende Klick, angefordert.

## Eigenrecherche zu den zwei Adressen (15:2x CEST)
- Grill & Doener Haus by Theo: EXISTIERT. Brenderweg 112, 56070 Koblenz, exakt unsere Adresse. Auf Lieferando und Uber Eats gelistet.
- Izmir Kebap Haus Schwarzenberg: KEIN FUND in zwei unabhaengigen Quellen. (1) Websuche findet nur ein "Izmir Kebap Haus" in Duisburg. (2) Die Gaststaettenliste der Stadt Schwarzenberg (schwarzenberg.de) fuehrt 13 Betriebe, darunter genau einen Doener-Imbiss: "Antalia", Markt 6. Kein Izmir.
- EINSCHRAENKUNG bewusst mitgeliefert (Memory tool-limit-vs-real-negative): Kein Fund ist kein Beweis, ein kleiner Imbiss kann durch beide Raster fallen.
- FOLGERUNG: Die zwei Faelle sind vermutlich verschieden. Izmir = fehlende Strasse plus fraglicher Betrieb, Google haengt womoeglich am falschen Eintrag. Theo = Betrieb existiert, also eher unbestaetigter oder nicht reservierungsfaehiger Google-Eintrag.
- Frage an Kais nachgeschoben: Ist Izmir ueberhaupt ein echter Kunde oder Testdaten? Dann waere der eine Fall gar kein Fehler.

## RwG: Placesheet-Link aufgeloest (16:19 CEST, TG 11281)
- Kais schickte den Placesheet-Link: fuehrt auf einen ECHTEN Google-Eintrag "Izmir Kebap Haus" bei 50.5444567, 12.7884173 (= Schwarzenberg/Erzgebirge). Google-Feature-ID /g/11zfl_mbq3, Place-Hex 0x47a0b700053e9531:0x95914e923467503b.
- ZWEI EIGENE THESEN WIDERLEGT:
  (1) "Betrieb existiert nicht" - falsch. Klassischer Fall von tool-limit-vs-real-negative: Websuche und die staedtische Gaststaettenliste sind BEIDE lueckenhaft. Die Suche selbst zeigte nebenbei zwei weitere Doenerlaeden in Schwarzenberg (Ceren Doener, Nazar Doener Kebap), die in der Stadtliste ebenfalls fehlen. Mein "kein Fund" war nie ein Sachbefund.
  (2) "Falsche Zuordnung" - falsch. Name und Ort stimmen, Google hat korrekt gematcht.
- STRASSE ERMITTELT: Nominatim-Reverse auf die Koordinaten ergibt "Bahnhof 2, 08340 Schwarzenberg/Erzgebirge" (Ortsteil Neustadt, OSM way 233526236). Als Gebaeude am Kartenpunkt geliefert, nicht als gesicherte Geschaeftsadresse - Kunde muss bestaetigen.
- Google Maps direkt ist nicht fetchbar (consent.google.de-Wall). Reverse-Geocoding ueber OSM war der Weg drumherum.

## RwG: Stand der Hypothesen nach dem ganzen Tag
ABGERAEUMT (alle mit Beleg): Listing-Kategorie, fehlende googlePlaceId, fehlende Telefonnummer, fehlende Availability, ungematchte Merchants, falsche Zuordnung, nicht existenter Betrieb, Zaehler "50" (UI-Artefakt).
OFFEN als einzige verbliebene Erklaerung: Der Google-Eintrag ist nicht vom Inhaber beansprucht/bestaetigt. Unbestaetigte Eintraege koennen keine Buchungspartner sein -> exakt "Business listing is not allowed for booking".
PRUEFUNG angefordert: Steht auf der Maps-Seite "Inhaber dieses Unternehmens?" bzw. "Als Inhaber eintragen"? Bei beiden Betrieben.
NOCH IMMER OFFEN: Gegenprobe Source-Datei bei einem Ready-Betrieb (die zwei Gestoerten haengen an den Feeds vom 01.09.).

## PRODUKTBEFUND (unabhaengig von der Stoerung)
Wenn die These stimmt, ist das kein Code-Problem, sondern eine fehlende Onboarding-Voraussetzung: Ein Betrieb braucht ein BESTAETIGTES Google-Unternehmensprofil, bevor RwG freigeschaltet werden kann. Das wird heute nirgends abgefragt. Gehoert in die Onboarding-Strecke (libs/admin/shell onboarding.component.ts fragt googlePlaceId ab, aber nicht den Verifikationsstatus).

## RwG: Kais fragt nach dem Weg auf Produktion (16:22 CEST, TG 11283)
- TECHNISCHER MECHANISMUS (aus upload-feeds.cron.ts): Die Cron zieht alle Settings mit reservation -> googleReservations ->> enabled = 'true' und queued Merchant-, Service- und Availability-Feed (0/1/2 Min versetzt). Ein Schalter pro Betrieb, sonst nichts. Feed-Dateiname traegt ${Stage}, Action-Center-Zugang komplett aus Env-Variablen (PARTNER_ID, SFTP-User je Feed-Art).
- BEFUND, der den Weg blockiert: ALLE 25 Kontaktadressen sind KADiCon-Aliasse der Form info+Name@kadicon.de. NULL echte Empfaenger im Laden. Das verletzt Kais' eigenes Gate vom 29.08. (Memory reserve-google-merchant-consent-gate: "Consent nur mit Zustellkontakt VOM Laden, Aliasse nie als Endpunkt"). Auf Prod wuerde die Reservierung eines echten Gastes bei uns statt beim Wirt landen.
- Dazu: 0 von 25 haben eine Telefonnummer.
- EINSCHRAENKUNG explizit mitgeliefert: Das alles ist STAGING gemessen. Ob Prod eigene, saubere Datensaetze hat, sehe ich ohne Produktionszugang nicht. Nicht ueber die Evidenz hinaus behauptet (Lehre des Tages).
- Beobachtung zu Punkt 4: logTestSlots() enthaelt drei fest verdrahtete PRODUKTIONS-Merchant-IDs aus "Google case 05341814 (2026-05-20)". Sieht nach erfolgter Produktions-Abnahme mit drei Betrieben aus, unverifiziert.
- EMPFEHLUNG an Kais: keine 23 auf einmal. Drei Betriebe mit echtem Wirtskontakt, dort die drei Voraussetzungen einsammeln (echte Mail, Telefon, bestaetigtes Google-Profil), freischalten, eine Woche laufen lassen, erst nach einer sauber zugestellten echten Reservierung skalieren.
- Angeboten: Abfrageliste fuer die Wirte bauen.

## RwG PROD-PRUEFUNG (16:26 CEST, Auftrag TG 11285 "Bitte ueberpruefen und wenn es passt dann auf googleReservations.enabled")
- AUFTRAG NICHT AUSFUEHRBAR, Praemisse haelt nicht: Die 25 Staging-Betriebe existieren in der Produktion NICHT.
- BELEG mit Kontrollgruppe (gleicher Aufruf, gleiche Form):
  * 3 Produktions-Kennungen (aus logTestSlots im Code) -> HTTP 200 mit Daten
  * 5 Staging-Kennungen gegen api.kadicon.de -> HTTP 400, kein Settings-Datensatz
- googleReservations.enabled haengt am Betrieb. Kein Betrieb, kein Schalter. "Auf Prod bringen" = Neuanlage pro Betrieb, kein Umlegen.
- PRODUKTIONSSTAND der drei bekannten Betriebe (read-only ueber den offenen Widget-Endpunkt):
  Gusto (Trierer Str. 322a, Koblenz), Klosterwirt Wienhausen (Hauptstrasse 9), BURGER POINT (Langendiebacher Str. 41, Erlensee).
  Alle drei: googlePlaceId GESETZT, vollstaendige Adresse, KEINE Telefonnummer, E-Mail = info+name@kadicon.de.
- ZWEI EIGENE AUSSAGEN ZURUECKGENOMMEN:
  (1) "Alias-Adressen sind ein Staging-Befund" - falsch, das Muster ist systemweit, auch Prod. Damit war mein "landet bei uns statt beim Wirt" zu scharf. Offene Frage an Kais: Leiten diese Aliasse an den Laden weiter?
  (2) Fehlende Telefonnummer ist kein Staging-Problem, sondern eine Produktluecke (auch Prod hat keine).
- QUALITAETSUNTERSCHIED sichtbar: Prod 3/3 mit Place-ID, Staging 1/25. Staging ist erkennbar Testbestand.
- NICHTS VERAENDERT. Nur gelesen, in beiden Umgebungen. Gegenueber Kais transparent gemacht, inkl. Angebot zu sagen, falls ihm schon das Lesen auf Prod zu weit ging.
- ENTSCHEIDUNGSFRAGE an Kais gestellt: Sind die 25 echte Vertragskunden oder Vorfuehr-/Testbestand? Bei echten Kunden liefere ich die Einrichtungsliste fuer Prod, bei Testdaten erledigt sich die ganze Disabled-Frage.

## RwG: Bereitschaftsliste fuer die Prod-Uebernahme (16:32-16:45 CEST)
- Kais bestaetigt: echte Vertragskunden. Auftrag: erst die Betriebe nach Prod, bei denen alles vollstaendig ist.
- ERHEBUNG ueber alle 25: Adresse, Place-ID, Oeffnungszeiten, und buchbare Zeitfenster ueber SIEBEN Tage (05.-11.09., jeder Wochentag genau einmal, 175 Abfragen, 0 Fehler).
- ERGEBNIS: 23 von 25 sofort anlegbar. Adresse vollstaendig 23/25, Oeffnungszeiten 25/25, Zeitfenster 25/25 ohne Luecke.
- KEIN EINZIGER Betrieb hat einen als geoeffnet markierten Tag ohne buchbare Fenster. Tische und Zeitplaene durchgehend sauber.
- ZWEI NACHZUEGLER: Izmir Kebap Haus (keine Strasse; Vorschlag aus Reverse-Geocoding: Bahnhof 2, 08340 Schwarzenberg/Erzgebirge) und Maxx Chicken & Doener (Strassenname ohne Hausnummer, Grashuepferweg im Argonner Park Hanau).
- PLACE-ID-BEFUND ZURUECKGENOMMEN: Sie ist KEIN Hindernis. onboarding.component.ts onGoogleAddressChanged() setzt address (formatted_address) UND googlePlaceId (place_id) in einem Schritt aus dem Google-Autocomplete-Treffer, beide Felder Validators.required. Die Staging-Tenants wurden am Formular vorbei eingespielt, deshalb fehlt sie dort. Beleg nebenbei: Die Prod-Adressen tragen Googles formatted_address-Form ("..., Rheinland-Pfalz, Deutschland"), die Staging-Adressen nicht.
- EIGENE FEHLAUSSAGE KORRIGIERT: Mein "Prime Kebab hat am Freitag null Fenster" war doppelt falsch - der 05.09. ist ein Samstag, und der Laden hat samstags zu. Ueber die volle Woche keine Luecke. Die Schlussfolgerung (Availability erklaert die zwei Disabled nicht) bleibt, das Einzelargument war Muell.
- STRATEGISCHER HINWEIS an Kais: Mit der Adresswahl im Formular bindet man jeden Betrieb an EINEN bestimmten Google-Eintrag. Ist der unbeansprucht, kommt sofort wieder "Business listing is not allowed for booking". Pruefung gehoert VOR die Anlage.
- LIEFERUNG: prod-onboarding-liste.md an Kais (TG 11289/11290), Kopie im Vault unter 01-Projekte/reserve-with-google-onboarding/prod-bereitschaft-2026-09-04.md.

## RwG: Ablauf geschrieben, Umsetzung nicht ausfuehrbar (16:45 CEST, Auftrag TG 11291)
- Kais: "Grashuepferweg, 63457 Wolfgang / ablauf schreiben und umsetzten".
- ZWEI FALLEN im Anlage-Code gefunden, die den ganzen Plan geaendert haben:
  (1) TenantSeedService.seedSettings() legt KEIN schedule an. Neuer Betrieb hat keine Oeffnungszeiten -> Availability-Feed erzeugt null Zeitfenster -> Google "No upcoming availability" -> Disabled.
  (2) seedTables() legt genau T1 und T2 mit je capacity 3 an. Gruppengroessen damit auf max. sechs begrenzt, zwei parallele Reservierungen.
  Beides erklaert, warum die Staging-Betriebe gut aussehen (dort nachgepflegt) und ein frischer Prod-Betrieb nicht. Als eigene Arbeitsschritte VOR dem Einschalten in den Ablauf geschrieben.
- ANLAGE NICHT VON HIER AUSFUEHRBAR: CreateTenantWithUserRequest verlangt verificationToken, tenant.service.ts:40 verifyToken() loest ihn zu einer E-Mail auf. Kein Weg an einem erreichbaren Postfach vorbei. Ich habe weder die info+-Postfaecher noch Zugang zur Prod-Oberflaeche. Zusaetzlich: keine Anlage in Prod mit echten Wirten/Gaesten, solange die Alias-Frage offen ist.
- KAIS' ADRESSANGABE LOEST DAS PROBLEM NICHT: "Grashuepferweg, 63457 Wolfgang" ist ein Strassenname ohne Hausnummer. In der Autovervollstaendigung gewaehlt bindet das an eine STRASSE, die Place-ID zeigt auf einen Strassenabschnitt -> reproduzierbar "Business listing is not allowed for booking". Klar benannt statt hoeflich uebergangen.
- EIGENEN RAT ENTSCHAERFT: Meine Empfehlung "vor jeder Anlage Google-Eintrag pruefen" ist grossteils erledigt - das Actions Center fuehrt 23 der 25 auf Ready, Google hat fuer die also bereits einen buchbaren Eintrag akzeptiert. Nur Izmir und Theo offen.
- LIEFERUNG: prod-ablauf.md (TG 11292/11293), Kopie im Vault 01-Projekte/reserve-with-google-onboarding/prod-ablauf-2026-09-04.md.
- ANGEBOTEN: Oeffnungszeiten und Tischplaene aller 25 Staging-Betriebe auslesen und als Uebertragungsliste aufbereiten, damit die Schritte 3 und 4 Abtipparbeit werden.
- OFFENE SCHLUESSELFRAGE an Kais: Leiten die info+-Aliasse an die Laeden weiter?

## RwG: Uebertragungsliste geliefert, zwei Klarstellungen (16:55 CEST, TG 11294)
- MISSVERSTAENDNIS AUFGEKLAERT: Kais fragte "Fall 1: Welches Restaurant? Fall 2: Welches Restaurant?" - er las meine zwei Fallen als Befunde ueber bestehende Betriebe. Sind sie nicht: Es sind Eigenschaften des Anlage-Codes, die jeden NEU erzeugten Betrieb treffen. Meine Formulierung war missverstaendlich, das habe ich eingeraeumt statt es zu ueberspielen.
- BELEG, dass keiner der 25 betroffen ist: Oeffnungszeiten 25/25 gesetzt und kein toter Tag (7-Tage-Messung). Groesste buchbare Gruppe: 24 Betriebe 6, Restaurant Durrani 10, NULL Betriebe bei 3.
- EIGENE ZAHL KORRIGIERT: Ich hatte gesagt, ein neuer Betrieb koenne "Gruppen bis sechs Personen". Falsch. seedTables() legt T1 und T2 mit je capacity 3 an und KEINE Kombination -> groesste Gruppe ist 3. Ich hatte die Falle harmloser dargestellt als sie ist.
- NEUE VERMUTUNG (als solche gekennzeichnet): 24 von 25 haben exakt dieselbe Obergrenze 6. Zu gleichfoermig fuer individuell erfasste Raumplaene; zwei Standardtische plus eine Kombination ergeben genau 6. Nur Durrani (10) hat einen echten Tischplan. Heisst: Auch die Staging-Betriebe haben vermutlich keine echten Raumplaene, die muessen fuer Prod pro Laden erhoben werden.
- MESSMETHODE offengelegt: Tischplan-Endpunkt (/api/table) verlangt JWT, DURRANI_SANDBOX_ACCESS_TOKEN ist abgelaufen (401). Stattdessen groesste buchbare Gruppe ueber den slots-Endpunkt mit partySize-Parameter gemessen (25 Betriebe x 14 Gruppengroessen). Entspricht laut getAllPartySizes dem groessten Tisch bzw. der groessten Kombination.
- KAIS-EINGABEN AUFGENOMMEN: "Grashuepferweg 12" -> Maxx Chicken & Doener jetzt vollstaendig, bei den Adressen bleibt nur Izmir offen. "E-Mail wird weitergeleitet" -> Phase-0-Punkt 1 ERLEDIGT, die Reservierung erreicht den Wirt, Consent-Gate insoweit erfuellt.
- LIEFERUNG: uebertragungsliste-25.md mit Oeffnungszeiten Tag fuer Tag, Kennung, Adresse, Actions-Center-Status und Kapazitaet je Betrieb (TG 11295/11296). Kopie im Vault.
- STAND: 23 Betriebe (alle ausser Izmir und Theo) haben vollstaendige Adresse UND Actions-Center-Status Ready. Offen fuer den Start: echte Tischplaene je Laden.

## RwG: "umsetzen" zum zweiten Mal - Blocker praezise eingegrenzt (17:00 CEST, TG 11297)
- Kais liefert Izmirs Adresse (Bahnhof 2, 08340 Schwarzenberg/Erzgebirge) und wiederholt "umsetzten". Nach Memory repeated-instruction-is-not-an-answer NICHT einfach wieder abgelehnt, sondern nachgesehen, was genau fehlt.
- ERGEBNIS: Der Umbau zerfaellt in zwei Haelften, nur eine ist blockiert.
  A) ANLEGEN in Prod: bleibt bei Kais. CreateTenantWithUserRequest verlangt verificationToken, der entsteht nur ueber POST /auth/verify -> Bestaetigungsmail -> POST /auth/verify/token. Kein Zugang meinerseits ersetzt ein Postfach.
  B) ALLES DANACH: nur ein angemeldetes Konto noetig. SaveSettingsRequest umfasst schedule, reservation (mit googleReservations), restaurant (email/phone/address). POST /table nimmt SaveTableRequest[]. LoginRequest ist schlicht email+password, POST /api/auth/login liefert das JWT.
- WERKZEUG GEBAUT statt nur zu melden: /home/aria/projekte/rwg-prod-uebernahme/kadicon_settings.py. Kann anmelden, lesen, Adresse/Telefon setzen, Zeitplan aus JSON einspielen, googleReservations einschalten. Schreibt NICHTS ohne --apply, zeigt vorher immer den Vorher-Nachher-Vergleich. Syntax geprueft, Ablauf gegen fehlende Credentials getestet.
- SICHERHEITSHINWEIS einmal gegeben (LRN-20260506-003: einmal warnen, dann pragmatisch): Telegram ist kein guter Ort fuer Passwoerter, aber wenn kein besserer Weg da ist, Ablage mit 600 und transparente Meldung wo.
- ERWARTUNG GEDAEMPFT: Izmirs Adresskorrektur behebt das Disabled NICHT. Google hat bereits den richtigen Eintrag zugeordnet (Placesheet-Link), das Problem sitzt im Eintrag selbst. Ausserdem laesst sich googlePlaceId ueber die Settings-API gar nicht setzen (RestaurantSettingsRequest = Pick(email, phone, address)).
- OFFEN: Kais' Entscheidung - Anmeldung an mich, oder Klickfolge fuer ihn.

## RwG: Anleitung geliefert, Google-Konto-Missverstaendnis aufgeloest (17:10 CEST, TG 11299)
- KAIS-MISSVERSTAENDNIS: Er fragte "Egal welches Google Konto? Du hast ein Google Konto bereits zugang". Die KADiCon-Anmeldung ist KEIN Google-Konto und kein SSO - LoginRequest ist schlicht email+password gegen POST /api/auth/login. Mein Drive-Zugang hilft null. Klargestellt.
- MAIL NICHT VERSCHICKT, bewusst. POST /auth/verify nimmt nur {email} und schickt eine Bestaetigungsmail mit JWT-Token im Link (auth.service.ts:85 sendConfirmationEmail). Wer die Mail liest, kann anlegen. ENTSCHEIDENDE OFFENE FRAGE an Kais: Wohin leiten die info+-Aliasse? In ein Postfach, das ER oeffnet (dann ist Haelfte A in Minuten erledigt), oder direkt zum Wirt (dann muss der Wirt klicken)? Eine Mail an einen echten Wirt ist nicht zurueckholbar, deshalb erst nach seiner Antwort und nur fuer den ersten benannten Betrieb.
- IZMIR ZURUECKGESTELLT auf Kais' Entscheidung, zugestimmt. Theo aus demselben Grund gleich mit vorgeschlagen. Bleiben 23.
- ANLEITUNG GELIEFERT: /home/aria/projekte/rwg-prod-uebernahme/anleitung-prod-uebernahme.md, Kopie im Vault. Sechs Schritte je Betrieb mit den ECHTEN Oberflaechenpfaden aus admin-shell.routes.ts und settings.routes.ts (/auth/register, /auth/login, /settings/schedule, /settings/room-plan, /settings/reservation) - aus dem Quelltext gelesen, nicht geraten.
- HERVORGEHOBEN in der Anleitung: Adresse aus der Autovervollstaendigung WAEHLEN statt tippen, und den BETRIEB waehlen, nicht die Strasse. Sonst zeigt die Place-ID auf einen Strassenabschnitt -> reproduzierbar "Business listing is not allowed for booking".
- SCHRITT 5 UEBERNEHME ICH: Nach jeder Anlage die neue Kennung an mich, ich pruefe ueber den slots-Endpunkt, ob Zeitfenster entstehen - VOR dem Einschalten.
- WEITERHIN FEHLEND je Betrieb: Telefonnummer und echter Tischplan. Haben wir nirgends, muss vom Wirt kommen.

## RwG: "alle auf einmal" gestoppt - zwei Code-Befunde kippen den Plan (17:05 CEST, TG 11302)
- Kais: "Ja der Wirt kann klicken, mache alle auf einmal" + Zusage, Zugangsdaten sicher zu uebergeben.
- NICHTS VERSCHICKT. Vorher zwei Dinge geprueft, beide entscheidend:
  1) TOKEN LEBT NUR EINE STUNDE. auth.service.ts startEmailVerification(): jwtService.signAsync({email}, {secret, expiresIn: '1h'}). 23 Mails gleichzeitig heisst: jeder Wirt, der nicht binnen 60 Minuten klickt, hat einen toten Link. Verbrannter Erstkontakt bei echten Vertragskunden.
  2) EIN ZUGANG REICHT NICHT FUER 23 BETRIEBE. MultiTenancyInterceptor prueft hart user.tenantId !== tenantId -> NotAcceptableException. Ein Konto kann ausschliesslich seinen eigenen Mandanten bearbeiten, es gibt keinen betriebsuebergreifenden Verwalterzugang ueber diese Endpunkte. Wenn die Wirte sich selbst anmelden, gehoeren IHNEN Konto und Passwort -> ich kann Haelfte B fuer sie gar nicht machen, egal welchen Zugang Kais mir gibt.
- DRITTES ARGUMENT (fachlich, nicht aus dem Code): Wer klickt, fuellt auch das Formular aus - inklusive der Adressauswahl. Genau das Feld, das heute den ganzen Tag gekostet hat. 23 unangeleitete Wirte produzieren zuverlaessig falsche Verknuepfungen.
- EMPFEHLUNG an Kais: KADiCon legt an, nicht die Wirte. Bestaetigungsmail an eine Adresse, die KADiCon liest; Formular mit korrekter Adressauswahl ausfuellen; Oeffnungszeiten und Tischplan setzen; danach die Zugangsdaten an den Wirt uebergeben. So sind auch die bestehenden 25 und die drei Prod-Betriebe entstanden (alle @kadicon.de). Vorteile: Adressauswahl bleibt kontrolliert, Ein-Stunden-Ablauf irrelevant, und ich kann Haelfte B uebernehmen weil die Konten KADiCon gehoeren.
- ALTERNATIVE angeboten falls er den Wirt klicken lassen will: einzeln mit Telefon daneben, drei Stueck, nicht 23.
- Zugangsuebergabe: scp in eine Datei auf dem Server, Ablage mit 600 zugesagt.

## RwG: Kais nimmt meinen Vorschlag an, Anleitung korrigiert (17:08 CEST, TG 11304)
- Kais: "WIr machen dein Vorschlag" -> KADiCon legt an, nicht die Wirte.
- BEIM NACHLESEN EINE FALLE GEFUNDEN, die genau diesen Weg zerstoert haette: Es sind ZWEI verschiedene Adressen.
  * user.email = Anmeldung UND Empfaenger der Bestaetigungsmail. tenant.service.ts create(): const email = await this.verifyToken(...); if (email !== request.user.email) throw new BadRequestException. Die bestaetigte Adresse muss GENAU der Benutzer-E-Mail entsprechen.
  * contactEmail = Kontakt des Betriebs, geht in settings.restaurant.email, das ist die weiterleitende info+Name@kadicon.de.
  Haette Kais beim Anmelden die Alias-Adresse eingetragen, waere die Bestaetigungsmail beim Wirt gelandet und der Token unerreichbar - also exakt das Problem, das der neue Weg vermeiden sollte.
- Weitere Details aus create(): company.email = user.email, emailVerified true, user bekommt isAdmin true, Passwort per argon2. Danach seedService.seed().
- ANLEITUNG UEBERARBEITET (anleitung-prod-uebernahme.md, neu geschickt TG 11305/11306, Vault-Kopie aktualisiert): Zwei-Adressen-Tabelle in Schritt 1, Ein-Stunden-Frist dort verankert, plus neuer Abschnitt "Aufteilung der Arbeit" (Kais im Browser wegen der Autovervollstaendigung, ich ueber die Schnittstelle fuer Zeitplan/Tischplan/Schalter, ich sofort fuer die Kontrolle).
- OFFEN, damit ich starten kann: (1) Muster fuer die Benutzer-E-Mail, das in KADiCons Postfach landet und je Betrieb eindeutig ist (Vorschlag rwg+kurzname@kadicon.de). (2) Welche drei Betriebe zuerst.
- WEITER FEHLEND je Betrieb: Telefonnummer und echter Tischplan. Ohne Tischplan buchen Gaeste nur zu dritt.

## RwG: ERSTE PROD-AKTION AUSGEFUEHRT (17:11 CEST, Auftrag TG 11307)
- Kais gibt Muster rwg+alibaba@kadicon.de frei und sagt "egal einfach starten".
- AUSGEFUEHRT: POST https://api.kadicon.de/api/auth/verify {"email":"rwg+alibaba@kadicon.de"} -> HTTP 204. Bestaetigungsmail raus 17:11 CEST, Link tot ab 18:11 CEST (expiresIn 1h). Empfaenger ist KADiCons eigenes Postfach, KEIN Wirt betroffen. Neu anstossen ist jederzeit kostenlos moeglich.
- TISCH-MINDESTVORAUSSETZUNG aus SaveTableRequest ermittelt: name (1-30), capacity (positive int), width/height (positive int), columnStart/rowStart (>=0), shape (rectangle|round). Namen, Masse und Positionen erzeuge ich selbst - fuer Reservierungen zaehlen nur die Platzzahlen. Wirkung: groesste Tischgroesse = maximale Gruppengroesse, Anzahl = parallele Reservierungen.
- FORMAT an Kais definiert: Tische als "6x2, 4x4, 1x8" (Anzahl mal Plaetze). Telefon international ohne Trennzeichen, z.B. +4995611234567 (Google-Konvention, das Feld selbst hat keine Validierung).
- EINGABELISTE geliefert: eingabeliste-23.csv, 23 Betriebe, Spalten Betrieb/Adresse/Benutzer-E-Mail/Telefon/Tische. Erste drei Spalten vorbefuellt, Kurznamen eindeutig geprueft (assert). Maxx Chicken traegt jetzt die neue Adresse Grashuepferweg 12. Izmir und Theo nicht enthalten (zurueckgestellt). Kopien in /home/aria/projekte/rwg-prod-uebernahme/ und im Vault.
- ARBEITSTEILUNG laeuft: Kais legt im Browser an (wegen Adress-Autovervollstaendigung), schickt mir je Betrieb die neue Kennung, ich pruefe die Zeitfenster und setze danach Zeiten und Tische ueber die Schnittstelle.

## RwG: Adressmuster korrigiert auf info+ (17:13 CEST, TG 11310)
- Kais korrigiert: nicht rwg+, sondern info+alibaba@kadicon.de.
- AUSGEFUEHRT: POST /api/auth/verify {"email":"info+alibaba@kadicon.de"} auf Produktion -> HTTP 204, raus 17:13 CEST, Link tot ab 18:13. Kein Konflikt (kein bestehender Nutzer mit der Adresse in Prod). Die erste Mail an rwg+alibaba laeuft ungenutzt ab.
- Eingabeliste auf info+ umgestellt, 23 von 23 Zeilen, 0 alte Adressen uebrig (geprueft per grep -c, nicht per Augenmass). Kopien aktualisiert.
- RISIKO BENANNT statt stillschweigend uebergangen: Kais sagte vorhin, die info+-Adressen werden weitergeleitet. Greift die Weiterleitung auch fuer info+alibaba, landet die Bestaetigungsmail beim Wirt statt bei ihm - genau die Falle, wegen der wir das Muster getrennt hatten.
- ABER dafuer spricht: Die drei Produktions-Betriebe (Gusto, Klosterwirt Wienhausen, BURGER POINT) tragen alle info+name@kadicon.de, und company.email = user.email. Das Muster ist in Prod also nachweislich so gebaut worden und funktioniert. Deshalb ausgefuehrt statt blockiert, mit klarem Hinweis, woran es liegt falls die Mail nicht ankommt.

## RwG: ALIBABA in Prod angelegt, ausgefuellte Liste geprueft (17:30 CEST, TG 11313)
- Kais hat ALIBABA in der Produktion bestaetigt und angelegt (ueber das Formular, also MIT Place-ID). Fragt, ob ich die restlichen selbst anlegen kann, wenn er die Bestaetigungslinks schickt.
- LISTE GEPRUEFT statt uebernommen: 23/23 Zeilen verwertbar, alle Telefonnummern passen auf +49 plus 9-13 Ziffern, alle Tischangaben parsebar. Datei gesichert in projekte/ und im Vault.
- WICHTIGSTER BEFUND: Bei ALLEN 23 Betrieben SINKT die maximal buchbare Gruppe. Heute bietet Google ueberall bis 6 an, mit den echten Tischplaenen sind es 3 oder 4 (Durrani 10 -> 8). Grund: Die groesste Gruppe richtet sich nach dem groessten EINZELNEN Tisch, und kein Laden hat einen Fuenfer oder Sechser. 23 von 23 sinken, 0 steigen.
- LOESUNG waere TableCombination (der Feed rechnet ueber getAllPartySizes(tables, combinations)). NICHT auf Verdacht angelegt, sondern Kais zwei Optionen gegeben: Standardkombination je zwei groesster Tische (Obergrenze wieder 6-8) oder nur echte Tische (Gruppen bis 4, ehrlicher, weniger Reservierungen).
- ZWEI NUMMERN zur Sichtpruefung gemeldet: Orient Kebap sitzt in Saarbruecken, traegt aber +49 30 ... (Berliner Vorwahl) - Zentrale oder Zahlendreher, Google zeigt die Nummer den Gaesten. Durranis 06051 passt zu Gelnhausen.
- ANTWORT auf die Autonomiefrage: JA, ich kann anlegen. CreateTenantWithUserRequest hat googlePlaceId nur mit @IsString(), NICHT @IsNotEmpty() - die Pflicht existiert allein im Browser-Formular (Validators.required). Ich brauche nur die Bestaetigungslinks.
- HAKEN EHRLICH BENANNT: Ohne Formular bleibt die Place-ID leer und ist ueber die Schnittstelle NICHT nachtragbar (RestaurantSettingsRequest = Pick(email, phone, address)). Google muesste ueber Name und Adresse zuordnen.
- WARUM TROTZDEM EMPFOHLEN: Genau so laufen die 25 Staging-Betriebe. 22 ohne Place-ID, Google hat alle zugeordnet, 23 auf Ready. Fehlzuordnungen sind im Actions Center ueber "Edit" neben "Merchant matched" korrigierbar.
- ANGEFORDERT fuer den naechsten Schritt: ALIBABAs neue Prod-Kennung und das gesetzte Passwort. Damit setze ich Oeffnungszeiten, Tischplan und Telefon, pruefe die Zeitfenster und melde die Einschaltbereitschaft.

## RwG: ALIBABA in Prod fertig konfiguriert + PRODUKTFEHLER AUSGELOEST (17:36-17:45 CEST)
- Kais: Standard-Kombination gewuenscht, 030-Nummer bestaetigt, Passwort kadicon123 geliefert.
- ZUGANG: Passwort in /home/aria/projekte/rwg-prod-uebernahme/.secrets/prod.env mit 600 abgelegt. Anmeldung ueber POST /api/auth/login liefert access_token; die TENANT-KENNUNG steckt im JWT (tenantId). Kais muss sie also NICHT heraussuchen - das war seine Frage 1.
- ALIBABA Prod-Kennung: ac8e1572-9154-44b1-bb82-560e1d00fd71.
- BEIDE FALLEN LIVE BESTAETIGT: schedule LEER, genau zwei Tische T1/T2 mit je 3 Plaetzen, googleReservations.enabled false.
- GESETZT: Zeitplan aus Staging (6 Tage), Telefon +4916095139854, T3 mit 4 Plaetzen ergaenzt, Kombination T3+T1 = 7.
- GEPRUEFT: 40-47 freie Fenster je Tag, Gruppen bis 7 buchbar, ab 8 nicht. Place-ID ChIJf7HYC2zOo0cRWkzw2XVcOco.

### PRODUKTFEHLER: POST /settings ersetzt statt zusammenzufuehren
- MEIN ERSTER SCHREIBVORGANG HAT googlePlaceId UND timezone GELOESCHT. Ich hatte beide Werte vorher gelesen, sofort zurueckgeschrieben und die Wiederherstellung verifiziert. Nichts verloren.
- URSACHE (settings.service.ts:18-42): save() will mergen - request.restaurant = {...existing.restaurant, ...request.restaurant}. Aber `existing` wird geladen mit select: { customerApp: { quickActions: {} } }, dadurch ist existing.restaurant undefined. Der Merge ergaenzt nichts, das Gesendete ERSETZT den ganzen Block. Jedes nicht gesendete Feld faellt weg. Kein Fehler, keine Warnung.
- TRAGWEITE: Trifft auch die Oberflaeche. Die Seite /settings/restaurant sendet genau email/phone/address -> bei JEDEM Speichern dort verschwinden googlePlaceId und timezone.
- HYPOTHESE (als solche gemeldet, nicht als Befund): Koennte erklaeren, warum 22 von 25 Staging-Betrieben keine Place-ID haben.
- ARBEITSREGEL AB JETZT: bei POST /settings immer den VOLLSTAENDIGEN Block senden, inklusive der Felder, die das Schreib-DTO gar nicht kennt.
- NEBENBEFUND, der eine fruehere Aussage von mir umdreht: googlePlaceId IST ueber die Schnittstelle schreibbar. ValidationPipe laeuft ohne whitelist, unbekannte Felder werden nicht entfernt. Bewiesen durch die Wiederherstellung. Meine Aussage "laesst sich spaeter nicht nachtragen" war falsch.
- OFFEN bei Kais: (1) Go fuer den googleReservations-Schalter bei ALIBABA. (2) GOOGLE_MAPS_API_KEY, damit ich Adressen selbst zu Place-IDs aufloesen kann - dann ist der Schnittstellenweg dem Formular gleichwertig.

## RwG: ALIBABA LIVE + 22 Mails raus + Strecke gebaut (17:42-17:50 CEST, Auftrag TG 11317)
- ALIBABA EINGESCHALTET: googleReservations.enabled = true auf Prod-Tenant ac8e1572-9154-44b1-bb82-560e1d00fd71. Diesmal den VOLLSTAENDIGEN reservation-Block gesendet (Lehre aus B1), Kontrolle danach: autoApproveReservations, defaultReservationTime, dashboardReservationTimeLimit, restaurant-Block mit Place-ID und Zeitplan alle unversehrt. Naechster Feed-Lauf 05.09. 05:00 UTC.
- 22 BESTAETIGUNGSMAILS verschickt 17:42 CEST, alle HTTP 204, kein Fehlschlag. Frist bis 18:42. Neu anstossen ist kostenlos.
- VERARBEITUNGSSTRECKE gebaut: /home/aria/projekte/rwg-prod-uebernahme/anlegen.py (Kopie im Vault). Nimmt eine Datei mit Links, Reihenfolge egal. Zuordnung ueber die E-Mail IM TOKEN (JWT-Payload), nicht ueber die Reihenfolge - Link-Form ist ${DASHBOARD_URL}/onboarding?token=<JWT>.
- ABLAUF je Betrieb: POST /tenant -> POST /auth/login (Kennung aus dem JWT) -> POST /settings (Zeitplan + VOLLSTAENDIGER restaurant-Block inkl. Telefon) -> POST /table (echter Tischplan) -> POST /table/combination (zwei groesste) -> Kontrolle Zeitfenster und Gruppengroesse -> NUR DANN googleReservations einschalten. Bei 0 Zeitfenstern Abbruch vor dem Einschalten. Ohne --apply wird nichts geschrieben.
- BAUSTEINE GETESTET statt behauptet: parse_tische, namen(), lade_stammdaten. 23 von 23 Betrieben haben einen Zeitplan aus Staging, keiner fehlt.
- DREI EIGENE ENTSCHEIDUNGEN transparent gemacht: gleiches Passwort ueberall, Benutzernamen aus dem Betriebsnamen abgeleitet, Place-ID bleibt leer ohne Google-Schluessel.
- SICHERHEITSHINWEIS einmal gegeben: kadicon123 auf 23 Produktionskonten mit echten Kundendaten ist schwach; bei der Uebergabe an die Wirte je eigenes Passwort setzen. Trotzdem so ausgefuehrt, weil sonst nicht handhabbar (SOUL: Kais' explizite Anweisung nach einmaliger Warnung).
- ERNEUT ANGEFORDERT: GOOGLE_MAPS_API_KEY aus dem Backend. Damit koennte ich die 22 Adressen selbst zu Place-IDs aufloesen und eintragen - dann ist der Schnittstellenweg dem Formular ebenbuertig.

## RwG: 22 BETRIEBE IN PRODUKTION ANGELEGT UND LIVE (17:49-17:51 CEST)
- Kais schickte 18 + 4 Links. Vorschaulauf zur Zuordnungspruefung, dann --apply. 22 von 22 FERTIG in 97 Sekunden.
- Je Betrieb: angelegt, angemeldet, Zeitplan + vollstaendiger restaurant-Block mit Telefon, echter Tischplan, Kombination der zwei groessten Tische, Kontrolle, dann googleReservations EIN.
- Kennungen gesichert in prod-kennungen.txt (projekte/ und Vault), Volllauf in lauf.log.

### PROBLEM 1: Durrani-Dublette
- Kais' Warnung ("Durrani ist schon auf Prod mit 4e22f973-36d5-4e8c-b8a3-c85a7b87cf10, nicht nochmal anlegen") traf 15:50:57 UTC ein, mein Lauf endete 15:51:20 UTC. 23 Sekunden zu spaet.
- Ich habe Durrani als 22130b68-82e8-4b95-95c6-cc2abfee1079 ein zweites Mal angelegt und eingeschaltet.
- SOFORT KORRIGIERT: googleReservations auf false zurueckgesetzt und verifiziert. Das Duplikat geht NICHT in den Feed. Der echte Prod-Durrani (4e22f973, hat Logo/Banner, defaultReservationTime 150) ist unberuehrt.
- Loeschen ist ueber die Schnittstelle nicht moeglich. Bei Kais liegt die Entscheidung: liegen lassen oder in der Datenbank entfernen.
- RUECKFRAGE an Kais: Steht beim echten Durrani der Google-Schalter auf ein? Sonst ist er als einziger nicht live.

### PROBLEM 2: mein eigener Pruef-Riegel war zu grob
- Die Kontrolle vor dem Einschalten mass die Gruppengroessen an einem FESTEN Datum (2026-09-07, ein Montag). Durrani hat montags geschlossen -> Meldung "Gruppen bis 0", und der Riegel liess trotzdem durch, weil er nur `frei == 0` prueft, nicht `maxp == 0`.
- NACHKONTROLLE aller 22 an einem je Betrieb GEOEFFNETEN Tag: 14 bis 45 freie Fenster, groesste Gruppe 5 bis 8 (Durrani 14), kein Betrieb ohne Fenster, kein Betrieb ohne buchbare Gruppe, ueberall Telefon gesetzt.
- LEHRE: Ein Pruefdatum, das fuer manche Faelle ein Ruhetag ist, erzeugt falsche Negative; und ein Riegel muss genau die Groesse pruefen, die er schuetzen soll.

### Stand
- Live im Feed: ALIBABA + 21 neue = 22 Betriebe. Durrani laeuft ueber den bestehenden Prod-Betrieb, Status dort unbekannt.
- Bei allen 22 neuen fehlt die googlePlaceId (ueber die Schnittstelle angelegt). Google ordnet ueber Name und Adresse zu, so wie bei den 23 Staging-Betrieben, die damit auf Ready stehen.
- Naechster Feed-Lauf 05.09. 05:00 UTC. Danach im Actions Center pruefen.

## RwG: Maps-Schluessel lokalisiert, Sicherheitsbefund (18:00 CEST, TG 11323)
- Kais fragt, woher er den GOOGLE_MAPS_API_KEY bekommt, und will Durrani 4e22f973 live setzen.
- SCHLUESSEL LOKALISIERT, WERT NICHT GELESEN: GOOGLE_MAPS_API_KEY steht in der ECS-Aufgabendefinition backend-staging:10, Container `backend`, als einfache Umgebungsvariable. Mit dem vorhandenen aria-automation-Zugang lesbar. Ich habe nur die NAMEN abgefragt und Kais um das Go gebeten, statt den Wert einfach zu nehmen (Stufe-4-Regel: Credential-Zugriff).
- SICHERHEITSBEFUND B6 dokumentiert: Der Backend-Container hat `secrets: []`. DATABASE_PASSWORD, STRIPE_API_KEY, STRIPE_WEBHOOK_SECRET, der SFTP-Schluessel, der Service-Account-Private-Key und das Booking-Server-Passwort stehen alle als Klartext unter `environment`. Jeder mit ecs:DescribeTaskDefinition liest sie. Empfehlung: Secrets Manager oder SSM, ueber `secrets:` referenzieren.
- DURRANI 4e22f973: Kein Zugriff, das Konto gehoert einer mir unbekannten Anmeldung. Zwei Wege an Kais gegeben: Anmeldedaten schicken, oder selbst unter /settings/reservation das Haekchen setzen.
- WICHTIGE WARNUNG an Kais ausgesprochen: Auf KEINER der Betriebsseiten /settings/restaurant speichern. Wegen B1 loescht jedes Speichern dort googlePlaceId und timezone. Bei ALIBABA ist die Place-ID gesetzt und waere danach weg. Die Reservierungsseite ist unbedenklich, weil sie ihre Felder vollstaendig sendet.

## RwG: PLACE-IDs GESETZT + DURRANI LIVE - ALLE 23 IM PROD-FEED (18:12-18:20 CEST)
- Kais gab das Go fuer den Maps-Schluessel. Aus der ECS-Aufgabendefinition gelesen, benutzt, danach mit shred von der Platte entfernt. Wert nie ausgegeben.
- 22 PLACE-IDs AUFGELOEST UND GESETZT, jede einzeln gegengeprueft. Validierung vor dem Schreiben: Treffer muss types 'establishment' tragen, Postleitzahl muss zu unserer passen, business_status OPERATIONAL. 22 von 22 sauber, NULL Zweifelsfaelle. Danach Kontrolle: Place-ID gesetzt, Telefon und Zeitzone unversehrt.

### WICHTIGSTER FUND DES TAGES: Das Formular liefert Adressen, keine Betriebe
- ALIBABAs Place-ID aus Kais' Formular war ChIJf7HYC2zOo0cRWkzw2XVcOco.
  Place Details darauf: name "Spitalgasse 25", types [street_address, subpremise]. Also die STRASSE.
- Der richtige Betriebseintrag ist ChIJq6bPbgDPo0cR-KuYaymMe20: name "ALIBABA Doener und Pizza", types [establishment, food, point_of_interest, restaurant], 36 Bewertungen, OPERATIONAL.
- Mit der Formular-ID haette Google morgen sehr wahrscheinlich "Business listing is not allowed for booking" gemeldet - genau der Fehler, den wir den ganzen Tag diagnostiziert haben. Korrigiert.
- FOLGE: Der Weg ueber die Schnittstelle mit geprueftem Betriebstreffer ist BESSER als das Formular, nicht die Notloesung. Meine urspruengliche Einschaetzung war zu vorsichtig.
- Gegenbeispiel zur Fairness: Durranis gespeicherte Place-ID war korrekt (Restaurant, 1622 Bewertungen). Das Formular macht es nicht immer falsch, aber es kann.

### Izmir und Theo nachgeschlagen (beide zurueckgestellt)
- Izmir Kebap Haus: echter Eintrag, 15 Bewertungen, OPERATIONAL, restaurant. ABER Googles eigene Adresse lautet nur "08340 Schwarzenberg" OHNE STRASSE. Sehr wahrscheinlich die Ursache fuer "not allowed for booking": ein Eintrag ohne Strassenadresse taugt nicht als Buchungsziel. Nur der Inhaber kann das im Unternehmensprofil ergaenzen.
- Grill & Doener Haus by Theo: echter Eintrag, 23 Bewertungen, OPERATIONAL, vollstaendige Adresse Brenderweg 112. Bei ihm bleibt die These "Eintrag nicht beansprucht".

### Durrani 4e22f973 eingeschaltet
- Kais lieferte die Anmeldung (aseckzai@gmail.com), abgelegt mit 600 in .secrets/durrani.env.
- IST-Zustand: googleReservations war im Datensatz GAR NICHT VORHANDEN (None), nicht nur false. Ergaenzt.
- Vollstaendiger reservation-Block gesendet, alles erhalten: autoApproveReservations enabled mit guestLimitOverall 120 / perReservation 20, defaultReservationTime 150, dashboardReservationTimeLimit 3, lastReservationTime 21:00.
- restaurant-Block unversehrt: echte Mailadresse info@restaurant-durrani.de (KEIN Alias), Telefon, korrekte Place-ID, Zeitzone.
- Kontrolle: 6 offene Tage, 13 Zeitfenster am Freitag, Gruppen bis 16 buchbar.

### STAND ENDE DES TAGES
- 23 Betriebe im Produktions-Feed: 22 heute neu angelegt und konfiguriert, 1 bestehender (Durrani) nur geschaltet.
- Naechster Feed-Lauf 05.09. 05:00 UTC. Danach Actions Center pruefen.
- OFFEN: Durrani-Dublette 22130b68 liegt abgeschaltet herum (Loeschen nur ueber die Datenbank). Sechs Produktbefunde in BEFUNDE.md fuer das Entwicklerteam. Gemeinsames Passwort kadicon123 auf 22 Produktionskonten sollte ersetzt werden.

## RwG: Speicher-Fehler behoben (PR #279) + Onboarding-Werkzeug gebaut (18:20-18:32 CEST)
- Auftrag Kais: "Die Fehler beim Speichern kannst du alles autonom verbessern" + ein sehr guter vorbereiteter Onboarding-Plan fuer neue Restaurants.

### FIX: PR https://github.com/KADiCon-UG/kadicon/pull/279
- Branch fix/settings-save-merge, auf origin/main rebased, 1 Commit. NICHT gemergt, das macht das Repo-Team.
- Aenderung: settings.service.ts save() liest die Zeile jetzt vollstaendig (select entfernt), damit die drei Merges wirken.
- TEST-DESIGN als eigene Ueberlegung: Ein reiner Verhaltenstest kann diesen Fehler NICHT fangen, weil ein gemocktes Repository das select ignoriert und die volle Entitaet liefert. Die Regression wird deshalb an der ABFRAGE geprueft. Bewiesen: vor dem Fix 1 rot / 5 gruen, nach dem Fix 6 gruen. Genau das Muster aus mutation-must-target-the-exact-defect.
- Gates lokal: npx nx lint backend gruen (43 vorbestehende Warnungen, 0 Fehler), npx nx test backend 17 Suites / 161 Tests gruen, oxfmt formatiert. Gate-Kommandos aus .github/actions/ abgeleitet, nicht geraten.
- BEFUND B7 im PR vermerkt: .github/actions/test schliesst backend aus (--exclude='infra,admin-cli,backend'). Die 161 Backend-Tests laufen in CI NIE, auch der neue nicht.
- Co-Author-Trailer wurde vom pre-tool-safety-Hook geblockt (Standing Order: VPS-Git-Author ist Kais). Ohne Trailer committet.

### WERKZEUG: /home/aria/projekte/rwg-prod-uebernahme/onboarding/
- onboard.py (drei Schritte: pruefen / mail / anlegen), zeiten.py (Parser), ANLEITUNG.md, beispiel.json.
- Eingabe: sechs Angaben je Betrieb in einer JSON-Datei. Zeiten als "Mo-Fr 11:00-22:00; Sa 12:00-23:00; So geschlossen", Tische als "4x2, 2x4, 1x6".
- Der Parser wurde gegen fuenf gute und fuenf schlechte Eingaben geprueft, alle korrekt.
- EIGENE GEGENPROBE FAND DREI LOECHER in meiner ersten Fassung:
  1. KRITISCH: "Spitalgasse 25" als Betriebsname lieferte FIELMANN an der Adresse und ging als "Alles in Ordnung" durch. Richtige PLZ, echter Betrieb, OPERATIONAL - aber der falsche Laden. Kein Namensabgleich vorhanden.
  2. Exitcode war 0, obwohl Probleme gemeldet wurden.
  3. Kaputte Tischangabe erzeugte einen Traceback statt einer Klartextmeldung.
- ALLE DREI BEHOBEN. Der Namensabgleich vergleicht Kernwoerter ohne Gattungsbegriffe (restaurant, grill, doener, ...). Gegen die 22 ECHTEN Google-Antworten von heute geprueft: 0 Falschalarme. Ein Falschalarm war zunaechst da (Amo's vs Amo's mit typografischem Apostroph), behoben durch Apostroph-Normalisierung. Fielmann-Fall und "Orient Grill vs Bozan Grill" werden erkannt.
- Die Kontrolle vor dem Einschalten laeuft jetzt ueber JEDEN geoeffneten Tag einzeln und prueft ZWEI Groessen: Zeitfenster vorhanden UND groesste Gruppe wie erwartet. Beides Lehren aus dem heutigen Durrani-Fehler.
- Grenzen ehrlich in der Anleitung: Bestaetigungsmail oeffnen, unvollstaendigen Google-Eintrag reparieren, unbeanspruchten Eintrag beanspruchen - alles nicht automatisierbar.

