// 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.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

    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.