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>
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
-
Abhängigkeiten installieren:
npm install -
Umgebungsvariablen kopieren und ausfüllen:
cp .env.local.example .env.local -
Datenbank migrieren (lokale Postgres oder Docker):
npx prisma migrate dev -
Dev-Server starten:
npm run devDie Seite ist unter
http://localhost:3000/debzw.http://localhost:3000/enerreichbar.
Produktiv-Deployment (Docker Compose)
-
.env.localauf dem Server mit echten Werten befüllen. -
Container starten:
docker compose up -d --buildDies startet:
- Next.js App auf Port 3000
- PostgreSQL
- n8n auf Port 5678
-
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 erstellenPOST /api/portal-session
Stripe Customer Portal für Rechnungen/AdressePOST /api/webhooks/stripe
Stripe Webhook EmpfängerGET /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:
- In jedem der beiden Beds24-Konten: Settings → Account → Apps/API → "Generate invite code" (Scope
inventory, später auchbookingsfür automatische Buchungsanlage). - Jeden Code einmalig gegen einen Refresh-Token tauschen:
curl -H "code: <invite-code>" https://api.beds24.com/v2/authentication/setup - Die zurückgegebenen
refreshToken-Werte alsBEDS24_REFRESH_TOKEN_HERDWEGbzw.BEDS24_REFRESH_TOKEN_SCHOENAICHERin.env.localhinterlegen.
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:
- 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). - Nach erfolgreicher Anzahlung (Webhook
checkout.session.completed) automatisch einen Stripe Subscription Schedule mit fester Phasenzahl (= Aufenthaltsmonate) undend_behavior: "cancel"anlegen. - Prisma-Schema um
stripeSubscriptionScheduleId/stripeSubscriptionIdaufBookingerweitern. - Webhook um
invoice.paid/invoice.payment_failederweitern (Status-Update + Benachrichtigung bei Fehlschlag). - Optional später: SEPA-Lastschrift als zusätzliche Zahlmethode ergänzen.
Lizenz
Privat – alle Rechte vorbehalten.