MarkusandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 57832d5e86 Retry Beds24 data calls on 401 by invalidating the cached access token.
When a data endpoint rejects the token with 401, the cached token is now
cleared and one retry is attempted with a fresh token. This prevents a
stale token from causing a cascade of 401s while still failing cleanly if
refresh itself is rate-limited.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-24 22:28:13 +02:00
2026-08-09 21:32:04 +02:00

BB-Apartment Website

Zweisprachige (DE/EN), buchungsfähige Website für BB-Apartment mit Next.js, Tailwind CSS, Beds24-Integration, Stripe-Zahlung und n8n-Automatisierung.

Technologie-Stack

  • Framework: Next.js 14 (App Router, TypeScript)
  • Styling: Tailwind CSS
  • Internationalisierung: next-intl (Deutsch/Englisch)
  • Zahlungen: Stripe Checkout (Anzahlung) + Stripe Billing (monatliche Rechnungen) + Stripe Customer Portal
  • PMS: Beds24 API
  • Workflows: n8n (Self-Hosted)
  • Datenbank: PostgreSQL (via Prisma)
  • Deployment: Docker Compose auf eigenem Server

Projektstruktur

app/[locale]/           # Öffentliche Seiten (i18n-Routing)
app/api/                # API-Endpunkte (Beds24, Stripe, Portal)
components/             # React-Komponenten
messages/               # Übersetzungsdateien (de.json, en.json)
prisma/                 # Prisma Schema
public/images/          # Bilder & Logo
src/config/             # Apartment-Konfiguration & Preislogik
src/lib/                # API-Clients (Beds24, Stripe, Prisma)

Lokal entwickeln

  1. Abhängigkeiten installieren:

    npm install
    
  2. Umgebungsvariablen kopieren und ausfüllen:

    cp .env.local.example .env.local
    
  3. Datenbank migrieren (lokale Postgres oder Docker):

    npx prisma migrate dev
    
  4. Dev-Server starten:

    npm run dev
    

    Die Seite ist unter http://localhost:3000/de bzw. http://localhost:3000/en erreichbar.

Produktiv-Deployment (Docker Compose)

  1. .env.local auf dem Server mit echten Werten befüllen.

  2. Container starten:

    docker compose up -d --build
    

    Dies startet:

    • Next.js App auf Port 3000
    • PostgreSQL
    • n8n auf Port 5678
  3. Erste Datenbank-Migration im Container ausführen:

    docker compose exec nextjs npx prisma migrate deploy
    

Wichtige API-Endpunkte

  • GET /api/availability?apartmentSlug=...&start=YYYY-MM-DD&end=YYYY-MM-DD
    Verfügbarkeit und Preis (inkl. Rabatt/Anzahlung)
  • POST /api/checkout-session
    Stripe Checkout für Anzahlung erstellen
  • POST /api/portal-session
    Stripe Customer Portal für Rechnungen/Adresse
  • POST /api/webhooks/stripe
    Stripe Webhook Empfänger
  • GET /api/rooms
    Apartment-Informationen aus Beds24

Konfiguration

Apartments

Die 8 Apartments mit Beds24 Property-/Room-IDs sind in src/config/apartments.ts hinterlegt:

  • Herdweg (Property-ID 121184): 4 Apartments
  • Schönaicher Straße (Property-ID 36159): 4 Apartments

Preise & Anzahlung

Rabattstaffel und Anzahlungshöhe sind in src/config/apartments.ts (bookingConfig) zentral konfigurierbar:

  • Mindestaufenthalt: 20 Tage
  • Standard-Rabatte: 30 Nächte = 5%, 60 Nächte = 10%, 90 Nächte = 15%
  • Anzahlung: 20% der Gesamtkosten

Stripe

Pro Haus wird ein separates Stripe-Konto verwendet. Die API-Keys und Webhook-Secrets müssen in .env.local hinterlegt werden.

Beds24

Die Anbindung nutzt Beds24 API v2 (Token-Auth), siehe Kommentare in src/lib/beds24.ts.

Jedes Haus hat einen eigenen, separaten Beds24-Zugang (eigener Login, nicht nur eine eigene Unterkunft innerhalb eines Accounts) — analog zu den pro Haus getrennten Stripe-Konten. Es werden daher zwei Invite-Codes/Refresh-Tokens benötigt:

  1. In jedem der beiden Beds24-Konten: Settings → Account → Apps/API → "Generate invite code" (Scope inventory, später auch bookings für automatische Buchungsanlage).
  2. Jeden Code einmalig gegen einen Refresh-Token tauschen:
    curl -H "code: <invite-code>" https://api.beds24.com/v2/authentication/setup
    
  3. Die zurückgegebenen refreshToken-Werte als BEDS24_REFRESH_TOKEN_HERDWEG bzw. BEDS24_REFRESH_TOKEN_SCHOENAICHER in .env.local hinterlegen.

Jeder Refresh-Token bleibt gültig, solange er mindestens alle 30 Tage einmal genutzt wird (passiert automatisch bei jedem Seitenaufruf mit Verfügbarkeitsprüfung für das jeweilige Haus). Ohne konfigurierten Token liefert der jeweilige Endpunkt Mock-Daten für die Entwicklung.

Wichtig: Die genaue Feldstruktur der Antwort von /inventory/rooms/offers und /properties wurde anhand der offiziellen Beds24-Dokumentation modelliert, aber noch nicht gegen einen echten Account verifiziert. Nach Eintragen der echten Tokens unbedingt einmal /api/rooms aufrufen und mit der Swagger-UI (https://beds24.com/api/v2/#/) abgleichen, ob Feldnamen wie maxPeople/minNights exakt passen.

Nächste Schritte / Offene Punkte

  • Für beide Häuser je einen echten Beds24-Refresh-Token hinterlegen und Antwortstruktur gegen Swagger-UI verifizieren
  • Stripe API-Keys & Webhooks für beide Häuser konfigurieren
  • n8n-Workflows für Buchungsbestätigung, Beds24-Buchungsanlage und monatliche Rechnungen bauen
  • E-Mail-Vorlagen (Deutsch/Englisch) finalisieren
  • Haus-/Apartment-Adressen vervollständigen
  • Optional: 3D-Rundgänge (Insta360) und KI-Assistent (OpenRouter) nach Go-Live

Geplant: Monatliche Zahlweise (zurückgestellt)

Entscheidung: Option A – automatisch per Stripe Subscription Schedule, Monatsrate = (Gesamtpreis − Anzahlung) ÷ Anzahl Monate, gleichmäßig verteilt.

Umsetzungsschritte, sobald wir weitermachen:

  1. Bei der Anzahlungs-Checkout-Session payment_intent_data.setup_future_usage: "off_session" setzen, um die Karte zu speichern (inkl. klarer Einwilligungs-Formulierung für den Gast).
  2. Nach erfolgreicher Anzahlung (Webhook checkout.session.completed) automatisch einen Stripe Subscription Schedule mit fester Phasenzahl (= Aufenthaltsmonate) und end_behavior: "cancel" anlegen.
  3. Prisma-Schema um stripeSubscriptionScheduleId / stripeSubscriptionId auf Booking erweitern.
  4. Webhook um invoice.paid / invoice.payment_failed erweitern (Status-Update + Benachrichtigung bei Fehlschlag).
  5. Optional später: SEPA-Lastschrift als zusätzliche Zahlmethode ergänzen.

Lizenz

Privat – alle Rechte vorbehalten.

S
Description
No description provided
Readme
344 MiB
Languages
TypeScript 98.8%
Dockerfile 0.6%
CSS 0.3%
JavaScript 0.3%