// release-history

Was wir geliefert haben.

Foyer ist seit Ende April 2026 im Bau. Hier ist die vollständige Release-Liste — keine Marketing-Übertreibung, sondern Git-Tags. Datum + Version stehen für jeden Eintrag.

v0.99.26
03. August 2026

The hydration warning was a date without a timezone

    v0.99.25
    03. August 2026

    46 correction lines written: a cancelled stay now says so

      v0.99.24
      03. August 2026

      Whether a resolution reached the guest is decided by the guest side

        v0.99.23
        03. August 2026

        Airbnb's guest service fee is not a refund

          v0.99.22
          03. August 2026

          A payout of zero means nothing remains, even with a stray fee line

            v0.99.21
            03. August 2026

            The folio guard can see corrected folios again

              v0.99.20
              03. August 2026

              The recompute now writes the correction lines itself, behind a switch

                v0.99.19
                03. August 2026

                Correction lines can now be derived, and they know who owns them

                  v0.99.18
                  03. August 2026

                  A refund can finally appear on the payment side

                    v0.99.17
                    02. August 2026

                    Correction lines are visible in the folio, and only they are coloured

                      v0.99.15
                      02. August 2026

                      The test database left its disk behind, 81 times

                        v0.99.14
                        02. August 2026

                        A folio correction line can now survive the next recompute

                          v0.99.12
                          02. August 2026

                          Age only decides when the two price paths actually disagree

                            v0.99.11
                            02. August 2026

                            A backfilled price now carries its own age, not the hour it was imported

                              v0.99.10
                              02. August 2026

                              The gate skipped the only test kind that drives a browser

                              • Playwright now runs in the pre-push gate (measured 1:47 incl. DB bootstrap); before this, no browser test ran before a push and two folio specs had been red unnoticed since before the portal work.
                              • The two failing specs are marked test.fixme with the measurement rather than patched, because folio-init is mid-rework and a guessed fix would collide with it.
                              • The defect itself: the folio room-charge row's Gesamt contradicts its own Menge × Einzelpreis by 27,10 €, which is far beyond the rounding drift the code documents as acceptable.
                              • The gate's first live run exposed three flaky specs that pass in isolation, so the hook runs with --retries=2 — locally retries is 0, and a random miss would block unrelated pushes.
                              • A v0.99.3 bullet quoted a JS template-literal placeholder as prose; build-changelog.mjs copied it verbatim into the generated module and Biome flagged it. Reworded.
                              v0.99.9
                              02. August 2026

                              robots.txt and sitemap.xml belong to a host, and this app serves two

                              • The developer portal had no sitemap at all; its 96 indexable pages, including 79 generated tool-domain pages, were invisible to crawlers except by following links.
                              • robots.txt and sitemap.xml are host-aware now instead of 404'ing on the developer host, and the marketing versions are unchanged.
                              • The portal sitemap is derived from the page registry and the live tool registry, so a new doc page or tool domain appears without anyone maintaining a list.
                              • middleware.ts gained HOST_NEUTRAL_FILES for paths that exist on every host with different content — the opposite of the portal-only list, which 404s off-host.
                              • Reading the Host header makes both routes dynamic, which is correct: a cached answer would be wrong for one of the two hosts.
                              v0.99.8
                              02. August 2026

                              The itemised price is only better while it is also current

                                v0.99.7
                                02. August 2026

                                The portal now publishes itself in a form an agent can read

                                • The developer portal now serves /llms.txt and /llms-full.txt; before this there was no machine-readable entry point on the host at all.
                                • /llms-full.txt is the whole documentation set plus all 432 MCP tools in one 105 KB request — roughly 26k tokens, one round trip instead of twelve HTML pages.
                                • Markdown is a second renderer over the same typed content blocks and the same live tool registry the HTML uses, so neither file can drift from the pages.
                                • Tool schemas are deliberately excluded (~270 KB) since an MCP client gets the authoritative shape from tools/list; a test pins the file under 400 KB.
                                • Both paths had to be named in middleware.ts, because the developer host 404s any path it does not recognise as a portal path even when the route exists.
                                • A Connect Quickstart page gives the one-line client setup, explains the first 401, and states plainly that there is no sandbox hotel.
                                v0.99.6
                                02. August 2026

                                The developer portal had no CSS for the things it used most

                                • Every developer-portal doc page had rendered as unspaced text with unmarked lists since launch: Tailwind's preflight strips those globally and the portal's scoped stylesheet never restated them.
                                • The table of contents moved out of the article flow, where it sat between the intro and the first section and pushed the indexed content below the fold, into a sticky column beside it.
                                • The portal now uses the Foyer brand palette instead of a teal that appears nowhere else in the product, with links on #8E661B because the mark colour itself does not clear 4.5:1 on the page grounds.
                                • Geist, Source Serif 4 and JetBrains Mono are used directly; the root layout already self-hosts all three via next/font, so it costs no request and no CSP change.
                                • The tool reference replaced a 432-item bulleted list with 79 domain tiles, a client-side filter and per-tool badges; the listing still renders in full server-side.
                                • Tool badges corrected a real omission: read-only tools were marked while writing tools carried no indicator at all.
                                • New throughout: a header with the brand mark, a sticky sidebar with a visible active state, OS-driven dark mode, and a line stating whether a page is written or generated.
                                • An accessibility defect introduced during the work was caught by axe and removed: a closed <details> forced visible with CSS reported a collapsed disclosure while 89 links were on screen and tabbable.
                                v0.99.5
                                30. Juli 2026

                                Four claims that had nothing behind them

                                • A click on /settings/rates could flatten 2211 priced nights: a type price overwrites per-room prices; rates.upsert now blocks that once a type has more than one active room.
                                • The /work PWA manifest shipped but was missing on /work/login, a separate route group, so first-time users never saw the install prompt — fixed the same hour.
                                • The me.get MCP tool could only throw; deleting its hand-written twin uncovered the real meRouter.get it had shadowed — allTools().length staying at 432 confirmed no tool was lost.
                                • The date guard asserted its reach (>300 files, >30 sql fragments) but never its own detection, so it could report "no findings" if broken; it now self-tests all four paths.
                                • Documentation was corrected against live measurement: RLS coverage is actually 157 of 162 tables, not the documented "19 of 155 without RLS"; tool counts were updated from 411/144 to 432/156.
                                • Two Beds24 migration phases (ν and ξ) had been built without a written plan, unlike λ and μ; plans were retroactively written for both.
                                v0.99.4
                                30. Juli 2026

                                A webhook that was answered 405 before anything could log it

                                • The Beds24 booking webhook was dead for 36 hours unlogged — beds24_webhook_log held zero rows, confirmed by sync enqueues dropping from 14 on the 28th to 0 on the 30th.
                                • No booking data was lost: the 6-minute polling fallback caught all five Airbnb bookings during the outage; the only cost was latency up to ~6 minutes instead of the usual ~1 minute.
                                • Root cause: the property was configured on Beds24 webhook version 1 (a GET request with no payload), but the route only accepted POST, so Next.js answered 405 before any Foyer code ran.
                                • The route now accepts both webhook versions, mapping v1's bookid onto the same booking_id column as v2's booking.id; v1's status stays unmapped since it reflects events, not booking states.
                                v0.99.3
                                30. Juli 2026

                                Two checking tools that stopped believing their own inputs

                                • The daily-summary cron interpolated a bare Date into two raw sql fragments and threw on every run; a catch one level up swallowed it, so pg-boss recorded 192 runs, all completed, none red.
                                • Latent, not damaging: the tasks table is empty, so no summary was owed either way — the defect fires the moment tasks are used.
                                • A cast does not help. Measured against real Postgres: a bare Date throws, and a ::date cast throws too — only toISOString() with a timestamptz cast works. The v0.99.2 explanation was wrong.
                                • The same defect appeared in three waves in one day (four sites, then seven, then the cron), so a guard now scans 712 source files across five roots and names file and line.
                                • That guard's first version read only server/ and reported safety for 26 files it never opened; it now asserts how much it read, because a scanner that reads nothing always reports success.
                                • The RLS audit derives its table list by runtime introspection instead of trusting a hand-maintained one that carried 55 names against 134 tenant-scoped tables — 88 missing, 10 dead.
                                v0.99.2
                                30. Juli 2026

                                The published contract, checked against what we actually return

                                • BEHAVIOUR CHANGE: a missing entity now answers 404 with the documented JSON error shape instead of 500 with plain text.
                                • Anyone branching on 500 to detect "not found", or retrying every non-2xx as a transport failure, sees different behaviour from this release on.
                                • Two responses threw on every call: postgres.js cannot bind a bare Date interpolated into a raw sql fragment, so the tenant tool and task search answered 500 every time.
                                • Four further call sites carried the same defect and are closed too; the rule is never to interpolate a bare Date, but .toISOString() with an explicit ::timestamptz cast.
                                • tenants.lastAnchorAt was declared z.date() while the select returns a string, so the published component promised nothing at all there.
                                • getRequestBilling returned an email key the schema omitted, and additionalProperties: false made every real response violate the component clients generate parsers from.
                                • 156 read routes are now validated with ajv against the component the OpenAPI document actually publishes, at a real database — every defect above was found by that suite, not reported from outside.
                                v0.99.1
                                30. Juli 2026

                                Removal that removes, and a documented URL that 404s

                                • Removing a member now revokes access on all five paths that resolved a soft-deleted row like a live one: session, credentials sign-in, magic link, iCal feed, invite redemption.
                                • A removed member's magic link is skipped as silently as an unknown address, so removal never becomes an account-enumeration oracle.
                                • Both Auth.js provider callbacks are exported and referenced directly, so a test holds the decision instead of trusting the wiring.
                                • The arrival guide closes on the checkout day instead of 14 days after issue.
                                • The check-in token's lifetime hangs on the stay, with lost-and-found access until checkout plus ten days.
                                • The OpenAPI document's server URL no longer repeats /api/v1 — carrying it twice made all 172 documented paths 404 for every consumer.
                                v0.99.0
                                30. Juli 2026

                                Two monitors for the silence, and the channel decision in one place

                                • A confirmation watchdog runs off an allowlist of providers with a demonstrated confirmation path, because provider_acked is terminal for Beds24 and an age check would have fired on every send.
                                • Its two-hour grace period is measured rather than guessed: real readback over 14 days (n=208) is p50 0.4 min, p99 2.0 min, max 15.9 min.
                                • It alerts on share plus count instead of the first row, because 22 of 215 hospitable_api rows hang permanently for an unrelated reason that is diagnosed and deliberately untouched.
                                • A channel-invariant monitor runs daily and read-only, asking beds24OwnsStayChannel() in both directions rather than restating the cutover rule.
                                • That monitor is deliberately not gated on FOYER_BEDS24_ENABLED — a monitor sharing a kill switch with the thing it watches goes quiet exactly when the switch is the fault.
                                • The channel decision is now one pure function that returns the channel and a reason, and the reason is logged on every send.
                                • A decision table over source × ota_source × parentChannel runs without testcontainers, so a new booking source breaks the file instead of slipping through.
                                • The pre-push flake was a hardcoded 10 s port-bind timeout inside testcontainers; container start now retries once, while migrations and tests get no retry.
                                v0.98.2
                                30. Juli 2026

                                The bug poisoned its own threads, so v0.98.1 only fixed half of it

                                • Two hours after v0.98.1 went live, a Booking.com reply went out over Beds24 again: the fix was deployed and did not apply.
                                • v0.98.1 had put the ownership question in beds24Capable, which governs only the no-history case, while plain channel inheritance one line below decides as soon as a thread has any message.
                                • The already-misrouted threads each carried a beds24 row written by the bug itself, so every further send inherited it — 9 of the 111 threads, 6 with an arrival still ahead.
                                • The lesson generalises: once a channel changes intermediary, every inherited channel value is a claim about the past, not the present, and both directions need the same check.
                                • Inheritance now gates on ownership rather than capability — a booking id or an active connection changes nothing about Beds24 not serving that channel.
                                • Verified by measurement: the new Booking.com-with-a-beds24-parent case fails on v0.98.1 and passes with the fix, and an Airbnb case keeps this fix from undoing the 2026-07-28 one.
                                • The rule path is now covered positively too, driving sendDueForTenant() over a due queue row instead of arguing that it shares a function with the operator path.
                                v0.98.1
                                30. Juli 2026

                                A Beds24 booking id is not a Beds24 channel

                                • A Booking.com guest never received her check-in codes: Foyer had recorded the message as sent with a provider id, over Beds24, while the thread she reads lives at Hospitable.
                                • Nothing looked wrong because Beds24 accepts the text either way; she wrote in five hours later asking for the door code.
                                • Cause: the send path asked whether a stay has a Beds24 booking, not whether Beds24 owns its channel — and Beds24 imports every booking by design, so that question is true for every stay.
                                • Counted on production: 111 of 150 stays carrying a Beds24 id went to the wrong intermediary — 103 Booking.com and 8 of Hospitable's own reservations.
                                • Between the cutover and the fix, rule-driven sends went from 16 per day over Hospitable to 19 over Beds24.
                                • beds24OwnsStayChannel() now decides on ownership and reads the same FOYER_BEDS24_CUTOVER_CHANNELS declaration the overlap guard uses, so the Booking.com cutover stays one environment change.
                                • stays.source alone is unsafe as a discriminator: direct means Hospitable's booking portal under one ota_source and Beds24's direct channel under the other.
                                • Undeclared channels fall back to Hospitable, which fails loudly — this bug survived five days because the wrong route failed silently.
                                v0.98.0
                                28. Juli 2026

                                Foyer shows its own numbers, and shows the tax it contains

                                • The booking panel no longer mirrors the channel's tax block: it showed "Servicegebühr 6,00 €" where 48,00 € accommodation tax belonged, which reads as a wrong invoice rather than a finding.
                                • The channel's arrangement is kept — per-night breakdown, fee sub-lines, payment row — because that is information Foyer does not have and it is correct.
                                • The divergence was explained rather than lived with: Foyer's derived accommodation differed from the channel's on 3806 of 5878 bookings, by up to 1981 €.
                                • 1878 of those are the channel reporting no VAT line at all, so its "Accommodation" is gross where Foyer's is net — a different quantity, not an error.
                                • The rest is a documented misconfiguration at full scale: the channel charges 6,00 € per night flat, Foyer 3,00 € per adult per night, and the two agree only when two adults travel.
                                • Because this hotel's bookings are mostly couples it stayed invisible for years; 1179 bookings had fewer adults, 415 more, and two competing hypotheses died on the measurement.
                                • The investigation caught a defect in the change itself: on 3750 of 5822 bookings accommodation plus taxes no longer summed to the total, now fixed and verified 5822 of 5822.
                                • The folio now shows the VAT each line contains, and its summary is split by rate instead of lumping net accommodation together with tax-free accommodation tax.
                                v0.97.0
                                28. Juli 2026

                                Airbnb runs on Beds24. Live, and it cost eight bugs.

                                • The booking webhook rejected its own correct secret. getTenantSecret
                                • The first real booking pull created 100 duplicate stays. It recognised a
                                • The pull read the first page and called the run complete. 100 of 133
                                • A conversation opened before its stay existed stayed orphaned forever.
                                • Bookings that did not come from Beds24 were invisible to it. A Booking.com
                                • …and that fix duplicated all 30 Airbnb bookings on its first run, because
                                • **A reply to an Airbnb guest failed with hospitable_send_failed on 31
                                • Every Beds24 thread answered 404. The route never decoded its URL segment,
                                v0.96.0
                                27. Juli 2026

                                Beds24: the channel manager we will actually switch on

                                • The calendar is range-based. {from, to} instead of one entry per date:
                                • Prices go in currency units, not cents. Beds24 takes 129, not 12900 —
                                • price1 and only price1. priceN is the value for price rule N, not
                                • numAvail is derived and silently discarded. A POST carrying it answers
                                • Price is the gate to bookability. The operator panel reports "no price
                                • Stop sell is called override. There is no stopSell field, which is why
                                • A block is a booking. blocked_dates hangs off a single Foyer room while
                                • The refresh token dies after 30 days unused, without notice; bookings
                                v0.95.0
                                27. Juli 2026

                                Channex: certification-ready, deliberately inert

                                • The full Channex integration — connection, mapping, ARI push, sync, booking ingest — shipped behind FOYER_CHANNEX_ENABLED (off); Foyer keeps running on Hospitable, unchanged.
                                • With the flag unset, the Channex path costs nothing: no queue rows, no extra SQL, no registered worker, and the inbound webhook answers 404 without even looking up the tenant.
                                • Migration 0169 adds channex_connections and channex_mappings; migration 0170 adds channex_booking_revisions, since Channex uses its own UUIDs instead of reusing ota_connections.
                                • The pg-boss worker batches a change across several rate plans, room types, or dates into at most two API calls per property, matching Channex's limit of 10 requests/minute per property/endpoint.
                                • Restrictions (stop sell, CTA/CTD, min/max stay) never reached any channel — a gap also affecting Booking.com/Expedia — and the editor UI was fixed so CTA/CTD and max stay can be set.
                                • The tool registry grew from 411 to 422 (the channex router bridges 10 of its 11 procedures), with 2 new migrations, 0 RLS violations, and 2146 unit tests passing.
                                v0.94.0
                                26. Juli 2026

                                MCP tool schemas: the documented surface finally has types

                                • 77 new /connect/tools/{domain} pages render each tool's input parameters and output fields as tables.
                                • Pre-existing bug found on the way: [product]/[slug]'s generateStaticParams mapped every registry page.
                                • Output schemas declared for 193 tRPC procedures across 16 routers — documentable tools go from 103 to 342 of 411.
                                • The REST read surface grows 103 → 144 paths, and 41 of those were redeemed, not invented.
                                • Three migrations close the RLS thread — production RLS coverage is now 150 of 155 tables.
                                • The e2e suite works again — 45 passed, 6 skipped, 0 failed.
                                • Two Dependabot alerts closed, one of them by dismissal with written reopen conditions.
                                • Every portal page now sets its own title and canonical — before this the portal had exactly one indexable page.
                                v0.93.0
                                26. Juli 2026

                                The Public API becomes a read API: 7 endpoints → 99

                                • assistant.ask was flagged read-only but calls Anthropic and writes to llm_daily_spend, so the GET billed the tenant on every call — and a read-only MCP key could spend the tenant's AI budget.
                                • messaging-rules.preview-queue-item claimed "no row writes", but previewing a template that uses %checkin_url% minted a guest-facing check-in credential as a side effect of a GET.
                                • agents.proposals.list runs a lazy-expiry UPDATE on agent_proposals before it selects, so the list endpoint wrote rows.
                                • Every portal page now sets its own title and canonical. The layout carried canonical: "/", which Next merges downward, so all 12 doc pages declared themselves duplicates of the hub.
                                • /icon.svg and the social images stopped 404ing on the developer host; robots.txt and sitemap.xml deliberately still do.
                                • First unit tests for middleware.ts (matcher regex + host routing).
                                • checkin.get_meldeschein gained a real discriminated-union response schema, enumerated from the two backing tables and asserted against getTableColumns.
                                v0.92.0
                                26. Juli 2026

                                The member lifecycle is fully audited

                                • Creating, removing, and inviting a team member left no real audit trail (removal only set deleted_at, invite only invite_sent_at); these now write member.created/removed/invited events.
                                • The audit logic was consolidated into one module, server/members/audit.ts, since the two rights-change write paths had drifted apart once, and creation paths still duplicate inserts.
                                • A removal record now captures the role held at removal time, showing what they could actually reach, not just that they're gone; repeat invites accumulate instead of overwriting.
                                v0.91.0
                                26. Juli 2026

                                Developer portal (developer.getfoyer.app)

                                • A dedicated developer portal was built at developer.getfoyer.app, with a hub page and two products — Public API (REST /api/v1) and Connect (MCP, OAuth) — each with Overview and Reference pages.
                                • The portal uses host-based routing via apps/web/middleware.ts (the repo's first), serving only when the Host header matches DEVELOPER_HOST; every other host gets a 404 instead of a redirect.
                                • Content is written as typed TS modules rather than MDX, since no markdown renderer exists in the repo and MDX would hit the same dynamic-readFile trap that made v0.66.13 move email templates off .md.
                                • The tool reference page is generated from allTools() with a drift test checking it matches the registry; it imports the tools barrel so side effects run first, avoiding a vacuous "0 tools" pass.
                                • The portal carries a strict CSP (connect-src 'self', no third-party hosts); the Plausible component is now host-gated so zero third-party requests happen by construction.
                                v0.90.0
                                26. Juli 2026

                                The `settings` catch-all is split; team rights stop wiping themselves

                                • /properties, /direct, and config shared one permission key (settings), so property visibility also handed out API keys and user management — how Tenant#1's receptionist opened the user list.
                                • Übergabe (/handover) had no server guard under the always-on overview catch-all and could not be revoked; it now has a guard and its own permission, preserving everyone's access.
                                • The rights grid checkbox labelled "Tür öffnen" (smart_locks) had actually covered the entire Geräte/Devices section since v0.81.0 and is now correctly labelled "Geräte" / "Devices".
                                • Rights changes via members.update and team.update now write a member.rights_changed audit entry with before/after role and modules, closing a silent-reset gap in team.update.
                                • members.list was reachable by any logged-in role despite exposing every colleague's personal data and module rights; it's now gated by moduleProcedure("team") to match the page-level guard.
                                • team.update reset a member's module_permissions to the role default whenever role appeared in the patch (always present in the form), silently wiping custom rights; it resets only on role change.
                                v0.89.0
                                26. Juli 2026

                                Test gate repaired, 26 security alerts closed, two guest-facing fixes

                                • WCAG AA contrast in the arrival guide. Labels measured 2.58, 3.51 and
                                • An Anthropic hiccup no longer breaks guest ID-OCR.
                                v0.88.0
                                22. Juli 2026

                                Per-tenant MCP-OAuth re-auth interval

                                • Tenants can now configure a per-tenant interval forcing connected AI agents to re-authorize on a schedule, via migration 0167's tenants.mcp_reauth_hours (default 24; 0/24/168/720, 0 = off).
                                • The interval anchors on the last interactive login, not the last token refresh, since silent refresh must not extend the clock; verifyBearer rejects with 401 once the login is too old.
                                • Because oidc-provider's ttl callbacks are synchronous while tenant resolution needs an async DB call, enforcement moved into bearer.ts; the global TTL ceiling moved from 14 to 30 days.
                                • Settings → API-Keys gained an owner-only dropdown (off / daily 24h / weekly 7 days / monthly 30 days) plus per-grant "last authorized" and "re-auth due" indicators, in German and English.
                                • No new MCP tool was added (registry stays at 411) since config stays Web-UI-only; the 24-hour default means every OAuth MCP session older than 24 hours re-authorizes once after deploy.
                                v0.87.0
                                21. Juli 2026

                                MCP per-key role/module scoping

                                • Api-keys tragen jetzt zusätzlich zum full/read_only-Scope eine role (owner/staff/reception/housekeeping/maintenance) und ein optionales Modul-Override, analog zum granularen Nutzer-Rechtesystem.
                                • Migration 0164 fügt api_keys.role (DEFAULT 'owner') und api_keys.module_permissions rein additiv hinzu, sodass jeder bestehende Key weiterhin vollen Zugriff behält.
                                • Die Durchsetzung erfolgt über effectiveModules() und toolVisibleToKey() in tools-adapter.ts, das tools/list/tools/call gated; runWithKeyScope(...) lässt tRPC-Prozeduren mit FORBIDDEN antworten.
                                • Da die meisten operativen Router wie folio ungegatetes protectedProcedure sind, bleibt die Sichtbarkeitsprüfung die eigentliche Sicherheitsgrenze.
                                • Owner-Rollen-Keys und OAuth-Clients behalten unveränderten vollen Zugriff; die Registry bleibt bei 411 Tools, es wurden keine Tools hinzugefügt oder entfernt.
                                • Ein adversariales Review führte zum Fix, dass auch hand-geschriebene Tools ihr Modul über moduleForToolName auflösen; der neue Test key-scoping.int.test.ts deckt Sichtbarkeit und Durchsetzung ab.
                                v0.86.1
                                21. Juli 2026

                                Inbound Auto-Reply Hardening (pre-deploy)

                                • Neues ENV-Flag FOYER_INBOUND_NATIVE_AUTOSEND (default OFF): der native L1a-Pfad schreibt eine Antwort als Draft statt sie zu senden; Auto-Send greift erst mit tenant.aiMode="auto".
                                • detect-invoice-request.ts unterscheidet jetzt eindeutige Signalwörter (invoice/rechnung/quittung/factura) von mehrdeutigen Tokens (bill/receipt/beleg), die nur mit Request-Intent-Kontext matchen.
                                • Migration 0163 fügt die Spalte invoice_form_submissions.source sowie einen partial unique index hinzu, damit createInvoiceRequest garantiert nur eine Row pro Aufenthalt erzeugt.
                                • Der Divergenz-Report zeigt jetzt Stichprobengröße, vergleichbare Zeilen, noCcData und die Divergenzrate über die vergleichbaren Zeilen, um die Repräsentativität vor dem Cutover zu prüfen.
                                v0.86.0
                                21. Juli 2026

                                Native Inbound Auto-Reply Engine

                                • Foyer beantwortet eingehende Gast-Nachrichten nun nativ statt per Proxy über das Command-Center (hospitable_backend:4550).
                                • Neue Komponenten: ai_question_replies als Idempotenz-Ledger gegen Doppelantworten, ai_shadow_decisions für Parallel-Logging, sowie zwei Felder für native Rechnungsanfrage-Erkennung.
                                • Der neue L1b Invoice-Sentinel antwortet mit einem Link auf Foyers eigenes Gäste-Rechnungsformular statt auf das CC-Formular.
                                • Zwei ENV-Flags, standardmäßig aus: FOYER_INBOUND_NATIVE_SHADOW loggt Divergenzen zwischen nativer und CC-Antwort ohne zu senden, FOYER_INBOUND_NATIVE schaltet den CC-Proxy-Pfad ab.
                                • Ein Backfill-Skript (backfill-cc-inbound.ts) importierte einmalig 24 Fragen und 92 Codes/Fakten für Doerenkamp; Migration 0162 legt die neuen Tabellen/Spalten additiv mit FORCE RLS an.
                                v0.85.0
                                21. Juli 2026

                                tRPC→MCP Auto-Bridge (Registry 203 → 428)

                                • Eine neue Bridge (trpc-bridge.ts) durchläuft bei jedem Boot appRouter._def.procedures und registriert ein MCP-Tool pro Prozedur, außer 5 denylistete und ~96 hand-geschriebene.
                                • Bridged-Tool-Namen entsprechen dem wörtlichen tRPC-Pfad (z. B. folio.addLine); 20 destruktive P1-Prozeduren erhalten kuratierte Beschreibungen und requiresConfirmation in bridge-metadata.ts.
                                • Ein adversariales Review deckte auf, dass die Default-ALLOW-Bridge sensible owner-only Prozeduren re-exponiert hatte; der Fix schließt 6 sensible Router per Default-Deny komplett aus.
                                • Die Registry wächst auf 203 hand-kuratierte plus 225 auto-gebrückte Tools, insgesamt 428 (nach Härtung wurden 42 sensible auto-gebrückte Tools von ursprünglich 470 beim Launch wieder entfernt).
                                v0.84.0
                                21. Juli 2026

                                RBAC-Härtung, ADRs & Aufräumen

                                • 10 weitere Router (u. a. security.ts, voice.ts, hotel-facts.ts, upsell.ts, tax-settings.ts, properties.ts) sind jetzt auf moduleProcedure gegatet statt auf ungegatetem protectedProcedure.
                                • Die tote NAV_MODULE_MAP wurde entfernt und team.update resettet module_permissions bei einem Rollenwechsel jetzt auf null, damit ein alter Override keine Rechte durchleaken kann.
                                • 3-spaltige Formular-Reihen in team-form und im invoices-request-panel stacken jetzt mobil (grid-cols-1/2 sm:grid-cols-3).
                                • Eine Untersuchung ergab: das Pricing-Casing ist kein funktionaler Bug, da der Read-Pfad Zeilen normalisiert; ein Backfill der ~57.000 Zeilen hätte 1.644 Kollisionen erzeugt, blieb bewusst aus.
                                • Zwei ADRs wurden nachgezogen (granular-module-permissions, operator-ui-i18n); Schema, Migrationen und die MCP-Registry (203 Tools) blieben unverändert.
                                v0.83.0
                                21. Juli 2026

                                i18n-Feinschliff, Settings-Reorg & Mobile-Politur

                                • Der DE/EN-Sprachumschalter zog von der Nav-Fußzeile auf eine eigene Seite Einstellungen → Sprachen (/settings/languages) um.
                                • Aus der Hospitable-Struktur übernommene englische Nav-Labels wurden eingedeutscht, etwa Properties→Objekte, Metrics→Kennzahlen, Direct bookings→Direktbuchungen, Devices→Geräte und Channels→Kanäle.
                                • Die Settings-Navigation wurde von zwei widersprüchlichen Navigationen auf eine Quelle vereinheitlicht, gruppiert in 4 Themen: Konto, Hotel & Inhalte, Preise & Abrechnung, Technik & Integrationen.
                                • Die KI-Antworten-Liste unter Einstellungen → KI zeigt jetzt nur noch echte KI-Antworten (aiLayer in llm/escalated) statt auch Regel-Automatik-Sends.
                                • Ein Mobile-Audit stellte die Messaging-Tab-Leiste unter /gx/messaging auf ein Dropdown um und prüfte alle 28 Operator-Tabellen und Tab-Leisten auf Overflow.
                                • Ein vorbestehender hospitable-send-message-Shape-Drift wurde korrigiert, die Unit-Suite steht danach bei 1809 grün / 0 rot.
                                v0.82.0
                                20. Juli 2026

                                Operator-UI zweisprachig (DE/EN)

                                • Die gesamte Operator-Oberfläche ist jetzt pro Benutzer auf Deutsch oder Englisch umschaltbar, umgesetzt über eine echte i18n-Schicht mit next-intl ohne URL-Präfixe.
                                • Der Umfang beträgt rund 2.900 Übersetzungs-Keys über 19 Namespaces, verteilt auf rund 150 Seiten- und Komponenten-Dateien.
                                • Die Umsetzung erfolgte in Wellen: Fundament und Nav zuerst sequenziell, danach Seiten-Cluster teils sequenziell, teils parallel mit 5 Agenten auf disjunkten Datei-Partitionen.
                                • Die Verifikation umfasste einen grünen Prod-Build über 109 Seiten, 0 tsc-Source-Fehler, einen grünen i18n-Katalog-Test sowie 1807 grüne Unit-Tests und 0 RLS-Violations.
                                • Bekannt blieben 2 vorbestehende hospitable-send-message-Testfehler, die unabhängig von der i18n-Umstellung sind.
                                v0.81.0
                                20. Juli 2026

                                Nav-Hospitable-Gruppierung

                                • Neue Gruppe „Gäste-Erlebnis" (Guest experience) bündelt Auto-Nachrichten,
                                • Properties, Metrics, Direct bookings und Devices als eigene
                                • Metrics (Berichte/Belegung) getrennt von Finanzen (Kassenbuch/Rechnungen/
                                v0.80.0
                                20. Juli 2026

                                Hospitable-URL-Parität (echtes Rename)

                                • Alle Alt-Pfade bleiben als 307-Redirect (permanent: false) erreichbar — Bookmarks/externe
                                • Guard-Erhalt: jede verschobene Settings-Seite behält requireModule("settings") am neuen
                                • Sidebar/Mobile-Nav (components/operator-nav.ts), NAV_MODULE_MAP
                                v0.79.2
                                20. Juli 2026

                                URL-Parität: /settings/user-management (Hospitable)

                                • Die Team-/Rechte-Verwaltung liegt jetzt unter /settings/user-management (spiegelt
                                v0.79.1
                                20. Juli 2026

                                Rechte-System-Follow-up: Team-Roster-Overexposure geschlossen

                                • team.list/team.byId (voller Roster inkl. Telefon/E-Mail/Gehalt) jetzt hinter
                                • Neuer schlanker team.listForRecipients (nur id/name/email/phone/role, keine
                                v0.79.0
                                20. Juli 2026

                                Granulares Rechte-System (Hospitable-Style User-Management)

                                • 5. Rolle reception + users.module_permissions: Migration 0161 fügt den Enum-Wert
                                • Nav gefiltert: Sidebar, MobileNav und Command-Palette zeigen nur noch die effektiven
                                • Server-Guards, nicht die Nav, sind der Sicherheitsanker: neues requireModule()
                                • Team-Rechte-UI unter Einstellungen → Mitglieder: pro User Rolle + Modul-Checkboxen im
                                • Abwärtskompatibel: additive Migration (neuer Enum-Wert + nullable Spalte) — bestehender
                                v0.78.0
                                20. Juli 2026

                                Inbox-Seitenpanels (Hospitable-Parität)

                                • 3-Spalten-Layout: Die Konversationsansicht bekommt links eine Reservierungs-
                                • Datenquelle: neuer read-only Endpoint stays.bookingPanel (+ MCP-Twin
                                • Echter Bug gefangen & gefixt: hospitable_pricing_lines führt zwei Casing-Ären
                                • Registry: stays.booking-panel ist Tool 202 (allTools().length), Registry
                                v0.77.9
                                20. Juli 2026

                                Sprachwahl: BCP-47-Normalisierung + EN-Fallback für fremdsprachige Gäste

                                • Fund (Nacht-Doubletten-Analyse): Ali (en-us) und Pablo (es) bekamen die deutsche
                                • Fix: OTA-Locales werden auf die Basissprache normalisiert (en-US/de_AT → en/de);
                                • Re-Audit nach v0.77.8: alle 10 gespiegelten Templates rendern mit 0 unaufgelösten
                                v0.77.8
                                20. Juli 2026

                                Hospitable-Template-Audit: Short-Code-Parität + Doubletten-Stopp

                                • Audit-Fund 1 (kritisch): Hospitables EIGENE Rule-Engine war nie abgeschaltet — die
                                • Audit-Fund 2: 9 Hospitable-Short-Codes fehlten als Foyer-Builtins und blieben roh
                                • Datenfixe: 1nightstay trägt seine Hospitable-Condition (x_nights=1 → nights 1..1);
                                v0.77.7
                                20. Juli 2026

                                Willkommensnachricht: Last-Minute-Block korrekt gegated (Fund: Ali Abdi)

                                • Bug: Die erste Foyer-Willkommensnachricht enthielt den kompletten Last-Minute-
                                • Fix: Neuer Condition-Typ check_in_hours (Migration 0160, Hospitable-Semantik
                                • Datenfix: die 4 Doerenkamp-Codes (NOTlastminutecheckin* → > 1 h,
                                v0.77.6
                                20. Juli 2026

                                Hospitable-Schema-Alignment (additiv)

                                • Analyse: Alle 22 Hospitable-Public-API-Schemas gegen Foyers DB abgeglichen
                                • 3 Migrationen (0157–0159): stays.booking_date/issue_alert/stay_type/notes
                                • Follow-up: GuestReview (Host→Gast-Bewertungen) als einziges echtes
                                v0.77.0
                                19. Juli 2026

                                Türen-Modell: beliebig viele Türen, jeder Provider

                                • Multi-Door: Neue doors-Tabelle (Migration 0156, RLS+FORCE) — Tenants legen beliebig viele
                                • Provider-Registry: DoorProvider-Contract (hasAccount/listLocks/unlock) — Provider #3 ist
                                • UI: Eine vereinheitlichte Oberfläche — kompakte Provider-Konten-Karte + Türen-Karte
                                • MCP: smart-locks.unlock mit optionalem doorId + neuer readOnly-Twin smart-locks.doors
                                v0.77.5
                                19. Juli 2026

                                Guide-Video: selbst gehostet, Embed-Block behoben

                                • Fund: Das Keybox-Video blockte im In-Page-Player („Wiedergabe auf anderen Websites
                                • Gleiche Lösung: Video-Modal spielt direkte Dateien (mp4/webm/mov) jetzt im nativen
                                v0.77.4
                                19. Juli 2026

                                Guide-Hilfevideo spielt im Guide ab (kein Tab-Wechsel)

                                • „Hilfevideo ansehen" öffnet jetzt ein In-Page-Modal mit eingebettetem Player
                                • CSP: frame-src um youtube-nocookie.com erweitert (Privacy-Embed, keine
                                v0.77.3
                                19. Juli 2026

                                Anreise-Guide in 7 Sprachen (CC-Parität)

                                • Sprachumschalter jetzt EN/DE/ES/FR/NL/TR/IT — exakt die Sprachen des CC-Checkin-Guides;
                                • Doerenkamp: Schritt-Texte (Eingang, Keybox, Hausregeln) + „Klemmt?"-Hilfetext in den
                                v0.77.2
                                19. Juli 2026

                                Anreise-Guide: Hilfetext pro Schritt unter „Klappt nicht?"

                                • Neues Feld helpTranslations pro Guide-Schritt (DE/EN, Settings-UI + tRPC + MCP-Twin):
                                • Doerenkamp Schritt „Zimmer betreten": „Klemmt? Ziehen Sie die Tür leicht zu sich,
                                v0.77.1
                                19. Juli 2026

                                Anreise-Guide: Hilfevideo als Button + Keybox-Video verlinkt

                                • Der Video-Link im Guide-Schritt war ein kaum sichtbarer unterstrichener Textlink —
                                • Doerenkamp: Keybox-Hilfevideo (YouTube-Short, CC-Parität) auf Schritt 4 hinterlegt
                                v0.76.7
                                19. Juli 2026

                                Zimmertausch: bewusste Doppelbelegung möglich

                                • „Zimmer tauschen"-Modus: Ein Drop auf ein bereits belegtes Zimmer ist kein harter
                                • Server: allowConflict-Flag auf stays.setRoomOverride (tRPC + MCP-Twin
                                v0.76.6
                                19. Juli 2026

                                Verlauf: keine Duplikate mehr für Foyer-gesendete Nachrichten

                                • Root-Cause (Fund: Melanie Asche doppelt im Verlauf): Beim API-Versand gibt Hospitable
                                • Fix (Migration 0156): messages.sent_reference_id — Versand speichert die Quittung,
                                • Diagnose-Beifang: failure_reason trägt jetzt den HTTP-Status
                                v0.76.5
                                19. Juli 2026

                                Abgelaufene Anfragen: wahrheitsgemäßer Status statt ewig „Ausstehend"

                                • Status-Mapping vervollständigt: Hospitable pusht tote Anfrage-Zustände (expired,
                                • Neue Spalte stays.ota_status (Migration 0155): der rohe Hospitable-Status bleibt
                                • Backfill prod: historische Stays aus den Webhook-Rohevents + der CC-Wahrheit nachgetragen.
                                v0.76.4
                                19. Juli 2026

                                Messaging zielt nie mehr auf Pending/Storniert (HOST-0LRKYX)

                                • Root-Cause-Fix (Fund: HOST-0LRKYX, abgelaufener Request-to-Book): Abgelaufene
                                • Datenbereinigung prod: 53 tote Pending-Stays (27 NotAccepted, 3 Checkpoint, 23 nicht mehr
                                • 2 neue Integrationstests: Scheduler materialisiert nie für pending/cancelled;
                                v0.76.3
                                19. Juli 2026

                                Ausstehend: Sprache, Plattform-Badge, Sofort-Senden (CC-Parität)

                                • Sprache-Spalte zeigt jetzt die Gast-Sprache (guests.locale) statt „—" (der Sende-Hint
                                • „Kanal" → „Plattform": Badge mit OTA-Plattform (Booking.com/Airbnb/Direkt/Manuell)
                                • Pro-Zeile „Senden": geplante Nachricht sofort ausliefern (confirm-gated) — identischer
                                v0.76.2
                                19. Juli 2026

                                Multi-Room-HPR-Fix: alle Zimmer einer Buchung verlinkt

                                • Root-Cause-Fix (Fund: Buchung 5502217272, 3 Zimmer, nur 1 verlinkt): Hospitable liefert
                                • Coverage-Guard-Doku korrigiert (partielle Lücken waren real, nicht nur all-or-nothing).
                                v0.76.1
                                19. Juli 2026

                                Ausstehend: Live-Vorschau + chronologische Sortierung

                                • Live-Vorschau im Ausstehend-Tab: Aufklappen einer geplanten Nachricht rendert sie on-demand
                                • „Geplant"-Liste sortiert jetzt aufsteigend (nächste Sendung oben).
                                v0.76.0
                                19. Juli 2026

                                Zimmertausch per Drag & Drop

                                • Dritter Kalender-Modus „Zimmer tauschen": Buchungs-Balken vertikal auf eine andere
                                • Override-Ebene stay_room_overrides (Migration 0154): schreibt NIE stays.room —
                                • Automatische Propagation in Check-in-Nachricht (Keybox-Codes), Anreise-Guide und
                                • Belegungs-Konflikt-Check beim Tausch inkl. offener Buchungen (NULL checkOut) und
                                • Audit-Log für jeden Tausch (rooms.swapped) und jeden Reset (rooms.swap_reset).
                                • MCP 195→198 (stays.set-room-override / stays.reset-room-override /
                                • Bekannte Grenzen (Follow-ups): Smart-Lock-PINs werden bei einem Tausch nach dem
                                v0.75.2
                                19. Juli 2026

                                Anreise-Guide Critical Fixes (Design-Audit)

                                • Tote Zone weg: Buttons folgen dem Inhalt statt ans Viewport-Ende gepinnt zu sein —
                                • Sperrsatz nur noch für Ziffern-Codes — SSID/Passwort brechen nicht mehr pro Zeichen um.
                                • Motion: 150-ms-Fade beim Schrittwechsel (guide-fade-Keyframes), active:scale-[0.97]
                                • Karten-Embed bewusst NICHT umgesetzt (Google-iframe = DSGVO/CSP-Rückschritt nach v0.74.0
                                v0.75.1
                                19. Juli 2026

                                Anreise-Guide Quick-Wins (Design-Audit)

                                • Guide-Polish: Hotelname als Absender im Kopf (neben Sprachwahl), Schritt-Zähler „2/7"
                                v0.75.0
                                19. Juli 2026

                                Anreise-Guide (CC Checkin-Guide-Parität)

                                • Gäste-öffentlicher Anreise-Guide: 7-Schritte-Walkthrough unter /check-in/<token>/guide
                                • Zeitfenster-gesteuerte Code-Herausgabe (serverseitig): Eingangs- und Keybox-Codes sowie
                                • Migration 0153: arrival_guide_settings (JSONB auf tenants) — Adresse, Code-Namen,
                                • Operator-Settings /settings/guide: Konfiguration aller 7 Schritte inkl. Foto-Upload
                                • %guide_url%-Template-Variable: Messaging-Templates können den Guide-Link jetzt direkt
                                • MCP 194→195 (tenants.update-arrival-guide-settings, owner-only, wholesale-replace der
                                • Bugfix: Subject-Clobber bei der checkin/guide-URL-Token-Erkennung in eingehenden
                                v0.74.0
                                19. Juli 2026

                                Rechtliches: AGB-Seite + Scalar self-hosted (DSGVO)

                                • AGB: Neue Seite /agb — vollständige B2B-SaaS-AGB (§ 1 Geltungsbereich bis § 12
                                • Scalar self-hosted: Beide API-Referenzen (/developers/reference + Hono-Route) laden das
                                v0.73.2
                                19. Juli 2026

                                Verlauf: „Alle" zeigt jetzt wirklich alles

                                • Verlauf-Quell-Filter: „Alle (außer Manual)" → „Alle" — manuelle Host-Nachrichten sind
                                v0.73.1
                                19. Juli 2026

                                Mobile: Messaging-KPI-Kacheln kompakt

                                • Ausstehend/Verlauf mobil: Die Stat-Kacheln (Gesendet/Zugestellt/Fehlerquote/Morgen
                                v0.73.0
                                19. Juli 2026

                                TTLock als zweiter Smart-Lock-Provider

                                • Gast-PINs: TTLock-Schlösser (Cloud-API + Gateway) als per-Zimmer-Lock-Typ — Check-in erzeugt
                                • Haupttür: „Tür öffnen"-Knopf unterstützt TTLock (ttlock_configs, Migration 0152, RLS+FORCE);
                                • Sicherheit: TTLock-Passwort wird vor der Verschlüsselung MD5-gehasht — Klartext wird nie
                                • MCP-Registry unverändert bei 194 — smart-locks.unlock ist jetzt provider-agnostisch
                                v0.72.0
                                19. Juli 2026

                                Messaging CC-Parity: Scheduler-Fixes, Warteschlange, Verlauf

                                • Scheduler-Fixes: platform_filter einer Regel wurde gespeichert, aber nie
                                • KI-Auto-Reply-Unterdrückung: wenn bereits eine echte Host-Antwort auf eine
                                • acceptDraft flip+deliver: Annahme eines Drafts flippt jetzt UND liefert
                                • Warteschlange-Tab (Ausstehend): Status-Filter, Zeit-Bearbeitung pro Instanz,
                                • Verlauf-Tab: Hospitable-Host-Nachrichten-Historie mit Quellen-Attribution
                                • MCP-Registry 193→194 (messaging-rules.host-history).
                                v0.71.0
                                15. Juli 2026

                                Legal-Compliance + Gäste-Portal WCAG 2.1 AA

                                • Rechtstext-Fixes: Impressum § … TMG → § … DDG (Anbieterkennzeichnung §5 DDG,
                                • Geteilter LegalFooter (Impressum/Datenschutz/Barrierefreiheit) jetzt im
                                • Gäste-Portal WCAG 2.1 AA (Check-in-Wizard, app/check-in/[token]/):
                                • Sichtbare :focus-visible-Ringe auf allen Buttons/Primitiven; Labels bleiben
                                • role="group" + aria-label am Fortschritts-Header (Schritt-X-von-Y), role="alert"
                                • Skip-to-content-Link + Fokus-Management bei Step-Wechsel (Fokus wandert bei
                                • aria-live (polite) für den Submit-Status.
                                • Tastaturbedienbare Unterschrift-Alternative (WCAG 2.1.1): „Namen tippen statt
                                v0.70.5
                                11. Juli 2026

                                Mobile-Audit Wave C: Formulare stacken + Kapazität 2-up

                                • Datenerfassungs-Formulare stacken mobil einspaltig (grid-cols-1 sm:grid-cols-2):
                                • Property-Kapazität als 2×2 mobil (grid-cols-2 sm:grid-cols-4): die vier
                                • Aufgaben-H1 mobil text-2xl→text-xl (sm:text-2xl) — schließt die letzte
                                v0.70.4
                                11. Juli 2026

                                Mobile-Audit-Fixes: Pagination + Overflow + Header-Wrap

                                • „Mehr laden"-Pagination auf Reservierungen, Check-ins und Anrufen:
                                • Server-Listen-Ceilings angehoben (nur max, Defaults unverändert):
                                • Reservierungen mobil: Spalten Check-out + Kanal per sm:table-cell ausgeblendet
                                • Overflow-Fixes: /inbox/unconfirmed schnitt die Aktions-/Bestätigen-Spalte ab
                                • Konversations-Header bricht jetzt um (flex-wrap + truncate auf H1) statt die
                                v0.70.3
                                11. Juli 2026

                                Mobile-Density-Pass + mobiler Tür-Button

                                • Kennzahlen als 2-up-Zeilenraster (Übersicht, Belegungsanalyse, KI-Analytics):
                                • Global: alle 18 Seiten-H1s mobil text-3xl→text-xl (Titel steht ohnehin in der
                                • Tabellen (Reservierungen, Zimmertyp-Aufschlüsselung, Check-ins, Anrufe):
                                • Listen & Details: Heute/Übergabe-Abstände halbiert, Übergabe-„Lage jetzt" mit
                                • Tür-Button mobil: der Nuki-„Tür öffnen"-Knopf (v0.70.2) auch im mobilen
                                • Fix: TRPCProvider umschließt jetzt die ganze Operator-Shell — der Sidebar-
                                v0.70.2
                                10. Juli 2026

                                Nuki „Tür öffnen" (Cloud, manueller Remote-Unlock)

                                • BYOK: Nuki Web API Token pro Tenant, AES-256-GCM-verschlüsselt (nuki_web_configs,
                                • Setup (Einstellungen → Smart-Locks → „Nuki — Tür öffnen"): Token einfügen →
                                • „Tür öffnen"-Knopf (Tür-Icon) — in der Desktop-Seitenleiste und im mobilen
                                • MCP-Twin smart-locks.unlock (owner, requiresConfirmation). Registry inkl. dem
                                • Foyers Bridge-Adapter (per-Zimmer-Keypad-Codes) bleibt unangetastet — separater
                                v0.70.1
                                10. Juli 2026

                                Property-Detailseite ausgebaut + URL-Parität-Follow-ups

                                • Kapazität — Schlafzimmer / Bäder / Betten / max. Gäste (aus
                                • Ausstattung — Amenity-Chips (hospitable_property_amenities → hospitable_amenities).
                                • Preise & Verfügbarkeit — Summary aus dem Hospitable-Kalender
                                • Hausregeln — Rauchen / Haustiere / Events erlaubt-Badges (aus
                                v0.70.0
                                10. Juli 2026

                                Hospitable-URL-Parität: Reservierungen-Rename, Gäste- & Property-Routen

                                • „Aufenthalte" wurde durchgängig in „Reservierungen" umbenannt (Nav plus rund 17 weitere Textstellen) und die Buchungsliste liegt jetzt unter /reservations, mit Redirect von /stays.
                                • Eine neue Detail-Route /reservations/<external_ref> löst die Hospitable-CC-UUID tenant-scoped auf den zugehörigen Stay auf.
                                • Gäste sind erstmals unter /guests/<id> adressierbar, mit geteiltem <GuestDetail>-Component, neuer Query getGuestById, tRPC contacts.guests.byId und MCP-Twin contacts.guest.
                                • Hospitable-Properties sind unter /properties/<property_uuid> adressierbar, mit neuer Query getPropertyByUuid, tRPC properties.byUuid und MCP-Twin properties.get.
                                • Die MCP-Tool-Registry wuchs im Zuge dieser drei Bausteine von 181 auf 183 Tools; die Umsetzung erfolgte als checkpointed Subagent-Wave über 8 Tasks ohne Schema- oder Migrationsänderung.
                                v0.69.4
                                10. Juli 2026

                                Kanonische Buchungs-URL `/inbox/thread/<id>` + `ex_conversation_id`-Backfill

                                • /inbox/thread/[threadId] (app/(operator)/inbox/thread/[threadId]/page.tsx)
                                • Zentraler Helper lib/booking-href.ts (bookingHref({ id, exConversationId })):
                                • Härtung: voice-calls.byId läuft die stayId aus untrusted MCP-Action-Output
                                • Hospitable-API (per-Reservation get-reservation, Concurrency 6): 1267 Threads
                                • Einmaliger read-only staydb-Pull aus hospitable.messages (Legacy-ASP.NET-DB)
                                • 8 echte Foyer-native Seed-Stays (keine Hospitable-Herkunft) restlos gelöscht.
                                • Ergebnis: ~70 % der Stays (4711/6731) tragen jetzt eine Thread-ID; die 2020
                                v0.69.3
                                08. Juli 2026

                                Conversations: leere/gespaltene Threads reparieren

                                • listByStay: ORDER BY last_message_at DESC NULLS LAST → immer die aktive
                                • Merge-on-Relink (ensureHospitableConversation): Beim Verknüpfen einer
                                • Prod-Cleanup: 5 gespaltene/leere Conversations über 4 Aufenthalte in je eine
                                • Kalender-Quickview-Buttons konsolidiert: die zwei Aktionen „Details"
                                v0.69.2
                                08. Juli 2026

                                Hospitable-Nachrichten: Sync-Gap heilen + Resync-Handle

                                • Fix A — Drift-Heal (hospitable.heal_messages, tRPC
                                • Fix B — Resync-by-Reservation (hospitable.resync_reservation, tRPC
                                • Beide teilen einen extrahierten Kern resyncReservationMessages (aus dem
                                • Idempotenz-Härtung (behebt einen vorbestehenden Prod-Bug): der kanonische
                                • Auf Prod ausgeführt (scripts/heal-hospitable-messages.ts, dry-run→real,
                                v0.69.1
                                08. Juli 2026

                                Check-in: Meldeschein & Ausweis in einem Flow

                                • Die zwei getrennten Ausweis-Erfassungen im Check-in-Portal wurden zu einem Abschnitt konsolidiert: der Multi-Gäste-Upload ist jetzt Schritt 1/5 im Meldeschein-Wizard.
                                • Der alte ?ocr_…-URL-Umweg mit Seiten-Reload entfällt, die OCR-Vorausfüllung fließt jetzt in-component direkt ins Formular.
                                • Der Upload lässt sich mit „Ohne Ausweis fortfahren" überspringen, der redundante Foto-Schritt im Unterschrift-Schritt sowie der separate Order-16-Abschnitt wurden gelöscht.
                                • Der Ausweis-Schritt erscheint nur noch, wenn id_upload_mode ihn verlangt; bei never wird er übersprungen (Schritt 1/4).
                                • Ausweis-Fotos liegen jetzt einheitlich in guest_id_uploads, die Operator-Detailseite zeigt sie in einer neuen „Ausweisdokumente"-Karte (meldescheine.id_photo_path bleibt Fallback für Alt-Datensätze).
                                • Keine Migration nötig, MCP-Registry unverändert bei 179 Tools; Umsetzung erfolgte subagent-getrieben in 7 Tasks mit Review je Task.
                                v0.69.0
                                08. Juli 2026

                                Länderabhängige Meldeschein-Pflicht (BEG IV)

                                • Rules-Engine (server/checkin/registration-rules.ts, pure + unit-getestet):
                                • Portal: Bei foreign_only fragt der Check-in-Wizard vorab „Haben alle
                                • Settings (/settings/portal → „Meldeschein & Ausweis"): Radio
                                • Retention-Cron checkin.registration-retention (gated FOYER_CHECKIN_AUTO=1,
                                • Operator: Badge „entfällt (Inland, BEG IV)" in Liste + Detail; bei
                                • Migration 0146 (additiv, Default = Status quo → verhaltensneutraler Deploy).
                                v0.68.4
                                08. Juli 2026

                                Landing: Phone-Frame-Dramaturgie (makler-os-Pattern) + Truth-Mode-Welle

                                • Die Omnichannel-Demo sitzt jetzt in einem Telefon-Rahmen in den makler-os-Maßen (448×780, 8px-Bezel, 40px-Radius) mit fester Höhe über alle Kanäle, ohne Resize beim Tab-Wechsel.
                                • Die Demo-Threads wurden auf je rund fünf Nachrichten vertieft (Parkplatz-/Frühstück-Follow-ups, kanalübergreifend konsistente Fakten) und antworten jetzt als Hotel Doerenkamp.
                                • Die vier Kern-Features sind keine Textkarten mehr, sondern alternierende Blöcke mit 280×560-Geräte-Mockups (Kalender, Buchungsbestätigung, Check-in-Checkliste, Task-Karten) in purem HTML/CSS.
                                • Gestrafft bzw. entfernt wurden die 13-Sprachen-Sektion, der veraltete Booking-Engine-Screenshot und rund 30 Prozent der Case-Study-/Founder-Prosa (Stats und Zitat blieben erhalten).
                                • Alle Sektions-H2s laufen jetzt einheitlich auf dem Serif-System, und die Navigation führt mit „Omnichannel" ohne Umbruch.
                                • Umgesetzt als parallele 3-Agent-Welle mit disjunkter Datei-Ownership.
                                v0.68.3
                                08. Juli 2026

                                Landing: Omnichannel-KI als Lead-Argument + Design-Entschlackung

                                • Die Startseite zeigt jetzt nach dem Hero die neue Omnichannel-Sektion „Eine KI. Fünf Posteingänge.", die dieselbe Gast-Situation über WhatsApp, Email, Booking.com, Airbnb und Telefon durchspielt.
                                • Der Telefon-Kanal zeigt einen Voice-Bot mit Foyer.AI-Badge im makler-os-Demo-Pattern.
                                • Der Hero-Absatz wurde von 7 auf 3 Zeilen gekürzt, das Feature-Grid von 12 gleichrangigen Karten auf 4 Kern-Features plus Kompakt-Liste reduziert.
                                • Die Vergleichstabelle zeigt jetzt die 6 entscheidenden Zeilen zuerst (Omnichannel), mit einem „Alle 19 Kriterien anzeigen"-Toggle für den Rest.
                                • Der Gold-Italic-Akzent beschränkt sich nur noch auf das Hero-H1, alle „//"-Code-Kommentar-Labels wurden durch Caps-Eyebrows ersetzt (inklusive Kontrast-Fix der Screenshot-Captions).
                                • Die Pricing-CTAs sind jetzt tarif-spezifisch („Foyer.OS testen") statt siebenmal identischem Button-Text.
                                v0.68.2
                                06. Juli 2026

                                Messaging-Queue: failed items auto-purge after 24h

                                • Failed scheduled messages now stay retryable for one day and are then deleted automatically instead of accumulating indefinitely — 15 stale failures had piled up since 27.06 on prod.
                                • A new hourly pg-boss cron job messaging.failed-cleanup, gated behind FOYER_MESSAGING_AUTO=1, purges failed scheduled_messages rows older than 24 hours via failed_at.
                                • Retrying a failed message removes it from the delete predicate, and the queue header now states the 24-hour auto-removal policy.
                                • The behavior was integration-tested against real Postgres covering purge, keep, legacy, and idempotency cases, with no migration required.
                                v0.68.1
                                06. Juli 2026

                                Inbox: inquiry-stage OTA threads show as „Anfrage · Airbnb"

                                • Airbnb inquiries (booking not yet confirmed) arrive as Hospitable message.created webhooks with reservation_id: null, but the inbox rendered them as anonymous with no pre-booking hint.
                                • A new conversations.platform column (migration 0145, additive) is stamped fill-once from the message payload's data.platform and backfilled from stays.source for booked threads.
                                • messages.listConversations now returns platform and isInquiry (stay-less Hospitable thread), and the Postfach renders an amber „Anfrage · Airbnb" badge for these.
                                • Once the guest books, the reconcile process relinks the stay and the badge disappears on its own.
                                • A sister fix shipped to the command-center (hospitable-messaging-clone commit 4e969cc, messaging-rules commit 8d4a191), whose history showed such sends as a fabricated "Shadow Guest".
                                v0.68.0
                                02. Juli 2026

                                3-tier billing (Connect / OS / AI), dormant behind a flag

                                • W1 foundation — tenants.tier/billing_cycle enums (migration 0139), tier-pricing.ts,
                                • W2 signup + checkout — trial/checkout/room-sync/webhook are tier-aware; signup captures
                                • W3 tRPC gating — featureProcedure/ownerFeatureProcedure gate the 8 features'
                                • W4 MCP gating — MCP agent control is AI-only; the tools-adapter gates every tools/call
                                • W5 UI upsell — gated operator pages render <PlanUpsellCard> via plan.entitlements.
                                • W6 go-live prep — migration 0141 grandfathers existing tenants (Doerenkamp → ai, rest →
                                v0.67.0
                                30. Juni 2026

                                ID-unification (W1–W3) + real-bug fixes + green integration gate

                                • W1 — external_ref normalised: all 7038 hospitable stays' external_ref now equals
                                • W2 — aggregate collapse: the 264 multi-stay reservations collapsed to one stay each (438
                                • W3 — conversation links backfilled: conversations.ex_conversation_id filled from staydb
                                • Availability — cross-tenant leak (security): the public availability query runs under
                                • Pricing — last-night off-by-one (revenue): resolve-rates excluded the last night
                                • FritzBox import — guest FK (matched calls silently dropped): the import matcher assigned
                                • Crash / reliability: getBrandVoiceStats + previewVoiceStyle interpolated a JS Date into
                                v0.66.19
                                29. Juni 2026

                                Availability double-booking fix + integration-suite consolidation

                                • Fixed a double-booking risk: availability and Stripe guards filtered on a non-existent in_house status — stay_status uses checked_in — so occupied rooms could show as available.
                                • The fix was applied in availability.ts and connect-webhook-handler.ts.
                                • Consolidated 25 integration test files onto the shared bootstrapTestDb() helper, replacing drifted per-file setup that omitted GRANT CONNECT and caused silent suite rot on Docker-down.
                                • Switched to valid v4 UUID fixtures (Zod v4 rejects version-0) and to getDb()→tenantDb() inside withTenant.
                                • The revived suite surfaced the double-booking fix plus three bugs — a pricing off-by-one, a brand-voice date-in-sql issue, a never-created late-arrival queue — tracked in operational-todos.md.
                                v0.66.18
                                29. Juni 2026

                                Off-box build → GHCR pull-deploy (ops)

                                • Deploys no longer build on the RAM-constrained 3.7 GB prod box: a dev Mac builds the arm64 image (~90s) and pushes to GHCR via build-and-push.sh; prod only pulls, migrates, recreates.
                                • scripts/deploy.sh gained a WEB_IMAGE guard — set, it pulls that tag with a relaxed RAM preflight; unset, it falls back to the byte-identical on-box build.
                                • A deploy now takes ~30-60 seconds instead of 5-7 minutes, with no OOM risk; rollback is re-deploying a previous sha- tag, and prod authenticates to GHCR with a read:packages token.
                                • The post-deploy build-cache prune is now gated on disk pressure (≥85% used) instead of running on every deploy, keeping the BuildKit/pnpm/Next caches warm between on-box builds.
                                • Repaired the test infrastructure: migration 0135 guards publish_task_rule_event against a missing pgboss.job, and pre-push now blocks when Docker is down instead of silently skipping.
                                v0.66.17
                                29. Juni 2026

                                Remove the /calls KPI strip (UI)

                                • Removed the four-card KPI strip (Heute / Verpasst heute / Ø Dauer / Gesamt) at the top of /calls, which ate too much vertical space above the call list.
                                • The underlying fritzboxCalls.stats query stays in place, since it still feeds the live "N neue Anrufe" badge.
                                • Only the card display and the now-unused fmtAvgDuration helper were removed.
                                v0.66.16
                                29. Juni 2026

                                RAM headroom C: runtime container memory limits (ops)

                                • postgres mem_limit: 960m / mem_reservation: 256m. Sized from the live
                                • web mem_limit: 768m / mem_reservation: 256m (steady ~203 MB → ~3.8×
                                • caddy mem_limit: 128m / mem_reservation: 32m.
                                v0.66.15
                                29. Juni 2026

                                MCP OAuth defense-in-depth hardening + prod-URL fix (#301, #302, #303)

                                • OAuth-grant revocation for operators. A new owner-only oauthGrants tRPC
                                • Header normalization in the OAuth Node bridge. node-bridge.ts strips every
                                • Strict CSP for /oauth/*. `default-src 'none'; style-src 'unsafe-inline';
                                • Prod-URL fix (#302). Three server-side URL builders — team.ts (worker-invite
                                v0.66.14
                                29. Juni 2026

                                RAM headroom: bound the build + bigger swap (ops)

                                • Build memory cap (deploy.sh): the build now runs `docker build
                                • Swap 2 GB → 4 GB (prod host, already applied): absorbs the build spike so
                                v0.66.13
                                29. Juni 2026

                                Next.js 16 + two standalone-path bug fixes

                                • Next.js 15.5 → 16 (#296), the last outdated dependency, alongside
                                • Email-template ENOENT (#297) — the pre-arrival onboarding cron (daily
                                • Meldeschein ID-photo persistence (#298) — the meldeschein wizard's ID photo
                                v0.66.12
                                29. Juni 2026

                                Click-to-dial: tel: links + copy across the call surfaces

                                • Every operator-visible phone number is now a one-click tel: dial link with
                                • Wired across the call log (/calls desktop + mobile), the contact book
                                • Pure frontend — no backend, no new tRPC/MCP tool (tool count stays 175), no
                                v0.66.11
                                29. Juni 2026

                                FritzBox Tier 3 backlog: missed-call → task + call↔reservation link

                                • Missed call → task: missed call rows get an "Aufgabe" button that creates a
                                • Call ↔ reservation link: a new additive fritzbox_calls.stay_id
                                v0.66.10
                                29. Juni 2026

                                Guest-portal bug fixes + E2E suite revival

                                • Untranslated section titles (guest-facing): the check-in page's getTitle
                                • Portal tRPC response-parse (guest-facing): the direct-fetch portal sections
                                • pino dev-server crash (DX): pino's dev transport (pino-pretty) runs in a
                                v0.66.9
                                29. Juni 2026

                                FritzBox Tier 3 UX: callbacks, contact modal, live badge, guest deeplink

                                • 4-state callback for missed calls (Offen / In Bearbeitung / Zurückgerufen /
                                • Real add-contact modal: the + on a nameless call opens the contact
                                • Live "N neue Anrufe" badge: the page polls stats and shows a badge when
                                • Guest deeplink: a matched-guest call name opens the GuestCard inline
                                v0.66.8
                                29. Juni 2026

                                Off-site backups live (the #1 reliability gap)

                                • Off-site replication ENABLED to a second Hetzner box (OpenClaw,
                                • Watchdog target-disk check (foyer-watchdog.sh): probes the off-site
                                • Builds on v0.66.6 (the replicate-offsite.sh SOURCE fix + the watchdog).
                                v0.66.7
                                28. Juni 2026

                                FritzBox correctness: DST timestamps + E.164 matching + guest FK

                                • DST-correct timestamps: the parser emits a naive wall-clock and Postgres does
                                • E.164 phone matching: a dependency-free toE164() post-filter removes
                                • H:MM:SS duration (calls > 99 min no longer parse to 0); batch upsert
                                • FK fritzbox_calls.guest_id → guests.id ON DELETE SET NULL (migration 0133;
                                v0.66.6
                                28. Juni 2026

                                Ops: deploy disk hygiene + health watchdog + off-site fix

                                • Deploy disk hygiene (deploy.sh, #283): each on-box build grew the
                                • Health watchdog (foyer-watchdog.sh + systemd timer, every 15 min; #283,
                                • Off-site source fix (replicate-offsite.sh): SOURCE pointed at the
                                v0.66.5
                                28. Juni 2026

                                FritzBox call-log reliability batch

                                • HTTP-status guards: fetchCallsCsv and getFritzboxSID now throw on a
                                • Retry with backoff: a new fetchWithRetry retries transient failures
                                • Honest connection test: checkCredentials does a real SID-auth
                                • Visible import failures: per-tenant import errors are persisted
                                v0.66.4
                                28. Juni 2026

                                DB-backup count retention

                                • backup.sh: the retention rule was age-only (-mtime +14), which bounds
                                • One-time prod cleanup: collapsed the existing pile to the newest backup
                                v0.66.3
                                28. Juni 2026

                                Security headers (CSP enforcing) + API-docs fix + shared-host hardening

                                • CSP now enforcing (was deliberately omitted): poweredByHeader: false
                                • /developers/reference fixed: the Scalar API reference threw
                                • H1 — Postgres host hardening: foyer-postgres pg_hba.conf catch-all
                                • C1 — shared-host co-tenant exposure: neighbour apps (makler-os,
                                • Hygiene: removed 9 stale .env.bak* secret-backups from prod. (M1 —
                                v0.66.2
                                28. Juni 2026

                                Rechnungsgäste-Ansicht + Invoice-Guest-Import

                                • Schema: guest_billing_addresses.reservation_ref (migration 0132,
                                • Backend: contacts.invoiceGuests query (guests with ≥1 billing address,
                                • Frontend: "Rechnungsgäste" chip on /calls/kontakte (paginated, 100/page)
                                • Data import (Hotel Doerenkamp): 174 billing addresses across 161 guests
                                v0.66.1
                                28. Juni 2026

                                pg-boss self-migration ownership fix + deploy readiness gate

                                • Root cause (migration 0131): pg-boss ≥ 12 self-migrates its pgboss
                                • Deploy readiness gate: new GET /api/health/workers readiness probe
                                v0.66.0
                                28. Juni 2026

                                Contact Book + Guest Billing

                                • Contact book (/calls/kontakte): a new sub-page listing non-guest contacts — Reinigung, Rezeption, Hausmeister, Dienstleister — with multiple phone numbers, email, company, and notes. Backed by the ne…
                                • FritzBox +Kontakt (tRPC + MCP): the existing "add contact from call" flow is repointed to the new tables via a shared upsertQuickContact helper — no duplicate write paths.
                                • Guest card — email + billing addresses: the guest detail card now surfaces an editable canonical_email field (guests.set-email MCP twin). A new guest_billing_addresses table stores N billing addresse…
                                • 9 new MCP tool-twins (MCP-Twin-Rule): contacts.list, contacts.get, contacts.search-guests, contacts.upsert, contacts.delete, guest-billing.list, guest-billing.upsert, guest-billing.delete, guests.set…
                                • Invoice-address integration (auto-fill from guest_billing_addresses into the invoice form) is intentionally deferred to a future focused task.
                                v0.65.4
                                28. Juni 2026

                                Operator UX (Übergabe / Übersicht / Heute + Nav) + email-routing fix

                                • Übergabe (/handover): a new auto-compiled „Lage jetzt" briefing above the notes — today's arrivals/departures, unanswered guest messages, open + urgent tasks, pending cleaning, rooms in maintenance, …
                                • Übersicht (/dashboard): reframed from a counter hub into business-health + alerts — KPI row (Belegung %, Umsatz, ADR from reports.revenueStats; KI-Antwortquote from dashboard.aiAnalytics) + an Alarme…
                                • Heute (/today): an action board — summary bar, arrival flags (missing Zimmer/Kaution red, Ausweis/Ankunftszeit amber, row tint) and a per-row quick-action.
                                • Navigation: „Anrufe" promoted to a top-level sidebar item (under „Sicherheit"); new Einstellungen → Navigation page to reorder + hide top-level items per browser (localStorage, drag-&-drop + ↑/↓; „Ei…
                                • Fix — signed_agreements restored on prod: the table was recorded-applied in the ledger but missing (/today + guest-portal AGB-signing errored with relation does not exist). Re-applied migration 0057;…
                                • Fix — inbox-reply email routing: dispatch.ts no longer hardcodes provider_name="postmark" — sendEmail (Gmail→Brevo→Postmark) already sent via Brevo, so replies were mislabeled and the delivery-reconc…
                                v0.65.3
                                28. Juni 2026

                                Security & reliability quick-wins (deep-audit follow-up)

                                • Webhook SSRF guard (server/webhook/ssrf-guard.ts): tenant-supplied webhook URLs are now re-resolved and rejected if they point at loopback/RFC1918/link-local/CGNAT/cloud-metadata IPs (or non-http(s) …
                                • FORCE RLS regression fixed (migration 0129): re-applies FORCE ROW LEVEL SECURITY to every RLS-enabled public table that lost it from migration 0089 onward (~54 tables incl. all Hospitable guest-PII, …
                                • Invoice-Portal indexes (migration 0129): reservation_id indexes on invoice_form_submissions/invoice_addresses/invoice_tax_ids — kills the O(stays × seq-scan) correlated-subquery cost in listInvoiceRe…
                                • pg-boss crash-guard: the job-queue singleton now has an error listener (log + Sentry) — an emitter error can no longer take down the worker process.
                                • DR runbook fix: docs/deploy.md restore/DR steps now read from /opt/foyer/backups (where backups actually land) instead of the never-populated /var/backups/foyer.
                                v0.65.2
                                28. Juni 2026

                                FritzBox Call-Log (Phase ι): operator call list + BYOK import

                                • Added a tenant-scoped FritzBox call log so operators can see who called and act on it directly inside Foyer.
                                • A PBKDF2 SID client fetches the call-list CSV from the FritzBox using BYOK (per-tenant host plus encrypted password, with a test-connection probe in Settings).
                                • A pure parser layer normalizes German dates and durations, and a daily pg-boss worker (gated behind FOYER_FRITZBOX_AUTO) imports new rows with Foyer-guest matching.
                                • The operator Anrufe page lists calls with contacts, callback flags, and notes.
                                • Eight new MCP tool-twins (fritzbox-calls.*) bring the registry from 157 to 165 tools.
                                • Tenant-scoped schema plus RLS were added in migration 0128.
                                v0.65.1
                                28. Juni 2026

                                Invoice Portal: operator request pipeline (command-center parity)

                                • Operator UI (/invoices): five tabs — Anfragen (with status sub-filters Offen / In Bearbeitung / Versandbereit / Erledigt + search), Offen (bookings still needing an invoice), Erstellt / Versendet / S…
                                • Workflow status (migration 0127): new invoice_workflow_status enum (offen → in_bearbeitung → versandbereit → erledigt, free transitions) on invoice_form_submissions, lazily materialized per reservati…
                                • 5 new tRPC procedures + MCP twins (MCP-Twin-Rule): invoices.listRequests / requestStats (read), setRequestStatus / createRequest / generateFromRequest (mutations; generate confirm-gated). Registry 15…
                                • Completeness badges + tab counts are computed server-side under RLS; no new external dependency. Behavior coverage of the pipeline SQL is deferred to the testcontainers-Postgres suite (router + tool-…
                                v0.65.0
                                28. Juni 2026

                                MCP OAuth connect flow (sign-in + consent, Hospitable-style)

                                • OAuth 2.1 Authorization Server via panva/oidc-provider (ADR 2026-06-28): Foyer is both the Resource Server (/mcp) and the AS (/oauth/*). Opaque tokens, PKCE-required (S256), Dynamic Client Registrati…
                                • Discovery: /.well-known/oauth-protected-resource (RFC 9728) + /.well-known/oauth-authorization-server (RFC 8414); /mcp 401 now carries WWW-Authenticate: …resource_metadata=….
                                • Login + consent: reuses the Auth.js operator session; a branded consent screen where the operator approves and picks scope — full or read-only (→ mcp / mcp:read), mapped onto the existing least-privi…
                                • /mcp accepts OAuth tokens alongside fk_live_ keys (verifyBearer): audience validated, scope → tool-gate, accountId → tenant. Tenant isolation (RLS) + read-only enforcement identical for both.
                                • Security: passed an adversarial review (no critical findings); refresh-token rotation with replay-revocation, findAccount user-liveness gate, secrets (OIDC_JWKS/OIDC_COOKIE_KEYS) env-only + fail-clos…
                                v0.64.2
                                28. Juni 2026

                                MCP api-key hardening: read-only scope + expiry + rotation

                                • Read-only keys (migration 0125): mint a key with scope=read_only — it can only call readOnly-flagged MCP tools; every write/mutation tool is denied at the tools-adapter (read_only_key). Ideal for a k…
                                • Expiry: optional expires_at per key; verifyApiKey rejects expired keys — covers the MCP server and the REST developer API (central check, GET-only surface).
                                • Rotation: one-click rotate (revoke old + mint fresh secret, same name + scope) in Settings → API-Keys.
                                • Settings UI: scope toggle + expiry select on create; scope badge, expiry/expired state, and Rotate button per key.
                                • Existing keys default to scope=full + no expiry — fully backward-compatible. Security rules (scopeDeniesTool, isKeyExpired) are pure + unit-tested.
                                • This hardens Hospitable's fallback-bearer-token equivalent; the OAuth connect-flow (Hospitable's primary path) is the next piece.
                                v0.64.1
                                27. Juni 2026

                                phase θ hardening: pricing-drift monitor + regression guards + summary heal

                                • Folio↔Hospitable invariant monitor (#234): a daily READ-ONLY pg-boss cron (0 6 *, FOYER_MESSAGING_AUTO-gated) that flags any live OTA stay whose folio diverges from the authoritative Guest TotalPri…
                                • folio-init clamp (#233): room_charge is floored at ≥ 0, so a mis-priced/manual booking whose city tax exceeds the booking total can no longer produce a negative folio line.
                                • ×100 ingest regression test (#232): locks the Hospitable pricing ingest boundary against the ×100/÷100 drift that caused the v0.63.x inflation (asserts 6585¢ → "65.85" / 6585, not 658500).
                                • audit:rls in pre-commit (#231): the RLS audit now runs (and blocks the commit) automatically whenever staged changes touch apps/web/db/schema/ or apps/web/db/migrations/, closing the previously manua…
                                • Pricing-summary heal (#235): a one-off CLI re-pointed hospitable_pricing_summaries.total_amount at the authoritative Guest TotalPrice for the Doerenkamp tenant — 2961 corrupt summaries healed (Σ ~€99…
                                v0.64.0
                                27. Juni 2026

                                Messaging: n8ncloud-admin parity (codes conditions, AI analytics, rule conditions, semantic detection)

                                • Custom Codes (migration 0121): inline edit + per-code conditions (always / nights-range / property / booking-date window) + property/platform scope + usage_count + per-language value translations. Ga…
                                • AI questions (migration 0122): false_positive_count + an analytics panel (overall accuracy, detections, false-positives, top-topics bars) and a richer Detection Tester (confidence-threshold slider, t…
                                • Rules (migration 0123): per-rule conditions (min/max nights, min/max guests, booking-window) applied in the scheduler, plus a live preview with variable-insert buttons in the editor.
                                • Semantic FAQ detection (migration 0124): per-tenant detection mode — lexical (default, trigger-phrase) · OpenAI · Voyage — selectable in Settings. Question embeddings are stored as JSONB float arrays…
                                • Queue / History: edit a pending message before it sends (wired the previously-unused editQueueItem) and resend an already-processed message (re-renders from the current rule + stay, bypasses idempote…
                                • Schnellantworten: category filter + text search.
                                • MCP tool-twins (Critical Rule #2): each new endpoint exposed as an MCP tool — ai_questions.report_false_positive, ai_questions.regenerate_embeddings, messaging_rules.resend_queue_item, tenants.get_fa…
                                • New side-effect-free modules with unit tests (code-conditions, rule-conditions, semantic-faq — 39 cases); all migrations additive; pnpm audit:rls clean.
                                v0.63.4
                                27. Juni 2026

                                nav: "Aufenthalte" defaults to the calendar

                                • Operator nav (#236): clicking the Aufenthalte sidebar group now lands on /calendar (the occupancy timeline) instead of /stays (the list). The list stays one click away via the Liste child. One-line h…
                                v0.63.3
                                27. Juni 2026

                                phase θ pricing: residual folio inflation corrected (Phase 2)

                                • Root cause (confirmed in code): stays.booking_total_cents is FILL-ONLY (ingest-pricing.ts / projectors/pricing.ts set it only when NULL). It was frozen at the live-webhook ×100-era inflated value and…
                                • Fix (data correction — scripts/correct-pricing-from-lines.ts, #224–#226): per affected LIVE Hospitable stay, booking_total_cents := Guest TotalPrice → regenStayFolio (rebuilds room_charge + city_tax …
                                • Applied (Doerenkamp): 2340 stays corrected (Σ folio €1,132,271.50 → €283,408.13, −€848,863.37 of phantom revenue removed). Two follow-up passes extended the guard to cohorts the first run conservativ…
                                • Reporting impact: the inflated folios were counted as revenue. Last-90-days revenue corrects from ~€387.7k → €116.5k (the real figure; the old number was ~3× inflated). Combined with v0.63.0's cancel…
                                v0.63.2
                                27. Juni 2026

                                phase θ hardening: aggregate model locked (no silent revert)

                                • Importer is aggregate-only: removed the FOYER_AGGREGATE_BOOKINGS flag + the per-room split branch from upsertReservation (poll + live webhook both go through it). The OTA idempotency lookup omits roo…
                                • DB lock (migration 0120): replaced stays_tenant_ota_room_unique (tenant, ota_source, ota_reservation_id, room) with a partial unique index stays_tenant_ota_live_unique (tenant, ota_source, ota_reserv…
                                • The per-room split utilities (split-reservation.ts, resplit-multiunit-stays.ts) are kept — they host shared helpers (splitCentsEvenly, regenStayFolio) still used by live pricing ingest + the pricing-…
                                • Fixed the pre-existing red import-reservations.test.ts (mock lacked .orderBy/.limit) and flipped its two multi-unit cases to assert the aggregate result. Full suite green.
                                v0.63.1
                                27. Juni 2026

                                phase θ follow-ups: calendar fan-out fix + pricing correction

                                • Calendar — half-migrated bookings now fan out fully (#221): computeCalendarRooms only fanned an aggregate booking across its rooms when the reservation had exactly ONE live stay. A half-migrated book…
                                • Folio — ×100 pricing inflation corrected (data backfill): the legacy live-webhook bug (f71203b, fixed at the ingest boundary by dcfe314) left some stays' fill-only booking_total_cents ×100 too high (…
                                v0.63.0
                                27. Juni 2026

                                phase θ: aggregate booking model (shipped + cut over)

                                • W1 — Importer (#204): upsertReservation keeps a multi-room reservation as ONE aggregate stay (room dropped from the idempotency key).
                                • W2 — roomsForStay() (#205): model-independent room-set helper — own ∪ siblings ∪ hospitable_property_reservations→mapping.
                                • W3 — Calendar fan-out (#206): an aggregate stay occupies all its booked rooms on the timeline.
                                • W4 — Housekeeping (#207): checkout cleaning tasks generated per booked room.
                                • W5 — Check-in messaging (#208): per-room codes (Z_Nr25-N / Z_C25-N) resolved for every booked room.
                                • W6 — Folio (#209): combined Hotelzimmer — N Zimmer × M Nächte line.
                                • W7a/W7b — Migration (#210, #212–#214): unit-tested parity planner + merge-repoint executor (re-point 27 stays.id FK tables → canonical, soft-cancel siblings, per-reservation parity-assert + rollback)…
                                • W8 — Docs + band-aid retirement (#211, #217): CHANGELOG/runbook; the split-model read-side consolidations (group-stays, detail room-tabs, chatStayId) removed — the list/calendar now show one row per …
                                v0.62.0
                                26. Juni 2026

                                MCP expansion: run the business, not just read it

                                • Reporting & dashboard (read-only): reports.revenue_stats (occupancy %, ADR, RevPAR, revenue + per-room-type over 7/30/90 days) and dashboard.today (inbound 24h, open/urgent tasks, stays in/out today …
                                • Stays operations (confirm-gated): stays.create_booking, stays.update_dates, stays.perform_checkout, and owner-only stays.cancel_and_refund — whose Stripe refund path is extracted to server/stays/canc…
                                • Messaging automation: messaging_rules.list_rules, messaging_rules.list_queue, and confirm-gated messaging_rules.edit_queue_item / cancel_queue_item — manage the scheduled guest-message queue fleet-wi…
                                • Rate suggestions: rate-suggestions.list + confirm-gated rate-suggestions.act (accept writes room_rates, reject/override).
                                • All locked into the mcp-coverage EXPECTED_TOOLS gate. No migration (reads/edits on existing tables).
                                v0.61.0
                                26. Juni 2026

                                Calendar: occupancy timeline + rich booking quick-card

                                • Occupancy timeline: units as rows, horizontal date axis; booking bars coloured by channel (Booking.com blue, Airbnb red, direct amber, manual green), solid grey "Gesperrt" bars for blocked nights, ni…
                                • Rich booking quick-card (click a bar): guest + channel badge + status pill, confirmation code (copy), check-in/out with arrival/departure times, nights · price · guest breakdown (adults/children/infa…
                                • Automatic-message timeline in the card: scheduled + already-sent guest messages from the scheduled_messages queue, with inline edit/cancel of pending items. New messagingRules.scheduledForStay (+ MCP…
                                • Tasks view + add-booking / block-range dialogs from the same surface.
                                • No migration (reads/edits on existing tables). A dev-only /calendar-preview route renders the real timeline against a mock tRPC link for design iteration (404s in production).
                                v0.60.0
                                25. Juni 2026

                                Security: camera access-audit + ops hardening

                                • Access audit: new security_access_log (RLS, migration 0117), written throttled (≤1 row per user+camera+action per 60 s) from the snapshot/live/rtc proxy routes — user_id has no FK so the trail surviv…
                                • Ops (hetzner5): a WireGuard watchdog restarts the tunnel when its handshake goes stale (re-resolving the dynamic hotel endpoint on an IP change); the 15-min health cron now also checks the live pipel…
                                • Deferred: the camera-origin nginx lockdown (allow 178.105.30.3) is staged but held to coordinate with the owner of that shared server; the origin already has Basic-Auth + rate-limit.
                                v0.59.0
                                25. Juni 2026

                                Security live: sub-second video (go2rtc fMP4)

                                • go2rtc (on hetzner5) pulls the cameras' direct RTSP over the cam-hotel tunnel (video-only — audio dropped) and serves on-demand fMP4; the Foyer player tries fMP4 first (/rtc), falls back to HLS (/liv…
                                • Everything stays behind Foyer session-auth + nginx Basic-Auth (no WebSocket, no UDP, no Cloudflare-hostile transport). go2rtc binds localhost only; WebRTC :8555 disabled. New Foyer route /api/v1/secu…
                                v0.58.1
                                25. Juni 2026

                                Security live: sub-stream tiles + HD fullscreen, self-healing

                                • Sub stream for tiles, HD on demand: the dashboard grid now plays the 640×352 sub stream (≈10× less data than the 2560×1440 main), so two feeds comfortably fit the hotel's upload. Fullscreen requests …
                                • Self-healing playback: transient drops now recover in place (hls.js startLoad / recoverMediaError) instead of tearing down and reloading, so a brief network blip no longer shows a visible cut. Buffer…
                                • Service: the on-demand reaper is more lenient (45 s idle, 22 s stale-segment watchdog) and the warm-up window widened so the slower-keyframe sub stream serves its first playlist on the first request.
                                v0.58.0
                                25. Juni 2026

                                Security: live camera video (WireGuard + HLS)

                                • Live path: hetzner5 joins the hotel LAN over a new cam-hotel WireGuard tunnel (AllowedIPs = 192.168.178.0/24 only — the camera subnet, never full-tunnel) and pulls the cameras' native RTSP by LAN IP.…
                                • Foyer proxy + player: new tenant-scoped route GET /api/v1/security/cameras/<id>/live/<index.m3u8|seg_NNNNN.ts> (the file is allowlisted to playlist/segment names — the SSRF/path-traversal boundary; u…
                                • Coverage: the two wired Reolink E1 Pro cams (eingang, rezeption) stream live; the battery PIR spendenbox and the Ring doorbell stay snapshot-only by design. The dead /stream MJPEG route was removed.
                                • Runbook: docs/security-cameras.md (live architecture, WG tunnel, wg show / ffprobe diagnostics).
                                v0.57.1
                                25. Juni 2026

                                Email: Postmark → Brevo (magic-link + transactional)

                                • Brevo SMTP (smtp-relay.brevo.com:587, STARTTLS) is the primary outbound provider for magic-link login and guest-reply mail — sendonly SMTP key, prod egress IP whitelisted, getfoyer.app domain-authent…
                                • Branded magic-link email: HTML template (button + copy-link fallback + security note) with a plain-text alternative → multipart for deliverability. New server/email/templates/magic-link.ts.
                                • Fallback chains: magic-link = Brevo → Gmail → (dev) MailHog, with the dead Postmark SMTP/HTTP branch removed; guest replies (postmark-outbound.ts) = Gmail → Brevo → Postmark.
                                • Postmark stays for inbound parsing only.
                                v0.57.0
                                25. Juni 2026

                                Security module: cameras + Ring doorbell, monitoring & events

                                • Cameras + doorbell: 3 Reolink cameras (via neolink image — go2rtc served a "Stream not Ready" splash, so snapshots use the camera snap feature) and the Ring battery doorbell (via ring-client-api, sin…
                                • Real-time events: the service is a persistent Ring subscriber; doorbell ding/motion push to /api/v1/security/events (shared-secret webhook) and surface as a "Letzte Ereignisse" strip. New security_ev…
                                • Doorbell UI: its own "Türklingel" card with a battery % badge (security.ringHealth), refreshed every 60 s (battery-friendly; the service caches Ring frames ~120 s).
                                • Latency: lazy prewarm keeps recently-viewed camera frames warm (instant during active viewing, zero load when idle) — cold Reolink snapshots were ~9–10 s.
                                • Monitoring: a 15-min health cron e-mails on 2 consecutive device failures (guards against silent breakage like an expired Ring token); nginx limit_req rate-limit on the proxy.
                                • Runbook + architecture: docs/security-cameras.md. Deferred (documented): origin lockdown via Cloudflare Access, access-audit log, live video, Frigate NVR, two-way audio, multi-property onboarding.
                                v0.56.3
                                15. Juni 2026

                                Hospitable reviews/properties: lossless ingest fixes

                                • Reviews data-loss fixed: the review ingest read flat field names, but the real Hospitable payload (the review.created webhook and the capture page) is nested (public.{rating,review}, private.{feedbac…
                                • Property data-loss fixed: same class of bug in the listings projector + property webhook ingest — address/checkin/checkout are nested, not flat, and the capture endpoint now returns the property obje…
                                • Reviews/properties reconcile re-enabled: the 15-min capture poll now hits the live endpoints (/v2/properties + per-property /v2/properties/{uuid}/reviews; the old /v2/reviews, /v2/listings and /v2/co…
                                • Reservations verified clean — no change needed; the proven importer maps the webhook (same shape as the reservations API), 6507 stays with check-in dates and guests fully populated.
                                • Reference-only follow-up noted (not shipped): the property sub-cluster parity remap (capacities/amenities/room-details), whose /v2/properties shapes differ from the older listings shape.
                                v0.56.2
                                15. Juni 2026

                                Multi-room folio self-heal + backfill

                                • Root cause: a Hospitable multi-room aggregate stay whose folio was seeded BEFORE its hospitable_property_reservations links projected (the seed-before-links race) rendered as single-room Zimmer DO#17…
                                • Backfill: corrected 80 stale multi-room folios on prod. Settle-safe — OTA auto-settle payments are moved with the ±1-cent rounding shift so each folio stays balanced; closed folios are skipped. One-s…
                                • Self-heal (durable fix): the folio.reconcile cron now re-derives any CURRENT/UPCOMING multi-room aggregate whose folio drifted to a single-room label, converging it to Hotelzimmer within ≤30 min. Sco…
                                • Locked by tests: roomLabelFor (the multi-room → Hotelzimmer rule) and decideFolioReseed (the settle-safe re-seed decision) extracted as pure functions, with 11 new unit tests covering the label rule …
                                v0.56.1
                                13. Juni 2026

                                Folio hardening + ops/type cleanup

                                • Folio close-guard: financial mutations (add/update/reset line, remove line, add/remove payment) are now rejected with folio_closed once a stay's folio is closed (folio_closed_at set) — enforced in th…
                                • Folio E2E smoke (tests/e2e/folio.spec.ts, gated behind FOYER_E2E_FOLIO_LIVE): columns render, inline-edit updates Gesamt, reset restores without emptying (guards the reset-wipe bug class), multi-room…
                                • pg-boss handler fix: channel-rate-sync, channel-availability-sync, review-request, upsell-offer workers used the obsolete single-job handler form (received the Job[] batch and read .data off the arra…
                                • TypeScript baseline 50 → 18: cleared 32 type errors across jobs/tools/tests (no any, no @ts-ignore).
                                • Migration tracking: schema_migrations ledger (migration 0113, grant-gated like stripe_webhook_events) + scripts/apply-migrations.ts (--dry-run / --baseline). Prod baselined (112 versions).
                                • Transaction-boundary audit: confirmed the folio reset connection-isolation bug class has no other live instances; one LOW concurrency TOCTOU in checkin.saveArrivalTime noted for the backlog.
                                • CLAUDE.md refreshed: Rule #5 (Hospitable reconcile) marked implemented; MCP tool count reconciled.
                                v0.56.0
                                13. Juni 2026

                                Smart-Lock (η.6) documented + Landing-Page/Doku-Sync

                                • smart_locks + access_codes schema with Pattern-A RLS
                                • SmartLockAdapter interface + NukiAdapter + registry (resolved by lock_type); Salto/Dormakaba as adapter stubs
                                • Lifecycle: check-in mints a 6-digit PIN (crypto.randomInt) with a validity window → check-out revokes it vendor-side
                                • BYOK credentials encrypted at rest (AES-256-GCM)
                                • tRPC router + /settings/integrations/smart-locks UI + MCP twin (server/tools/smart-locks.ts)
                                • MCP action count 52 → 117 (real defineTool registry size) in the comparison table, the "Wo Foyer schlägt" bullet, and feature block /10
                                • New comparison rows: Smart-Lock keyless Entry + Lost & Found
                                • New feature blocks /11 (Smart-Lock) + /12 (Lost & Found); "Zehn" → "Zwölf Bausteine"
                                v0.55.0
                                13. Juni 2026

                                Hospitable multi-unit reservations + multi-room folio

                                • Migration 0112 (stays_multiunit_ota_key) — widens the OTA idempotency key from (tenant, ota_source, ota_reservation_id) to include room, so an N-room reservation books N stays instead of collapsing t…
                                • split-reservation.ts (new) — even-split helper (splitCentsEvenly) distributing reservation total/guests/adults across booked rooms, remainder on the first rooms so per-room shares sum EXACTLY to the …
                                • Backfill (import-stays-from-staydb.ts) + live importer (import-reservations.ts) + pricing projector now create/price one stay per room.
                                • fix(hospitable): guest total derived from the TotalPrice bucket, not SUM(guest lines) — fixes triple-counting on multi-guest bookings.
                                • A multi-room aggregate stay's room_charge now shows the room count instead of qty = 1, derived from hospitable_property_reservations. totalCents stays authoritative so paid folios stay balanced.
                                • Combined line: one room_charge line per stay (not one per night) — Menge = Zimmer × Nächte, Einzelpreis = Preis/Zimmer-Nacht.
                                • Generic label Hotelzimmer for multi-room stays (single-room stays keep their Zimmer <nr> label).
                                • Deterministic ordering: Logis (room_charge) → operator extras → Beherbergungssteuer (city_tax), then date — no longer dependent on created_at ties.
                                v0.54.0
                                24. Mai 2026

                                Voice-AI-Agent Wave 4+5 closeout (Phase η.9 final)

                                • server/stripe/voice-hold-refund.ts (new) — charge.refunded webhook handler. Looks up the originating Checkout Session via payment_intent to recover metadata.foyer_stay_id. Full refund → stay flips to…
                                • /voice-calls/[callId] — native HTML5 audio player + download link for recording_url. Empty-state German message when no recording.
                                • /voice-calls — "CSV exportieren" button + new endpoint GET /api/v1/voice-calls/export (auth-gated, semicolon-delimited RFC 4180, honours days+outcome query params).
                                • tests/e2e/voice-hold-ota.spec.ts (new) — Playwright OTA hold→unblock E2E scaffold. Gated behind FOYER_E2E_OTA_LIVE=1 until Booking.com/Expedia sandbox creds are configured.
                                • docs/adr/2026-05-24-byok-stripe-decision.md (new) — ADR rejecting true-BYOK Stripe in favor of existing Stripe Connect Standard (per-tenant payouts already work via destination charges).
                                v0.53.0
                                22. Mai 2026

                                Voice-AI-Agent Wave 5.1 (race fix)

                                • server/jobs/stays-hold-expiry.ts refactored — per-stay one-shot pg-boss job (stays.hold-expire-one) schedules expiry at the EXACT hold_expires_at timestamp via boss.send(..., { startAfter }).
                                • voice-hold.create now schedules the one-shot expiry after insert (non-throwing — falls back to batch sweep if scheduling fails).
                                • Batch sweep cron (stays.hold-expiry, every 5 min) kept as safety net for orphaned stays.
                                • Bonus: OTA availability re-open moved into expireOneHold — room reopens within seconds of expiry, not on next 5-min tick.
                                v0.52.0
                                22. Mai 2026

                                Voice-AI-Agent Wave 4.1 (Stripe reconcile)

                                • server/stripe/voice-hold-reconcile.ts (new) — handles checkout.session.completed events dispatched via metadata.foyer_source='voice'. Flips stays.status from hold to confirmed on successful payment.
                                • Reuses existing /api/v1/stripe/connect-webhook endpoint — no new Stripe subscription needed.
                                • Idempotent via existing stripe_webhook_events table (Migration 0025).
                                • 10 new unit tests: idempotency, status-machine transitions, missing metadata, already-cancelled (warn-log only).
                                v0.51.0
                                22. Mai 2026

                                Voice-AI-Agent (Phase η.9, Waves 1+2+3)

                                • Schema: voice_agent_calls + voice_agent_call_actions + tenants.voice_settings JSONB (Migration 0091)
                                • Tenant-from-DID resolver mit E.164 Normalization (server/voice/tenant-from-did.ts)
                                • 3 MCP-Tools für externe Voice-Bots:
                                • voice-availability.check — live inventory + spoken-friendly rates (Wave 3: hold-aware)
                                • voice-hold.create — 30-min reservation-hold + SMS pay-link (Wave 3: real Stripe link)
                                • voice-facts.lookup — hotel facts Q&A (multi-locale aus ε.1.5 hotel_facts)
                                • Vapi-Webhook Endpoint POST /api/v1/voice/vapi-webhook mit HMAC-SHA256 Signature-Verify
                                • stays.status enum gewinnt 'hold' value + hold_expires_at TIMESTAMPTZ + source TEXT (Migration 0092 — ALTER TYPE, non-transactional)
                                v0.50.0
                                22. Mai 2026

                                Lost & Found (Phase η.10) + Infrastructure baseline

                                • Migration 0090: lost_items Tabelle + Pattern-A-RLS (tenant_id Filter, owner/staff/system Rollen)
                                • Neue /operations/lost-and-found-Seite für Operatoren (Liste, Status-Transitions, Foto-Upload)
                                • Guest-Portal /check-in/<token>/lost-found — Gäste melden vermisste Items selbst nach
                                • WhatsApp-Staff-Inbound: Pattern Found in 204: <item> → auto-record als lost_items-Row
                                • MCP-Tools: lost-found.list, lost-found.create (Twin zu tRPC-Router lostFound)
                                • pg-boss Retention-Cron: 90/180-Tage-Reminder + Telegram-Alert auf Schwellwert 180d
                                • Unit-Test: cross-tenant RLS-Block für lost_items (Testcontainers Postgres)
                                • PortalShell footer link to /check-in/<token>/lost-found (side-lookup, outside section-registry)
                                v0.49.0
                                20. Mai 2026

                                Hotel-Facts CRUD UI + Reconcile Telegram Alerts

                                • /settings/hotel-info: new "Eigene Hotel-Facts" section — add/edit/delete %fact:key% facts inline
                                • tRPC hotelFacts.upsert + hotelFacts.delete (owner-only, Pattern A RLS)
                                • Facts used by AI compose context, %fact:key% template substitution, and VAPI get_hotel_info
                                • sendTelegramAlert helper: fire-and-forget, no-ops when TG_BOT_TOKEN/TG_CHAT_ID unset
                                • Hospitable reconcile: Telegram ping when silent-drop messages are recovered (Critical Rule #5)
                                v0.48.0
                                20. Mai 2026

                                Pay-at-Hotel Booking Mode + E2E Smoke Tests

                                • Migration 0087: payment_mode TEXT NOT NULL DEFAULT 'stripe' auf rate_plans (CHECK: stripe | pay_at_hotel)
                                • Neuer REST-Endpoint POST /api/v1/booking/[slug]/reserve — erstellt Stay direkt ohne Stripe-Checkout
                                • StepReview.tsx: zeigt "Zahlung vor Ort"-Hinweis + alternativen CTA wenn paymentMode = pay_at_hotel
                                • /book/[slug]: ?status=reserved Success-Handler für direkten Booking-Flow
                                • Settings → Rates: Payment-Mode-Select (Stripe / Pay at Hotel) in Create+Edit-Formularen
                                • MCP rate-plans.list gibt paymentMode zurück (Schema: z.enum(['stripe', 'pay_at_hotel']))
                                • 12 Unit-Tests: Schema-Validierung für /reserve-Route
                                • tests/e2e/inbox-smoke.spec.ts: 3 Tests — Signup+Login → Inbox lädt, Nav-Link sichtbar, /api/v1/health → {ok:true,db:"ok"}
                                v0.47.0
                                20. Mai 2026

                                Hospitable Reconcile-Twin + Marketing AI Demo

                                • pg-boss Cron hospitable.reconcile.tick alle 15 Minuten — pollt /v2/conversations + /v2/messages pro aktivem Hospitable-Tenant
                                • Findet Nachrichten die per Webhook lautlos verlorengingen: onConflictDoNothing + enqueueAiProcess nur für direction = "inbound"
                                • Gated on FOYER_MESSAGING_AUTO=1 — identisches Pattern wie Postmark-Reconcile
                                • _started Idempotenz-Flag, localConcurrency: 1, max 3 Conversation-Pages × 2 Message-Pages pro Run
                                • 6 Unit-Tests: no_api_key, no_recent_conversations, all_in_db, new_inbound, host_message_skip, auth_fail
                                • Interaktive Guest-AI-Demo direkt auf der Homepage — kein Account nötig
                                • 3 Preset-Pills + Freitext-Input, SSE-Streaming, Cursor-Blink-Animation
                                • Backend: POST /api/demo — Groq free tier (llama-3.1-8b-instant), IP-Rate-Limit 5/min, 200-Zeichen-Cap
                                v0.46.0
                                20. Mai 2026

                                Guest Lifecycle Automation + OTA Availability Sync

                                • pg-boss Cron messaging.pre-arrival-mail täglich 07:00 UTC — selektiert alle Stays mit check_in = HEUTE+2 ohne gesendete Pre-Arrival-Mail
                                • Sendet personalisierten Portal-Deep-Link per Postmark (DE-Markdown-Template pre-arrival-de.md)
                                • Migration 0086: pre_arrival_mail_sent_at TIMESTAMPTZ auf checkin_sessions — Idempotenz-Guard
                                • 17 Unit-Tests (Datums-Arithmetik, URL-Konstruktion, Template-Rendering, Skip-Contracts)
                                • Kalender-UI (/calendar) mit Drag-Selektion: onMouseDown startet, onMouseEnter erweitert blaue Highlight-Zone, onMouseUp öffnet Bestätigungs-Dialog
                                • Geblockte Daten: roter Overlay + "gesperrt"-Badge im Grid
                                • Ruft trpc.rates.blockRoomDates auf (pre-existing endpoint)
                                • 6 Unit-Tests: toIsoDate, normaliseDateRange (forward/backward/single-day)
                                v0.45.0
                                20. Mai 2026

                                Developer API Expansion

                                • rate-plans.list — alle Rate-Plans des Tenants
                                • rates.list — Preise für Datumsbereich + optionaler roomType/ratePlanId Filter
                                • rates.upsert — Einzelpreis setzen (owner-only, onConflictDoUpdate)
                                • rates.bulk_set — Preis über Datumsbereich für Zimmertyp setzen (owner-only)
                                • rates.delete — Rate-Zeile löschen (owner-only)
                                • rates.list_restrictions — Min-Stay/Max-Stay Restriktionen abfragen
                                • availability.query — verfügbare Zimmer für Datumsbereich (nicht in blockedDates, mit Preisen)
                                • Bearer-Auth Middleware: Authorization: Bearer fk_live_… — reused verifyApiKey() aus MCP-Layer, vollständige OpenAPI-Security-Scheme-Deklaration
                                v0.44.0
                                20. Mai 2026

                                OTA Channel Manager (α.CM)

                                • Migration 0084: ota_connections Tabelle — (tenant_id, ota) unique, status pending/active/error/disabled, Dual-RLS
                                • Schema SecretKind erweitert: booking_com_api_key, booking_com_property_id, expedia_username, expedia_password, expedia_hotel_id — AES-256-GCM via BYOK-Muster
                                • server/channels/booking-com.ts: PUT zu Booking.com Supply API (/ari-rules), Bearer-Auth
                                • server/channels/expedia.ts: POST XML OTA_HotelRatePlanRQ zu Expedia EQC API
                                • pg-boss Worker channels.rate-sync: Fan-out zu allen aktiven OTA-Verbindungen, loggt in channel_sync_log
                                • tRPC: channels.listOtaConnections / channels.connectOta / channels.activateOta / channels.disconnectOta
                                • Operator-UI: /settings/channels — OtaChannelManager + OtaProviderCard für Booking.com + Expedia
                                • MCP-Twins: 3 Tools (channel.list_ota_connections, channel.connect_ota, channel.disconnect_ota)
                                v0.43.0
                                20. Mai 2026

                                Timeseries Demand Forecasting (γ.0)

                                • Migration 0085: demand_forecasts um source + sample_size Spalten erweitert, Unique-Constraint auf (tenant_id, room_type, date) vereinfacht
                                • server/ai/timeseries-forecast.ts: Pure-Math — bucketKey() + computeEWMAOccupancy(), keine externen Deps
                                • server/jobs/demand-forecast.ts: pg-boss Cron rates.demand-forecast täglich 01:00 UTC — expandiert Stays-History (18 Monate) in Tages-Occupancy, EWMA pro (Zimmertyp, Datum), Upsert in demand_forecasts
                                • Rate-Suggestion-Engine: liest demand_forecasts (source=timeseries-v1) als ersten Schritt, fällt auf Live-Heuristik zurück wenn kein Forecast vorhanden
                                • 13 Unit-Tests für EWMA-Mathematik (Decay, Clamping, DOW/Monat-Filter)
                                • Drizzle-Schema: demandForecasts in rate-suggestions.ts; 490 Tests grün
                                v0.42.0
                                20. Mai 2026

                                Cross-Tenant Benchmark (γ.5)

                                • Migration 0082: tenants.share_anonymous_benchmark — Boolean opt-in, DEFAULT false
                                • Migration 0083: anon_rate_benchmarks Tabelle — (country, size_band, date) → p25/p50/p75 + sample_size
                                • pg-boss Job rates.benchmark-refresh: Aggregiert room_rates über opt-in Tenants via withSystem, HAVING COUNT(DISTINCT tenant_id) >= 5, täglich 03:00 UTC
                                • tRPC: rateSuggestions.getBenchmark / rateSuggestions.getBenchmarkOptIn / rateSuggestions.setBenchmarkOptIn
                                • Operator-UI: Opt-in Toggle in /settings/rates + "Ø Region: €X" Kontext im InlineEditPanel
                                • MCP-Twins: rate-suggestions.get_benchmark / rate-suggestions.get_benchmark_opt_in / rate-suggestions.set_benchmark_opt_in
                                • 9 Unit-Tests für sizeBandForRooms (5-15 / 16-30 / 31-60 / 60+), 464 Tests gesamt grün
                                v0.41.0
                                20. Mai 2026

                                LOS Yield Optimization (γ.4)

                                • Migration 0081: rate_suggestions.los_hint — JSONB nullable, z.B. { "minStay": 2 }
                                • Engine: losHint wird gesetzt wenn occupancyP50 >= 0.75, in DB-Insert + Return inkludiert
                                • tRPC rateSuggestions.list: gibt losHint zurück
                                • Auto-Suggest Job: buildAutoMinStayRows() — upserted min_stay in rate_restrictions bei Auto-Mode + losHint
                                • Operator-UI: Amber-Badge "Min-Stay-Empfehlung: Mindestaufenthalt N Nächte" im InlineEditPanel
                                • MCP-Twin: Beschreibung um losHint ergänzt
                                • 4 neue Unit-Tests für buildAutoMinStayRows, 455 gesamt grün
                                v0.40.0
                                20. Mai 2026

                                Pre-Arrival Dashboard

                                • checkin.upcomingWithoutSession — tRPC-Query: Aufenthalte der nächsten 14 Tage ohne bestehende Check-in-Session (LEFT JOIN + IS NULL)
                                • messagingRules.seedPreArrivalDefaults — idempotenter Seed: erstellt "Pre-Arrival Portal"-Regel (−48 h vor Anreise, Email, DE+EN Templates mit %checkin_url%) wenn noch keine check_in-Regel mit negativ…
                                • /check-ins — zweistufiges Tab-UI: "Ausstehend" (Standard) zeigt ausstehende Ankünfte mit Quick-Action "Portal senden" pro Gast; "Eingegangen" behält bestehende Session-Liste mit Status-Filtern
                                • Amber-Badge auf "Ausstehend"-Tab zeigt Anzahl der ausstehenden Portale
                                • URL-Vorschau nach erfolgreichem Senden inline in Tabellenzeile
                                v0.39.0
                                20. Mai 2026

                                Folio-Zahlungen + Abschluss (δ.6)

                                • Migration 0080: folio_payments Tabelle mit Dual-RLS (tenant_isolation + system_bypass); folio_closed_at auf stays
                                • tRPC: folio.addPayment / folio.listPayments / folio.removePayment / folio.closeFolio
                                • Folio-Summary: neu mit paidCents + balanceCents (grün = ausgeglichen, amber = offen, violett = überzahlt)
                                • Operator-UI: Zahlungssektion mit Dialog (Zahlungsart + Betrag + Notiz), Tabelle aller Zahlungen, "Folio abschließen"-Button bei Saldo = 0
                                • MCP-Twins: folio.payment.add / folio.payment.list / folio.payment.remove / folio.close
                                • 11 neue Tests (10 Integration + 6 Pure-Unit Balance-Calc), RLS-Audit grün
                                v0.38.5
                                20. Mai 2026

                                KI Rate-Vorschläge Auto-Mode (γ.3)

                                • Migration 0079: tenants.rate_suggestion_auto_mode — CHECK('off'|'suggest'|'auto'), DEFAULT 'off'
                                • pg-boss Job rates.auto-suggest: Fächert withSystem pro Tenant auf, wendet Auto-Apply-Rows auf room_rates an, setzt rate_suggestions.actedOn='auto-accepted'; ±20% Guard verhindert extreme Ausschläge
                                • tRPC: rateSuggestions.getAutoMode / rateSuggestions.setAutoMode (Owner-only)
                                • MCP-Twins: rate-suggestions.get_auto_mode / rate-suggestions.set_auto_mode
                                • Operator-UI: RadioGroup in /settings/rates (Off / Nur Vorschläge / Auto-Anwendung) mit Amber-Warnung bei Auto
                                • 12 neue Unit-Tests (isWithinGuard + buildAutoApplyRows Edge Cases), 439 gesamt grün
                                v0.38.0
                                19. Mai 2026

                                Guest Check-out Flow

                                • stays.performCheckout tRPC-Prozedur — setzt Status auf checked_out, sendet stay.checked_out-Webhook, idempotent (doppelter Aufruf = kein Fehler)
                                • CheckoutAction-Komponente in /stays/[stayId] — nur sichtbar wenn Status checked_in; grünes Badge wenn bereits ausgecheckt
                                • Confirm-Flow: lädt Folio-Zusammenfassung (lazy, erst beim Öffnen), zeigt Posten + Gesamtbetrag
                                • Webhook-Event stay.checked_out im Queue-Typ ergänzt
                                • Ungültige Übergänge (cancelled) werden mit BAD_REQUEST abgelehnt
                                v0.37.0
                                20. Mai 2026

                                Hotel-Info-Sections (ε.1.5)

                                • Migration 0078: tenants.hotel_info_sections (JSONB) — Partial<Record<6 Schlüssel, {enabled, content}>>
                                • hotelFacts.getInfoSections / hotelFacts.updateInfoSection tRPC-Prozeduren + 2 MCP-Twins (hotel_info_sections.get/update)
                                • Messaging-Render Pass 0: Shorthand-Aliase werden aufgelöst, bevor %fact:key% greift — nur wenn enabled=true und content nicht leer
                                • Operator-UI: neue Sektion "Hotel-Informationen" in /settings/hotel-info mit 6 umschaltbaren Textfeldern
                                • Gästeportal: JSONB-first mit hotel_facts-Fallback (kein Breaking Change für Doerenkamp-Konfiguration)
                                • 37 neue Unit-Tests, 433 gesamt grün, RLS-Audit 0 Verstöße
                                v0.36.0
                                20. Mai 2026

                                Bewertungslinks (Review Request)

                                • Migration 0077: tenants.review_links (JSONB) — Google Maps, Booking.com, TripAdvisor, Custom URL + Label
                                • tenants.getReviewLinks / tenants.updateReviewLinks tRPC-Prozeduren (Owner-only Update)
                                • Messaging-Sender injiziert die konfigurierten URLs automatisch als %review_link_*%-Variablen in den Render-Kontext jeder Nachrichten-Regel
                                • Neue Settings-Seite /settings/review mit URL-Felder, Bezeichnung, Nutzungsbeispiel-Block
                                • Nav-Eintrag "Bewertungslinks" unter Einstellungen
                                v0.35.0
                                20. Mai 2026

                                Mängel & Wartung + Hospitable Multi-UUID Sync

                                • Neue Seite /operations/maintenance mit 3 Status-Tabs: Offen · In Arbeit · Erledigt
                                • Schnelles Melden: Dialog mit Zimmerwahl (aus Zimmerliste), Priorität (Niedrig/Normal/Hoch/Dringend), Freitextbeschreibung
                                • Inline-Statusübergänge: Offen → In Arbeit → Erledigt mit einem Klick; Abbrechen-Aktion für nicht mehr relevante Mängel
                                • Navigationslink "Mängel" unter Aufgaben-Gruppe im Sidebar
                                • Baut auf bestehenden tasks-Infrastruktur auf (kind = "maintenance"): keine neue Tabelle/Migration nötig, RLS-Schutz bereits vorhanden
                                • Unique Constraint von (tenant_id, room_type) auf (tenant_id, room_type, property_uuid) geändert (Migration 0076)
                                • Rate-Sync-Job pusht automatisch an alle gemappten Hospitable-Properties gleichzeitig
                                • Zwei Mapping-Modi möglich: per-Typ (Doppelzimmer → UUID1 + UUID2) oder per-Room (DO#11 → UUID)
                                v0.34.0
                                19. Mai 2026

                                KI-Vorschläge: LLM-Rationale Enrichment (γ.2)

                                • enrichWithLLMRationale: Haiku-Call pro 31-Item-Batch; JSON-Array mit {date, roomType, rationale}
                                • Silent Fallback auf Heuristik-Begründung wenn kein API-Key oder Anthropic-Fehler
                                • Batching: 31 Tage/Zimmertyp pro Call → max 2 Calls bei vollem Monatskalender (2 Zimmertypen)
                                • 5 neue Unit-Tests: No-API-Key-Fallback, leere Items, valides JSON, malformed Response, Multi-Item-Mapping
                                v0.33.0
                                19. Mai 2026

                                KI-Vorschläge: Heuristic Rate Suggestion Engine (γ.1)

                                • Neue Tabellen demand_forecasts + rate_suggestions (Migration 0074/0075, je mit Dual-RLS)
                                • Heuristik-Engine: historische Auslastung aus stays → Multiplikator (0.9×–1.35×) + Wochenend-Bonus (1.1×) → suggestedCents gerundet auf €1
                                • rateSuggestions.generate / rateSuggestions.list / rateSuggestions.act tRPC-Prozeduren
                                • Rate-Kalender: "💡 KI-Vorschläge"-Button → berechnet Vorschläge für den aktiven Monat; Zellen zeigen faden Vorschlag (grün = Potenzial ↑, amber = Potenzial ↓)
                                • Inline-Edit-Panel: "Vorschlag übernehmen"-Button mit Begründungstext; Accept appliziert Preis direkt via room_rates-Upsert
                                v0.32.0
                                19. Mai 2026

                                Bulk-Edit Audit + Undo (β.4)

                                • bulkSet snapshoted alte Preise vor dem Überschreiben → speichert rate_bulk_edits-Zeile mit diffJson
                                • rates.undoBulkEdit: stellt alte Preise aus diffJson wieder her (Löschen neu-erstellter, Wiederherstellen überschriebener Zeilen)
                                • /settings/rates/history: "Rückgängig"-Button pro unvertierter Zeile; bereits rückgängig gemachte Zeilen zeigen Timestamp
                                v0.31.0
                                19. Mai 2026

                                Rate-Plan CRUD (β.3)

                                • rates.createPlan / rates.updatePlan / rates.deletePlan tRPC-Prozeduren
                                • Guard: Standard-Plan nicht löschbar; Plan mit Preisen nicht löschbar (PRECONDITION_FAILED)
                                • Unique-Name-Check: doppelter Name → klare Fehlermeldung "Name bereits vergeben"
                                • /settings/rates: "Pläne verwalten ▾" Sektion mit Inline-Rename, Löschen, Neuen-Plan-Formular
                                v0.30.0
                                19. Mai 2026

                                Rate Calendar Grid + Multi-Plan Booking Engine (β.2)

                                • Monats-Navigation (← / →), Rate-Plan-Tabs (Standard + alle eigenen Pläne)
                                • Zellen farbkodiert: Grün = Preis, Rot = Stop-Sell, Gelb = Min-Stay
                                • Inline Edit-Panel pro Zelle: Preis + Stop-Sell-Toggle + Min-Nächte
                                • /settings/rates/history: Bulk-Edit-Protokoll (Datum, Zimmer-Typ, Zeitraum, Preisänderung)
                                • StepRooms: per-Plan-Karten mit Name, Erstattbarkeits-Badge, Gesamtpreis
                                • BookingWizard: ratePlanId / ratePlanName durch State + Reducer durchgefädelt
                                • StepReview: Rate-Plan-Zeile in der Buchungszusammenfassung
                                v0.29.0
                                19. Mai 2026

                                Voice Bot + Hotel-Zeit-Einstellungen

                                • Webhook-Route POST /api/vapi/webhook (auth via x-vapi-secret, always 200 OK)
                                • Tool-Handler: check_availability, book_room, get_hotel_info
                                • Per-Tenant BYOK: voice_configs Tabelle (Migration 0068) mit Enable-Toggle, VAPI API Key, Webhook-Secret-Rotation
                                • Settings-UI /settings/voice: Toggle, maskierter API-Key, Webhook-URL + Copy, Secret-Regeneration
                                • MCP-Twins: voice.config.get, voice.config.update
                                • Sidebar-Nav: "Voice Bot" unter Einstellungen + "Hotelinfos" ergänzt
                                • 8 Spalten auf tenants (Migration 0072): Check-in Standard/Früh/Spät, Checkout Standard/Spät, Zugangsfenster (Minuten seit Mitternacht, Berlin-Lokalzeit)
                                • tRPC: hotelFacts.getTimeSettings / hotelFacts.updateTimeSettings
                                v0.22.0
                                15. Mai 2026

                                Phase ε.3 — Multi-Guest ID-Upload

                                • ID-Upload section as the fifth section (order=16, after all
                                • Multi-guest slots: primary booker name pre-filled from the guest
                                • Upload-on-file-pick: no Save button — FileReader → base64 → tRPC
                                • Thumbnail preview: after upload, a thumbnail renders via the
                                • DSGVO-compliant storage: UUID-only paths, mime-sniff validation
                                • Migration 0061 (Wave 1): guest_id_uploads table with RLS
                                • checkin.uploadGuestId public tRPC mutation: token-auth, mime-sniff
                                • checkin.removeGuestId public tRPC mutation: idempotent removal of
                                v0.21.0
                                14. Mai 2026

                                Phase ε.5 — Pre-Arrival Deposit / Kaution

                                • Deposit/Kaution-Section as the fourth accordion section
                                • Migration 0059: pre_arrival_deposits table with RLS (Stage-2C
                                • Migration 0060: tenants.pre_arrival_deposit_cents opt-in column
                                • checkin.createDepositCheckout public tRPC mutation: token-auth,
                                • Webhook handler extension in connect-webhook-handler.ts for
                                • SectionDef.shouldShow contract: optional (session) => boolean
                                • 3-layer idempotency: UNIQUE(tenant_id, stay_id) row constraint
                                • RLS Stage-2C defense-in-depth in the webhook:
                                v0.20.0
                                13. Mai 2026

                                Phase ε.1.5 — Hotel-Info Sections

                                • Migration 0057: hotel_facts table with Stage-2 NULLIF-guarded RLS
                                • Migration 0058: idempotent seed of 8 Doerenkamp facts. Luggage uses
                                • Six new section modules (orders 10-15) under
                                • Shared HotelInfoBlock + deriveStatusFromKeys helper so every
                                • Portal-shell icon registry extended with train, book-open,
                                • HotelFact[] projection in guest-session-loader.ts becomes
                                • Loader reads hotel_facts inside withSystem(tenantId, ...) with
                                • Operator UI for editing hotel_facts (hotelier edits via direct SQL
                                v0.19.0
                                13. Mai 2026

                                Phase ε.2 — AGB Signature-Pad

                                • AGB-Signatur-Section as the third accordion section (order=3,
                                • Migration 0057: signed_agreements table with RLS (tenant-isolation
                                • Migration 0058: tenants.hausordnung_markdown (NULL → Foyer default)
                                • checkin.signAgreement public tRPC mutation: token-auth, RLS Stage-2C
                                • IP-hash with per-tenant salt: sha256(ip + tenant.ip_hash_salt) →
                                • AGB snapshot at sign-time: AGB-drift after signature does NOT
                                • SignaturePad component reused verbatim from the Meldeschein wizard —
                                • Default Hausordnung (apps/web/server/checkin/default-hausordnung.ts)
                                v0.18.0
                                13. Mai 2026

                                Phase ε.4 — Arrival-Time Picker

                                • New accordion section arrival-time registered at order=2 (right
                                • Migration 0056: stays.expected_arrival_at TIMESTAMPTZ NULL. Nullable
                                • Public tRPC mutation checkin.saveArrivalTime (token-auth, no login).
                                • Late-arrival auto-trigger: when the chosen local hour is ≥ 23, a
                                • Audit-trail breadcrumbs: every save writes a portal.arrival_time.saved
                                • Guest-session-loader now projects expected_arrival_at as a
                                • The section-registry pattern from ε.1 carried this slice end-to-end:
                                • RLS Stage-2C compliant: every tenant-scoped read/write inside
                                v0.17.0
                                13. Mai 2026

                                Phase ε.1 — Pre-Arrival Guest Portal Foundation

                                • New tenant setting portal_layout_version (migration 0055). Existing
                                • Operator can toggle the layout per tenant via Settings → Pre-Arrival.
                                • Public guest portal at /check-in/[token] now renders the accordion
                                • Magic-link refresh for expired tokens. Expired token URLs redirect to
                                • Operator can revoke all pending portal links for a stay from the stay
                                • Explicit expires_at column on checkin_sessions (migration 0054).
                                • Audit-log breadcrumbs on every token lifecycle event under the
                                • RLS Stage-2C re-audit passes for all Phase ε.1 code.
                                v0.16.0
                                12. Mai 2026

                                RLS Hardening + Operator UX

                                • Switched: prod DB role from foyer (BYPASSRLS) to foyer_app (BYPASSRLS=f).
                                • Migration 0052: all 53 RLS policies got current_setting('app.current_user_role','t')='system' OR (...) so withSystem/withAuthLookup paths keep working.
                                • Migration 0053: wrapped tenant-id casts in NULLIF(...,'')::uuid after
                                • Fixed: dedicated getAuthDb() postgres.js pool for the Auth.js DrizzleAdapter + Credentials provider. Starts every connection with -c app.current_user_role=system because auth lookups happen before an…
                                • Stage 2C audit: 4-agent parallel sweep found 3 HIGH + 5 MEDIUM cross-tenant bugs masked under withSystem. Notable: match-stay.ts would have routed a business-traveler's inbound msg into the wrong ten…
                                • Added: scripts/smoke-auth.sh — post-deploy 7-check roundtrip (4 page-smoke + CSRF + signin POST + verification_tokens DB write). Catches silent auth breakage in <10s instead of hours.
                                • Added: ⌘K (Mac) / Ctrl+K command palette over the entire operator nav. Fuzzy substring search with breadcrumb labels (Aufgaben · Reinigung), keyboard navigation, last-5 recents in localStorage. Self-…
                                • Restructured: sidebar from 30 flat items in two sections → 9 collapsible top-level groups (Hospitable-style). Auto-expand of the active group. Mobile drawer mirrors the same.
                                v0.15.0
                                09. Mai 2026

                                Booking-Engine MVP

                                • Added: rate_plans + room_rates + blocked_dates tables (migrations 0040–0042) for tenant-scoped booking rate management with per-(plan, room_type, date) prices and operator-managed unavailability
                                • Added: stays.payment_intent_id + payment_status + booking_total_cents (migration 0043) and tenants.stripe_connect_account_id + stripe_connect_onboarded_at (migration 0044) for per-tenant Stripe-Conne…
                                • Added: tRPC rates.* (list / upsert / bulkSet / delete / listBlockedDates / blockRoomDates / unblockDates) — all owner-only
                                • Added: tRPC availability.query — public, tstzrange-overlap algorithm, EUR 80/night fallback for unconfigured rates, 12 integration-tests covering edge cases (same-day dates, past dates, blocked rooms…
                                • Added: tRPC tenants.connectStatus + disconnectStripeConnect for OAuth lifecycle
                                • Added: tRPC stays.cancelAndRefund — operator-triggered Stripe refund on connected account, respects rate-plan cancellation_window_hours (default 24h), force-refund override
                                • Added: Public /book/<slug> 4-step wizard (Daten → Zimmer → Gast → Bezahlen) with sessionStorage rehydration, 13-language brand-CSS, success/cancel landing screens
                                • Added: Public GET /api/v1/booking/<slug>/quote (60/IP/min) + POST /checkout (5/IP/h) with server-side re-pricing
                                v0.14.0
                                09. Mai 2026

                                Phase 5 — Calendar Tasks Grid

                                • Added: 2D grid view at /operations/calendar/tasks showing rooms × dates with task pills
                                • Added: tasks.calendarGrid tRPC query (date-range × room pivot)
                                • Added: nav entry under Operations → Kalender
                                v0.13.0
                                08. Mai 2026

                                Phase 4 — Notification Rules Engine

                                • Added: notification_rules + notification_rule_executions tables (migration 0038)
                                • Added: notification.event pg-boss queue + evaluator worker
                                • Added: task.created / task.overdue / task.completed event publishers
                                • Added: tRPC notificationRules.* (CRUD + trigger + executions + dryRun)
                                • Added: /operations/notifications/* operator UI (list / new / edit / executions audit log)
                                • Added: per-event opt-out via users.notificationEventPrefs
                                • Note: WhatsApp dispatcher remained a throw-stub in this version — wired in v0.14.1 (Phase C)
                                v0.12.0
                                08. Mai 2026

                                Phase 1+6+7 — Operator Quickwins

                                • Added: /operations/tasks 4-tab dashboard (Needs Action / In Progress / Upcoming / Past)
                                • Added: /operations/log task history search
                                • Added: hourly daily-summary cron (DE/EN/PL/TR) sending at local 06:00 per tenant TZ
                                • Added: migration 0037 — users.last_daily_summary_at for cron dedup
                                v0.11.0
                                08. Mai 2026

                                Phase 3 — Team Management

                                • Added: users extension (payment_, task_kinds, notification_, invite_*, deleted_at)
                                • Added: room_cleaner_preferences + invite_tokens tables (migration 0035)
                                • Added: task_rules.property_ids → room_ids pivot (migration 0036)
                                • Added: multi-channel invite flow (Email / SMS / WhatsApp) via /work/invite/[token]
                                • Added: /operations/team/* operator UI + /work/profile worker self-service
                                • Resolved: Phase-2 stubs (preferred_for_room + round_robin assignee strategies)
                                v0.10.2
                                08. Mai 2026

                                Phase 2 — Task Rules Engine

                                • Added: task_rules + task_rule_executions tables (migrations 0031–0034)
                                • Added: DB triggers for booking.{new_reservation, checkout, cancellation}
                                • Added: pg-boss task-rule.event + scheduler queues, evaluator worker
                                • Added: condition evaluator + Mustache templates + assignee resolver
                                • Added: tRPC taskRules.* (CRUD + trigger + executions + dryRun)
                                • Added: /operations/task-rules/* operator UI
                                • Added: public iCal feed /api/ical/cleaner.ics?token=<uuid> for cleaner calendar subscription
                                v0.10.1
                                08. Mai 2026

                                Public Landing Overhaul · Analytics · Auth-Flow-Polish

                                • Hero rewrite + AI-first Sprachen-Frame ("jede Sprache der Welt", Mandarin/Suaheli/Bairisch nativ)
                                • Sieben Bausteine, interaktive Sprachen-Demo (13 Beispiele, RTL für Arabisch)
                                • Doerenkamp Case-Study mit verifizierten Metriken (20 Zimmer, 6.937 Buchungen, 4.108 Gäste)
                                • DIY/Foyer/PMS Vergleichstabelle, Tag-1-bis-Tag-8-Onboarding-Timeline, Founder-Section
                                • Pre-Arrival-Messaging-Timeline-Visual, Pricing-Quick-Cards (5/12/25 Zimmer)
                                • Mobile Sticky-Bottom-CTA, Hamburger-Drawer, Sticky-Nav mit Backdrop-Blur
                                • Plausible Analytics + 9 Custom-Events (5 Funnel + 3 Engagement + Mobile-CTA)
                                • JSON-LD Schema (Organization + SoftwareApp + FAQPage) für Google Rich-Snippets
                                v0.10.0
                                04. Mai 2026

                                Foyer Native Invoices

                                • invoice_* tables in Foyer's own DB (RLS-pinned, per-tenant numbering
                                • 10 native MCP tools: 3 read (invoices_list/invoices_get/invoices_stats)
                                • tRPC invoices router: list/get/stats/generate/send/cancel/
                                • Operator UI: /invoices (list + stats), /invoices/[id] (detail + Send +
                                • Public self-service form: /invoice-request/[token] (token-gated, no auth).
                                • Daily read-only sync cron from staydb (pnpm sync:invoices) — safety net
                                • Backfill scripts: 4 785 invoices + 5 181 PDFs migrated.
                                • Diff harness (pnpm diff:invoices) — exits 1 on any divergence (cutover gate).
                                v0.9.3
                                04. Mai 2026

                                Doerenkamp activation · external codes · real-time cleaning sync · race-condition fix

                                • slug=doerenkamp, name=Hotel Doerenkamp, subscription active,
                                • 20 real rooms (DO#11–DO#31, no #13) seeded directly from
                                • 6 937 reservations backfilled from staydb.hospitable.reservations
                                • 49 custom codes (Doerenkamp's existing variables — Z_C25-XX,
                                • INSERT confirmed → cleaning_task created on the check-out date
                                • UPDATE → cancelled → pending tasks deleted +
                                • UPDATE cancelled → confirmed → task re-created
                                • UPDATE check_out (date shift) → pending task moved to new date
                                v0.9.2
                                04. Mai 2026

                                Production Hardening Pack · Observability + Stripe idempotency + rate limits + MCP-tool tests

                                • @sentry/nextjs wired with EU residency (Frankfurt DSN). Configs split
                                • pino + pino-pretty (dev) for structured JSON logging in production.
                                • All 53 console.{log,error,warn} calls under apps/web/server/ and
                                • app/error.tsx + app/global-error.tsx capture client errors. Server
                                • PII helpers emailHash() / phoneHash() / bodyMeta() for safe logging
                                • New stripe_webhook_events table (migration 0025, primary key =
                                • reserveEvent() does INSERT … ON CONFLICT DO NOTHING RETURNING;
                                • Handler runs INSIDE a transaction. Failure releases the row so Stripe
                                v0.9.1
                                03. Mai 2026

                                Fragen + Schnellantworten · FAQ-Pool als first-class messaging tabs

                                • ai_questions — multi-language FAQ pool with operator-curated trigger
                                • canned_responses — single-language quick-reply snippets the operator
                                • New server/ai/classify-faq.ts — pure substring classifier with
                                • ≥ confidence_threshold match → draft from FAQ translation
                                • Sub-threshold partial match → FAQ default_response passed to
                                • Fire-and-forget detection_count + last_matched_at bumps on match
                                • Two new sub-tabs in /messaging: Fragen + Schnellantworten
                                • Fragen editor: name + topic + phrases textarea + 13-language tab strip
                                v0.8.5
                                02. Mai 2026

                                Public Developer-Portal · Hospitable-style Reference

                                • New /developers page: Hero ("Bauen mit Foyer"), 3-channel grid
                                • New /developers/reference: Foyer-branded Scalar embed via
                                • Existing /api/v1/docs (bare Scalar) preserved for direct
                                • OpenAPI metadata fixed: description was pointing at
                                • ~250 lines new CSS under .dev-* prefix in _marketing.css,
                                v0.8.4
                                02. Mai 2026

                                Operator UX overhaul · 4 new pages · Auth + signup fixes

                                • /dashboard — Tagessicht-Hub mit 4 Metric-Cards (Eingang 24h /
                                • /stays — Paginated list-view mit Filter-Tabs (Heute / Anstehend /
                                • /calendar — Monthly grid view, today-highlight als primary-filled
                                • /analytics — V1-Spec-aligned KI-Metriken: Auto-Reply-Rate (Ziel
                                • Sidebar redesign: 3 → 15 Items in 2 Sektionen (Operativ +
                                • All operator pages: shadcn design tokens (bg-card / border-border
                                • Operator layout: explicit font-sans (Geist) on the wrapper, max-
                                • Auth JWT strategy: Auth.js v5 Credentials provider is
                                v0.8.3
                                01. Mai 2026

                                Hospitable Direct-Webhook + Webhook-Signature Test-Suite

                                • Hospitable jetzt analog zu WhatsApp via per-Tenant Direct-Webhook
                                • 2 neue BYOK-SecretKinds: hospitable_api_key, hospitable_webhook_secret
                                • HMAC-SHA256 + Replay-Schutz (5 min Toleranz, Stripe-Pattern Header
                                • Settings-UI um Hospitable-Section erweitert (2 Felder + Webhook-URL
                                • 16 neue Unit-Tests für verifyMetaSignature + verifyMetaHandshakeToken
                                • 12 neue Unit-Tests für verifyHospitableSignature inkl. Replay-Schutz,
                                • Webhook-Endpoints sind damit produktionsdicht — alle 3 Inbound-Channels
                                v0.8.2
                                01. Mai 2026

                                Foyer-native WhatsApp · Direkt-Anbindung an Meta Cloud API

                                • Neuer Endpoint /api/v1/inbound/whatsapp/<tenantSlug> (GET = Meta-Verify-
                                • 4 neue BYOK-SecretKinds: wa_app_secret, wa_verify_token,
                                • Media (Bild/Video/Dokument) via Meta Graph API mit BYOK-Access-Token,
                                • Settings → Zugangsdaten neue WhatsApp-Section mit Per-Tenant-Webhook-URL
                                • Twilio-Section umbenannt zu "Twilio · SMS-Login (Personal)" — WhatsApp
                                • Legacy stay-Bridge (server/bridges/wa.ts) bleibt im Repo, ist aber per
                                • Activation runbook: docs/wa-bridge-activation.md neu geschrieben für
                                • ✅ Email (Postmark) — komplett, BYOK + Inbound-Signature-Verify
                                v0.8.0
                                01. Mai 2026

                                P2.4 · Rich-Media Inbox · Email-Attachments + Auto-Carry-Over

                                • New message_attachments table mit AES-256-GCM-Storage-Pfad-Pattern
                                • Postmark inbound webhook persistiert Attachments[] Array aus inbound Emails
                                • Magic-byte MIME-Detection in lib/sniff-mime.ts — vertraut nie der
                                • Auto-Carry-Over: AI-pipeline Layer 4 (Task-Detection) kopiert
                                • Operator-Inbox + Worker-App: neuer <AttachmentGrid>-Komponent mit
                                • Worker-App separiert visuell: 📩 Vom Gast geschickt vs. ✓ Beweis-Fotos
                                • 8 neue Magic-Byte-Unit-Tests, 141 tests gesamt grün
                                • ✅ Email (Postmark) — komplett
                                v0.7.4
                                30. April 2026

                                BYOK · eigene Postmark- und Twilio-Keys

                                • Tenants hinterlegen eigene API-Keys unter Settings → Zugangsdaten
                                • AES-256-GCM-Verschlüsselung im Postgres, Master-Key per FOYER_SECRET_KEY env
                                • Live-Test-Send-Buttons: echter Probe-Versand an Operator-Email/-Nummer
                                • Send-Pfade lookupen Tenant-Secret zuerst, fallback auf process.env
                                • RLS-Policy asymmetrisch: read = owner | system, write = owner only
                                • Postmark inbound webhook: two-phase signature verify (env-secret first,
                                • 10 Crypto-Unit-Tests (roundtrip, IV-uniqueness, GCM-tamper-detection)
                                v0.7.3
                                30. April 2026

                                MCP B.1 · invoices write-tools

                                • send_smtp tool (irreversibel, mit Warnhinweis im Tool-Description)
                                • update_address / update_tax_id / update_email tools
                                • Coverage weiter ausgebaut, jetzt mit Mutationen im invoices-Bereich
                                v0.7.2
                                30. April 2026

                                MCP-Tools auf 90 % Coverage

                                • 42 Foyer-Tools über das Model-Context-Protokoll exposed
                                • Phase B.1: 5 invoices read-tools + 5 kassenbuch read-tools als Legacy-API-Proxies
                                • Coverage von 33 % → 90 % in drei Phasen geschlossen
                                v0.7.1
                                30. April 2026

                                Public Marketing-Site live

                                • Anthropic-Trust Design-Direktion (Inter + Source Serif 4 + JetBrains Mono)
                                • /eu-hosting Page mit Architektur-Diagramm
                                • FAQ-Section + Use-Case-Galerie + interaktiver Pricing-Calculator
                                • Animated Hero Mockup (3 rotierende autonome Szenarien)
                                • OG-Image, Sitemap, robots.txt, Impressum + Datenschutz-Gerüste
                                • Mobile-Polish für 60 % Mobile-Traffic
                                • next/font self-hosting, Lighthouse mobile 84 / accessibility 92
                                v0.7.0
                                29. April 2026

                                Self-Serve Onboarding + Stripe Billing

                                • Sign-up-Wizard mit Email + Hotel + Zimmer-Anzahl in 3 Minuten
                                • Stripe Checkout im Test-Mode mit Sockel + Pro-Zimmer-Pricing
                                • Subscription-Gate auf Operator-Routes + MCP-Block
                                • Stripe-Webhook-Handler (6 Events, Signature-Verify)
                                • Settings → Abrechnung mit Customer-Portal-Session
                                • Zimmer-Update synct automatisch die Stripe-Quantity
                                v0.6.0
                                29. April 2026

                                MCP-Server (Claude Desktop / ChatGPT / Cursor)

                                • Foyer als MCP-Server für AI-Clients via API-Key
                                • Initial 33 % Coverage der internen Tools
                                • Rate-Limit + Auth-Middleware für externe Verbindungen
                                v0.5.0
                                29. April 2026

                                Worker / Task-Routing

                                • Personal-App unter /work mit SMS-Login (Twilio)
                                • Round-Robin-Verteilung an Hausmeister + Reinigung
                                • Foto-Beleg-Pflicht beim Erledigt-Klick
                                • 5 Sprachen: DE / EN / PL / TR / RO
                                • Operator /tasks Page für Übersicht
                                v0.4.1
                                29. April 2026

                                AI Auto-Mode + Trust-Ramp

                                • 7 Tage Soak-Window + 5 Drafts + 80 % Acceptance-Rate unlocked Auto-Send
                                • Sensible Themen (Beschwerden, Rechtliches, Sicherheit) bleiben immer eskaliert
                                • Settings → KI Dashboard mit Confidence-Charts
                                • L2 LLM Auto bleibt gated bis compose() echte Self-Confidence liefert
                                v0.4.0
                                29. April 2026

                                AI-Antwortvorschläge (Anthropic-EU)

                                • Claude Sonnet + Haiku über den Anthropic-EU-Endpoint (Irland)
                                • Vorschläge in der Sprache des Gastes (franc-min Detection)
                                • Operator gibt frei, ändert oder verwirft pro Nachricht
                                • Token-Budget pro Tag konfigurierbar
                                v0.3.0
                                29. April 2026

                                Channel-Adapters (WhatsApp + Hospitable + Voice)

                                • WhatsApp inbound + channel-aware outbound Bridge
                                • Hospitable inbound LISTEN-Bridge (Postgres-Notify)
                                • VAPI inbound HMAC-Route + Transcript-Persist
                                • Settings → Channels mit Live-Status-Karten
                                v0.2.0
                                29. April 2026

                                Inbox-Plumbing (Email + SSE + Webhook)

                                • Postmark inbound Email → Stay-Thread-Matching
                                • Postmark outbound für Operator-Antworten
                                • /api/v1/sse/inbox streamt Postgres-LISTEN-Events ans UI
                                • Webhook-Subscriptions mit HMAC-Signing + 5x exponential Retry (pg-boss)
                                • Mobile-First Navigation-Drawer
                                v0.1.1
                                29. April 2026

                                RLS-Hardening + Biome

                                • Row-Level Security auf jeder Tenant-Tabelle erzwungen
                                • ESLint → Biome Migration (schneller, weniger Konfig)
                                • Security-Audit dokumentiert + getestet
                                v0.1.0
                                29. April 2026

                                Foundation

                                • Next.js 15 + tRPC v11 + Drizzle + Postgres
                                • Auth.js v5 (Email-Magic-Link)
                                • 5 Personas (Owner / Staff / Worker / Public / System)
                                • 14 initiale Drizzle-Migrations
                                • Docker + Caddy + Postgres-16 in Compose, Hetzner CAX21 in Falkenstein

                                Liefert wirklich. Probier es aus.

                                14 Tage gratis testen. Keine Kreditkarte. 3 Minuten Setup.