---
name: site-vitrine
description: >
  Scaffold the PUBLIC (pre-auth) surface of a generated SmartStack client app:
  the home page (the `/` override), presentation pages (about, features, pricing,
  contact…) and a full marketing "site vitrine". Generates real, editable React
  pages + reusable sections (hero, features, split, CTA, FAQ, logos), wires them
  through the package's public seam (PublicRouteRegistry + extensions.pages),
  seeds i18n copy, and inherits the SmartStack theme. Conversational, then invokes
  the colocated scaffold-vitrine CLI. Use for "customise the home", "add a landing
  / about / pricing page", "build a vitrine / showcase site".
argument-hint: "[describe the vitrine, e.g. 'home + about + pricing, branded Acme']"
allowed-tools: Read, Grep, Glob, Bash
---

# site-vitrine — Build the public home / presentation pages / vitrine

A generated SmartStack app's `App.tsx` is just `<DynamicRouter/>` inside
`<SmartStackProvider>` — the routing, the auth shell and the built-in marketing
home all ship in `@atlashub/smartstack`. **But unlike the login page, the package
DOES expose a seam for client-owned public pages.** So a bespoke home / vitrine is
**scaffolded as real, editable source** the developer owns, wired through that seam:

1. **Home `/` override** — `config.extensions.pages[PAGE_KEYS.HOME] = HomePage`.
   Replaces the SDK's default home; renders inside the SDK `PublicLayout` (Header +
   Footer), no auth. `/` is reserved, so this override is the only way to own `/`.
2. **Public routes** — `PublicRouteRegistry.register({ path, component, layout })`
   for every presentation page. `layout:'public'` keeps the SDK Header/Footer;
   `layout:'none'` is white-label (no SDK chrome — uses the generated
   `MarketingHeader`/`MarketingFooter`).
3. **i18n** — copy lives in `vitrine` namespace JSON, registered via
   `addClientResources`. Layout/icons/hrefs are structural (in the components).

> **This works today** with `@atlashub/smartstack >= 3.55.0` (where the seam
> ships). There is **no package-contract dependency** (contrast `/login-config`).
> The CLI reads the installed version and warns if it's older.

> **NON-GOAL.** This skill never edits the SDK login/register pages, never touches
> `node_modules`, and never seeds DB navigation (these pages are public, not menu
> items). Theme is delegated to `/scaffold-theme`.

## What it generates (into `web/{appCode}-web/src/`)

| Path | What | On re-run |
|---|---|---|
| `vitrine/sections/*.tsx` | Reusable blocks: `Hero`, `FeatureGrid`, `SplitFeature`, `CtaBanner`, `Faq`, `LogoStrip` (+ `MarketingHeader`/`Footer` when any white-label page) | kept (your edits preserved) |
| `vitrine/pages/HomePage.tsx` + `{Name}Page.tsx` | Composed pages | kept (preserved) |
| `vitrine/locales/{lang}/vitrine.json` | i18n copy (namespace `vitrine`) | **deep-merged** (new keys added, edits kept) |
| `extensions/vitrine.generated.ts` | Wiring: route registrations + i18n + `vitrineExtensions` | regenerated |
| `src/main.tsx` | Adds the wiring import + spreads `vitrineExtensions` into the provider | idempotent edit |

Components use the SDK `theme.css` tokens (`--text-secondary`, `--bg-card`,
`--border-color`, `primary`/`accent` utilities, `gradient-text`, `hover-card`,
`animated-gradient`) so the vitrine matches the public shell and the tenant brand.

## Conversational flow

1. **Locate the project.** Confirm `projectPath` (generated app root) and `appCode`;
   the CLI auto-detects `web/{appCode}-web`.
2. **Scope.** Which of: the **home** (`/`), one or more **presentation pages**
   (about, features, pricing, contact…), or a **full vitrine** (home + pages).
3. **Per page/home, the sections** (ordered): `hero` (badge, headline, highlight,
   subhead, CTAs, benefit bullets) · `features` (cards with a lucide icon) · `split`
   (text + visual + bullets) · `cta` (banner) · `faq` · `logos`.
4. **Chrome per page.** Default `layout:'public'` (SDK Header/Footer). Offer
   `layout:'none'` (white-label) when they want a standalone marketing look.
5. **Branding (optional).** `appName`, `tagline`, `logoUrl` (used by the white-label
   header/footer).
6. **Languages.** Default `['fr','en']` — the same copy seeds each; translate the
   others after.
7. **Theme.** If they want colors/fonts, **delegate to `/scaffold-theme`** — this
   skill never writes `index.css`.
8. **Invoke** `scaffold-vitrine` once with the assembled `--spec`. Relay the
   envelope's `warnings` (version guard) and `nextSteps`.

## Invocation

```bash
npx --prefer-offline tsx skills/site-vitrine/cli/scaffold-vitrine/index.ts \
  --spec '{
    "projectPath": "/abs/project",
    "appCode": "demo",
    "home": {
      "sections": [
        { "type": "hero", "badge": "Nouveau", "headline": "Bienvenue", "highlight": "chez Acme",
          "subhead": "La plateforme métier.",
          "primaryCta": { "label": "Commencer", "href": "/register" },
          "secondaryCta": { "label": "Découvrir", "href": "#features" },
          "bullets": ["Rapide", "Sécurisé", "Multi-tenant"] },
        { "type": "features", "title": "Fonctionnalités", "items": [
          { "icon": "Users", "title": "Équipes", "description": "Gérez vos équipes." },
          { "icon": "Shield", "title": "Sécurité", "description": "OWASP & RBAC." } ] },
        { "type": "cta", "headline": "Prêt ?", "primaryCta": { "label": "Créer un compte", "href": "/register" } }
      ]
    },
    "pages": [
      { "name": "About", "path": "/about", "layout": "public", "sections": [
        { "type": "split", "title": "À propos", "body": "Notre histoire.", "bullets": ["2020", "Genève"] } ] },
      { "name": "Pricing", "path": "/pricing", "layout": "none", "title": "Tarifs", "sections": [
        { "type": "hero", "headline": "Tarifs simples" },
        { "type": "faq", "title": "Questions", "items": [ { "question": "…", "answer": "…" } ] } ] }
    ],
    "branding": { "appName": "Acme", "tagline": "On vous simplifie la vie" },
    "languages": ["fr", "en"]
  }'
```

Add `--dry_run` to preview the target files (and the strategy per file) without writing.

### Spec fields

| Field | Required | Notes |
|---|---|---|
| `projectPath`, `appCode` | ✅ | generated app root + app code |
| `home` | — | `{ sections[] }` → overrides `/` |
| `pages` | — | `[{ name (PascalCase), path (absolute, not reserved), layout, title?, sections[] }]` |
| `branding` | — | `appName`, `tagline`, `logoUrl` (white-label chrome) |
| `languages` | — | default `['fr','en']`; same copy seeds each |
| `force` | — | overwrite dev-owned pages/sections (default keeps them) |

At least one of `home` / `pages` is required. Reserved paths (`/`, `/login`,
`/register`, `/sso`, `/confirm-email`, `/forgot-password`, `/reset-password`,
`/force-change-password`, `/auth/*`, `/docs/*`, `/t/*`) are refused for `pages`.

## Output

A `generateEnvelope` on stdout: `filesCreated` / `filesModified`, plus `data`
(`homeOverridden`, `pagesRegistered`, `sectionsGenerated`, `webDir`,
`smartStackVersion`, `providerWired`, `providerSkipped`), `warnings`, `nextSteps`.

## Idempotency

- **Sections & pages** are dev-owned: written if absent, **kept** on re-run
  (`force` to overwrite). Edit them freely.
- **Locales** are **deep-merged** — new keys appear, your translated copy is preserved.
- **`vitrine.generated.ts`** is regenerated to reflect the current page set.
- **main.tsx** edit is idempotent: the import is inserted once after
  `componentRegistry.generated`, and `extensions: {}` becomes
  `extensions: { ...vitrineExtensions }`. A `// @customised` head marker skips it; if
  `extensions: {}` was already customized, the CLI prints a paste-in snippet instead.

## When NOT to use

- To restyle colors/fonts → `/scaffold-theme`.
- To configure login providers / registration → `/login-config`.
- To change the SDK login, register, or the built-in marketing home's internals →
  that lives in the SmartStack package (SmartStack.app), not a generated client app.
