Skip to main content

Full-Site Template Architecture

This document explains how the template system for center websites works – from the v0 generation to integration into cockpitOS.


Concept: Smartphone with Different Cover

Website templates are layout skins over the same technical structure – like a smartphone: the same technology inside, different appearance due to the cover.

  • Same functionality: Home, Shops, News, Services, Center Map, Contact – all pages
  • Same data: Comes from the cockpitOS dashboard (central data source)
  • Different design: Layout, colors, typography, map style – your v0 template

The template defines the cover, not the logic. Chatbot and Center Map (WayfindingMap) are global cockpitOS components – they are injected, not implemented in the template.


Architecture Overview

┌─────────────────────────────────────────────────────────────────┐
│ COCKPITOS DASHBOARD │
│ Center configuration, shops, news, events, services, etc. │
└─────────────────────────────┬───────────────────────────────────┘
│ Data (API)

┌─────────────────────────────────────────────────────────────────┐
│ CENTER-WEBSITE (Next.js) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Layout (centerConfig, websiteTemplate) │ │
│ │ ├── Template Layout? (Header + Footer) OR Standard │ │
│ │ ├── {children} = Page Content │ │
│ │ └── Chatbot, MetaTags, Analytics (global) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼─────────────────────────────────┐ │
│ │ Page (e.g. /shops) │ │
│ │ getPageComponent(template, 'shops') │ │
│ │ ├── Template Shops? → pages/shops.tsx (v0) │ │
│ │ └── OR ShopsPageClient (Standard) │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Data Flow

  1. Center activewebsiteTemplate from DB (e.g. 'cev-ai-theme' or null)
  2. Layout: If the template has a layout → CevLayout (or template layout) wraps {children}, otherwise standard (SiteHeader + ConditionalFooter)
  3. Page: getPageComponent(template, pageType) → template component OR standard
  4. Props: Server loads data (shops, news, etc.) and passes it to the component

Fallback: No template or template has no component for this page → standard cockpitOS component.


Page Types (PageTypes)

PageTypeRouteTemplate FileStandard Component
home/{slug}index.tsxCenterHomepage
shops/{slug}/shopspages/shops.tsxShopsPageClient
shop-detail/{slug}/shops/[shopSlug]pages/shop-detail.tsxShopDetailClient
news/{slug}/newspages/news.tsxNewsPageClient
news-detail/{slug}/news/[id]pages/news-detail.tsxContentDetailClient
event-detail/{slug}/events/[id]pages/event-detail.tsxContentDetailClient
services/{slug}/servicespages/services.tsxServicesPageClient
service-detail/{slug}/services/[slug]pages/service-detail.tsxServiceDetailClient
wayfinding/{slug}/wayfindingpages/wayfinding.tsxWayfindingPageClient
gastronomy/{slug}/gastronomypages/gastronomy.tsxGastronomyPageClient
restaurant-detail/{slug}/gastronomy/[id]pages/restaurant-detail.tsxRestaurantDetailClient
offices/{slug}/officespages/offices.tsxHealthCenterPageClient
parking/{slug}/parkingpages/parking.tsxParkingPageClient
opening-hours/{slug}/opening-hourspages/opening-hours.tsxOpeningHoursPageClient
impressum/{slug}/impressumpages/impressum.tsxImpressumPageClient
data-protection/{slug}/datenschutzpages/datenschutz.tsxDataProtectionPageClient
contact/{slug}/kontaktpages/contact.tsxContactPageClient
to-go/{slug}/to-go/[qrCodeId]pages/to-go.tsxToGoPageClient

Registry & Integration

Templates are registered in apps/center-website/lib/template-manifest-loaders.ts per ID as dynamic import(); at runtime, load-template-manifest.ts (React cache) loads exactly one manifest per request/center. template-registry.ts (Server/RSC) builds from that getHomepageTemplate, getPageComponent, getLayoutComponent, etc. (async, each await in the pages).

Client (cookie banner, overlay, chat trigger) uses template-client-registry.ts – does not bind the server registry with CenterHomepage.

Older documentation still shows a static registry example; the manifest map + lazy load is essential.

// Layout (Header + Footer)
const TEMPLATE_LAYOUT_REGISTRY = {
'cev-ai-theme': dynamic(() => import('@/components/templates/cev-ai-theme/layout').then(m => m.CevLayout)),
};

// Per-page components
const TEMPLATE_PAGE_REGISTRY = {
'cev-ai-theme': {
shops: dynamic(() => import('@/components/templates/cev-ai-theme/pages/shops').then(m => m.default)),
news: dynamic(() => import('@/components/templates/cev-ai-theme/pages/news').then(m => m.default)),
// ... additional pages
},
};

Adding a New Template:

  1. v0 generates template according to Website Prompt
  2. Download ZIP, unpack
  3. Move to apps/center-website/components/templates/[name]/
  4. template-meta.ts create (including optional customOverlayChrome, customChatTrigger, if the template sets its own overlay or chat triggers in the manifest) and include it in manifest.ts via ...templateMeta
  5. Add an entry in template-manifest-loaders.ts for template-id: () => import('@/components/templates/.../manifest'); include the same templateMeta in template-metadata-registry.ts under TEMPLATE_STATIC_METAS (same order as before)
  6. Data binding: Adjust route – e.g. loadShops for shops page, loadCenterplan for shop-detail (Center plan with shop highlight)
  7. Approve in the dashboard (Template Submission)
  8. Center: Website tab → Activation → Select Template

Metadata vs. Heavy Registry: dynamic-center-config, Theme-SSR and homepage flags use template-metadata-registry.ts. load-template-manifest + template-manifest-loaders pull only one manifest.ts per center; template-client-registry supplies cookie/overlay/chat on the client without server registry.

Integration Insights (CEV): Shops page needs shops prop (loadShops); Shop detail requires floors prop (loadCenterplan) and CenterPlanEmbed slot. Details see Website Prompt – Integration Insights.


Security for Existing Centers

  • websiteTemplate = null (default) → No change, Palais Vest etc. continue to use the standard layout
  • Migration additive: Only new column websiteTemplate, no data change
  • Fallback: Template unknown or page not existing → standard component

Workflow for Content Creators

  1. Copy PromptWebsite Template Prompt (from TASK)
  2. Screenshots – Section-wise (Hero, Maps, Footer) for v0
  3. v0 – Insert screenshots + prompt, generate
  4. ZIP – Download, check
  5. Upload – Dashboard → Templates → Upload
  6. Integration – Developer: take over into the repo, enter in registry, approve

Nutzungsstatistik: Seitenaufrufe werden anonymisiert erfasst. Im Umami-Dashboard nach diesem Pfad filtern: /en/templates/full-site-template-architektur