Public Center-Website API — Lückenanalyse & Prioritäten
Stand: Analyse gegen den Code in apps/center-website (v. a. lib/server-data-loader.ts) und apps/dashboard/src/app/api. Ziel: externes Frontend (z. B. v0 + Vercel) kann alle relevanten Reads über https://dashboard.cockpit-os.de (oder konfigurierte DASHBOARD_API_URL) beziehen — ohne Prisma auf der Client-App und ohne Daten-Duplikat.
Legende
| Symbol | Bedeutung |
|---|---|
| CORS * | Access-Control-Allow-Origin: * (und typisch OPTIONS) auf GET-Antworten |
| Kein CORS | JSON wird geliefert, Browser-Cross-Origin-Requests von z. B. *.vercel.app schlagen ohne Proxy fehl |
| Auth | Endpunkt erwartet Session / nicht für anonymes Publikum |
| Prisma CW | Center-Website lädt heute direkt aus der DB oder über eigene /api-Routen derselben App (nicht Dashboard-URL) |
Hinweis: Server-Side Rendering auf Vercel (nur fetch vom Node aus) braucht kein CORS. Sobald die Kollegin Client Components oder Browser-fetch nutzt, sind CORS + OPTIONS auf dem Dashboard nötig.
Quelle der Wahrheit: server-data-loader.ts
| Daten / Feature | Heutiger Pfad im Loader | Dashboard-Pendant (falls vorhanden) |
|---|---|---|
| Shop-Kategorien | Dashboard GET …/website-categories (Dogfooding; Logik in @mall-os/database) | GET /api/categories (Dashboard-Liste); Center-Website /api/categories = dünner BFF |
| Page Content (u. a. Öffnungszeiten) | Dashboard GET …/page-content (Dogfooding) | GET CORS * |
| Services | Dashboard GET …/services?publicWebsite=true (Dogfooding) | Ohne Flag: nur isActive |
| Büros | Dashboard GET /api/offices?centerId=&status= (Dogfooding) | Lokale /api/offices optional für BFF |
| Homepage-Tiles | Dashboard …/homepage-tiles | ✅ |
| Category-Themes | Dashboard GET …/category-themes-for-website (Dogfooding; @mall-os/database) | …/category-themes = roh fürs Cockpit-UI |
| Office-Themes | Dashboard GET …/office-themes (Dogfooding; isActive, nur Büros Aktiv) | ✅ |
| Gastronomie-Themes | Dashboard …/gastronomy-themes | ✅ |
| Shops | Dashboard GET …/shops?publicWebsite=true&status=… (Dogfooding; Limit bis 5000) | Ohne publicWebsite: breiterer Status-Filter (nicht Inaktiv) |
| Aktuelles (News, Events, Offers, Jobs) | Dashboard GET …/aktuelles-bundle (Dogfooding; max 500 je Typ) | Einzelrouten …/news usw. für andere Clients |
| Baustellen-Tagebuch | Dashboard GET …/news?constructionDiary=true (Dogfooding im Loader) | ✅ P1; lokale Route /api/construction-diary bleibt im Repo, SSR nutzt sie nicht |
| Einzel-Angebot | Dashboard GET …/offers?offerId= (Dogfooding im Loader) | ✅ P1; lokale Route /api/offers/[id] bleibt im Repo, SSR nutzt sie nicht |
| Centerplan / Floors | Dashboard wayfinding/centerplan + wayfinding/floors (Dogfooding im Loader; Medien wie früher im Loader aufgelöst) | Center-Website /api/centers/centerplan = BFF (Slug, kombinierte Antwort) |
Zugehörige Dateien (Center-Website):
apps/center-website/lib/server-data-loader.ts— Haupt-Loaderapps/center-website/app/api/categories/route.tsapps/center-website/app/api/shops/route.tsapps/center-website/app/api/aktuelles/route.ts(Client/BFF)apps/center-website/app/api/construction-diary/route.tsapps/center-website/app/api/offers/[id]/route.tsapps/center-website/app/api/centers/centerplan/route.tsapps/center-website/middleware.ts— u. a.GET …/api/centers/by-domain
P0 — Status (technisches Fundament)
Umgesetzt (CORS * + OPTIONS für öffentliche Reads)
Gemeinsames Modul: apps/dashboard/src/lib/public-api-cors.ts.
| Bereich | Datei |
|---|---|
| Kategorien GET | apps/dashboard/src/app/api/categories/route.ts |
| Page Content GET | apps/dashboard/src/app/api/centers/[centerId]/page-content/route.ts (POST weiterhin ohne breites CORS — Schutz vor Cross-Origin-Schreibzugriff) |
| Website-Shop-Kategorien GET | …/centers/[centerId]/website-categories |
| Category-Themes (Website-Payload) GET | …/centers/[centerId]/category-themes-for-website |
| Gastronomie-/Category-(Admin)-/Office-Themes GET | …/gastronomy-themes, …/category-themes, …/office-themes |
| Centerplan GET | apps/dashboard/src/app/api/wayfinding/centerplan/route.ts |
| Floors GET | apps/dashboard/src/app/api/wayfinding/floors/route.ts |
| Routing POST + Touchscreen-GET | apps/dashboard/src/app/api/wayfinding/routing/route.ts |
| Eingänge GET | apps/dashboard/src/app/api/centers/[centerId]/entrances/route.ts |
| DOOH öffentlich (Playlists / Player für v0) | …/centers/[centerId]/dooh/public/playlists, …/playlist, …/active, …/local-hero — siehe API-Vertrag — DOOH |
Öffentliches Konfig-Bundle (Whitelist, kein website-config)
| Route | Datei |
|---|---|
GET /api/centers/[centerId]/public-visitor-surface | apps/dashboard/src/app/api/centers/[centerId]/public-visitor-surface/route.ts |
Liefert nur explizit erlaubte Felder (Branding, SEO, Chatbot-UI, Centerplan-/Wayfinding-Hinweise, apiHints). Keine API-Keys, kein companionConfig, kein analyticsPagePassword, kein vollständiges templateContent / themeOverrides.
Weiterhin auth-pflichtig: GET /api/centers/[centerId]/website-config — für Dashboard-Editoren; externe Sites nutzen public-visitor-surface + by-slug / theme-config nach Bedarf.
Chatbot (Besucher)
POST /api/ai/visitor-chatbot hatte bereits CORS * — Konversation läuft serverseitig im Dashboard (OpenAI-Key in der Dashboard-Umgebung). Body: centerId und/oder WordPress-apiKey (siehe Route-Doku).
Bereits mit CORS * (Referenz): u. a. …/[centerId]/shops, news, events, offers, jobs, services, homepage-tiles, hotpicks, by-slug/[slug], by-slug/[slug]/theme-config, by-domain, offices, visitor-chatbot.
P1 — Parität (Stand)
| Thema | Umsetzung |
|---|---|
| Baustellen-Tagebuch | GET …/centers/[centerId]/news?constructionDiary=true (+ optional status) — inkl. linkedShops, Datumsfenster wie Website |
| Einzel-Angebot | GET …/centers/[centerId]/offers?offerId={uuid} — websiteOfferPublicFilter, kein To-Go-exklusiv |
| Aktuelles-Bundle | GET …/centers/[centerId]/aktuelles-bundle — CORS *, Limits parametrisierbar (max 500 je Typ) |
| Hot Picks | GET …/centers/[centerId]/hotpicks — öffentlich, max. 50 aktive Einträge; Pfad auch data.apiHints.hotPicksGet auf public-visitor-surface |
| OpenAPI‑Snapshots | cockpit-docs/static/openapi/agencyos-integration.yaml + public-wayfinding-read.yaml (öffentliche Wayfinding‑GETs); Markdown‑Vertrag bleibt führend bei Widersprüchen |
P2 — Qualität, Dogfooding, Betrieb
| Thema | Datei / Ort | Empfehlung |
|---|---|---|
| Loader nur noch über HTTP | apps/center-website/lib/server-data-loader.ts | Erledigt: alle bisher genannten Reads inkl. Shop-Kategorien + Category-Themes (Website-Payload). Optional: OpenAPI |
| Rate Limiting / Abuse | public-visitor-rate-limit.ts + Redis (rate-limit.ts) | Erledigt für: POST /api/ai/visitor-chatbot, POST /api/wayfinding/routing (pro IP, 429 + CORS). Edge-Middleware bleibt generell; neue teure öffentliche POSTs analog prüfen. Env: COCKPIT_DISABLE_PUBLIC_VISITOR_RATE_LIMIT=1 |
| Medien-URLs | Loader resolveMediaUrl | Externes Frontend: gleiche URL-Auflösung dokumentieren oder Dashboard liefert konsistent absolute URLs |
AgencyOS /context vs. Floorplan | …/agencyos/v1/centers/{id}/context | include=floors_summary: kompakte Etage ohne mapSvg-Body (Längen-/Hybrid-Heuristik, Mapping-Zähler). Volles SVG: GET …/wayfinding/floors oder MCP cockpit_public_wayfinding_floors. OpenAPI: /openapi/agencyos-integration.yaml (FloorsSummaryItem), /openapi/public-wayfinding-read.yaml. |
| AgencyOS Schreiben Website-UI | Homepage-Kacheln, Page Content, Mediathek-Liste | Erledigt: …/homepage-tiles, …/page-content, GET …/media; MCP cockpit_agencyos_homepage_tiles, cockpit_agencyos_page_content, cockpit_agencyos_list_media. Suche inkl. Jobs/Offices: cockpit_agencyos_search_content. |
| SEO / Revalidate | apps/center-website/app/api/revalidate/route.ts | AgencyOS content_push triggert Revalidate automatisch (CENTER_WEBSITE_URLS + REVALIDATION_SECRET). Externe v0/Vercel: gleiche Route + Secret + URL in CENTER_WEBSITE_URLS; MCP cockpit_agencyos_revalidate_website. |
Kurz-Checkliste für den Product-/Tech-Entscheid
- P0: Öffentliche Read-Konfiguration (ohne Session) + CORS auf allen Endpunkten, die der Browser von einer anderen Origin trifft.
- P1: Baustellen-Tagebuch + Angebots-Detail + ggf. Aggregat + geschriebener API-Vertrag.
- P2: Center-Website auf dieselben URLs umstellen und Betrieb absichern.
Verwandte Pakete / Konfiguration
packages/dashboard-api/src/index.ts—getDashboardApiUrl()(Env:DASHBOARD_API_URL,NEXT_PUBLIC_DASHBOARD_URL,NEXT_PUBLIC_API_URL)
Verwandte Doku
- Public Center-Website API — Vertrag (Read) — URLs, Parameter, Beispiel-JSON, v0-Prompt
Nutzungsstatistik: Seitenaufrufe werden anonymisiert erfasst. Im Umami-Dashboard nach diesem Pfad filtern: /developer-guide/public-center-website-api-gap-analyse