---
name: fluent-mystique-scaffold
description: Scaffold a new Mystique SDK component project with webpack, TypeScript, Storybook, Jest, component registration, and i18n — ready to develop and deploy. Triggers on "scaffold component", "new mystique project", "create sdk component", "mystique sdk setup", "new ui plugin".
user-invocable: true
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
argument-hint: <project-name> [--components ComponentA,ComponentB] [--category content|layout|page|filter]
cursor-tier: manual
planning-gate: mandatory
---

# Mystique SDK Component Scaffolder

Generate a complete, buildable Mystique SDK component project from a project name and optional component list. The output is a directory under `accounts/<PROFILE>/SOURCE/frontend/` containing a React/TypeScript/webpack project that produces a `bundle.[contenthash].js` file loadable via the `plugins[]` array in any Mystique manifest.

A Mystique SDK project is a standalone React application that registers custom UI components with the Mystique ComponentRegistry. At runtime, the Fluent OMX host application loads the bundle from a URL, executes it, and the registered components become available for use in manifests alongside built-in `fc.*` components. The host application provides React, ReactDOM, Material-UI, and Mystique globals as webpack externals -- the bundle does NOT include these libraries.

## Pre-flight: Feedback Check

Before starting, check for past learnings from this skill:

1. Check if `accounts/<PROFILE>/feedback/fluent-mystique-scaffold.jsonl` exists
2. If yes, read last 20 records
3. Filter to: same component category if known, FAILURE or USER_CORRECTED outcomes, confidence = CONFIRMED or PROMOTED
4. Extract top 3 relevant learnings — use as internal "WATCH OUT" guidance during execution
5. Do NOT show raw feedback to the user — silently adjust the generated scaffold and defaults

## Pre-flight: Project Knowledge Check

Check for project-specific knowledge that should inform the generated SDK project:

1. Check if `accounts/<PROFILE>/knowledge/` exists
2. If yes, read it and find files where `relevant-skills` includes `fluent-mystique-scaffold`
   **Account knowledge:** Read from `accounts/<PROFILE>/knowledge/` when `FLUENT_PROFILE` is set. These contain project-specific conventions.

3. Read matching knowledge files — typically:
   - `knowledge/frontend/mystique-sdk.md` — use for SDK structure, hooks, testing defaults, and registration patterns
   - `knowledge/frontend/mystique-advanced-sdk.md` — use for advanced category decisions, field behavior, and test strategies
   - `knowledge/frontend/mystique-components.md` — use for OOTB component composition patterns
   - `knowledge/frontend/mystique-patterns.md` — use for layout, styling, and plugin integration patterns
   - `knowledge/platform/user-action-contract.md` — use when scaffolding custom fields for user actions
   - `accounts/<PROFILE>/knowledge/naming-conventions.md` — use for component aliases, route naming, and i18n key prefixes
   - `accounts/<PROFILE>/knowledge/coding-standards.md` — use for testing, folder structure, and code quality conventions
   - `accounts/<PROFILE>/knowledge/client/data-model.md` — use for entity types and attributes surfaced in UI
   - `accounts/<PROFILE>/knowledge/client/integrations.md` — use when the scaffold includes external service calls or integration-specific helpers
4. If `accounts/<PROFILE>/memory/index.md` exists, read the top account-specific frontend, Storybook, test, and deployment gotchas and apply them silently.
5. Apply knowledge silently — do NOT show raw knowledge to user, just follow the conventions in the generated scaffold

## OMX Component SDK — Source Template

Every Mystique SDK project starts from the **OMX Component SDK** template zip (or an existing SDK source folder/repo provided by the user).

**Download URL (always latest):** `https://fluent.apps.fluentcommerce.com/_sdk/latest/omx-component-sdk.zip`

### Getting the SDK template

Ask first whether the user already has an SDK source repo/folder to extend. Use that source directly when available. Download/extract only when no source exists.

```bash
# Check if SDK template already exists in workspace
ls accounts/<PROFILE>/SOURCE/frontend/omx-component-sdk/ 2>/dev/null

# If not found, download and extract
curl -L -o /tmp/omx-component-sdk.zip "https://fluent.apps.fluentcommerce.com/_sdk/latest/omx-component-sdk.zip"
unzip /tmp/omx-component-sdk.zip -d /tmp/omx-sdk-tmp
# The zip contains omx-component-sdk/omx-component-sdk/ (double-nested)
cp -r /tmp/omx-sdk-tmp/omx-component-sdk/omx-component-sdk accounts/<PROFILE>/SOURCE/frontend/<project-name>
rm -rf /tmp/omx-sdk-tmp /tmp/omx-component-sdk.zip
```

### Project structure (one project = one bundle = one or more components)

Each SDK project produces a **single `bundle.[hash].js`** file. You can register **multiple components** in one project — they all ship in the same bundle. Create separate projects only when components belong to unrelated domains or need independent deployment.

**Simple project (1-2 components):**

```text
accounts/<PROFILE>/SOURCE/frontend/<project-name>/
├── @types/mystique/          # SDK type definitions (hooks, registries, components)
├── @types/mystique-barrel.d.ts  # Barrel declarations + runtime-accurate useQuery type
├── build/                    # Webpack plugins (GenerateVersionPlugin, GenerateManifestsPlugin)
├── i18n/locales/             # Translation files (en.json, etc.)
├── manifests/                # TypeScript manifest definitions (compiled to JSON at build)
├── src/
│   ├── index.tsx             # ENTRY POINT — all ComponentRegistry/FieldRegistry.register() calls
│   ├── components/           # Custom components (one dir per component)
│   │   └── MyComponent/
│   │       ├── MyComponent.tsx
│   │       ├── MyComponent.test.tsx
│   │       └── MyComponent.stories.tsx
│   ├── fields/               # Custom form fields (for user action dialogs)
│   │   └── MyField/
│   │       └── MyField.tsx
│   ├── hooks/                # Custom React hooks
│   └── utils/                # Shared utilities
├── package.json              # Dependencies (devDeps only — React/MUI are externals)
├── webpack.config.ts         # Webpack config with externals for React/MUI/Mystique
├── tsconfig.json             # TypeScript config
├── jest.config.js            # Test config
└── sdk-version.json          # SDK template version
```

**Multi-component project (3+ components) — container/presentation split:**

When a project has 3+ registered components, use a structured layout that separates registered containers from internal reusable pieces:

```text
accounts/<PROFILE>/SOURCE/frontend/<project-name>/
├── ... (same config files as simple project)
├── src/
│   ├── index.tsx                    # Registration ONLY — thin, no logic
│   ├── components/                  # Registered components (containers)
│   │   ├── OrderSummary/
│   │   │   ├── OrderSummary.tsx     # Data-fetching container (registered)
│   │   │   ├── OrderSummaryView.tsx # Pure presentation (NOT registered)
│   │   │   ├── OrderSummary.test.tsx
│   │   │   ├── OrderSummary.stories.tsx
│   │   │   └── index.ts
│   │   └── FulfilmentTracker/
│   │       ├── FulfilmentTracker.tsx
│   │       ├── FulfilmentTrackerView.tsx
│   │       └── ...
│   ├── fields/                      # Registered form fields
│   ├── shared/                      # Internal reuse (NOT registered, NOT exported)
│   │   ├── hooks/                   # useEntityStatus, useFormattedCurrency, usePagination
│   │   ├── utils/                   # formatDate, buildQueryFilter, extractEdgeNodes
│   │   └── components/              # StatusBadge, CurrencyDisplay, LoadingCard
│   └── types/                       # Shared TypeScript interfaces
│       └── index.ts                 # OrderData, FulfilmentData, etc.
```

**Key principles:**

| Directory | Contains | Registered? | Imported by |
|---|---|---|---|
| `src/components/` | Container components that call hooks and pass data down | YES — `ComponentRegistry.register()` | `src/index.tsx` only |
| `src/fields/` | Form field components for user action dialogs | YES — `FieldRegistry.register()` | `src/index.tsx` only |
| `src/shared/` | Internal hooks, utils, and presentation components | NO — never registered | `src/components/`, `src/fields/` |
| `src/types/` | Shared TypeScript interfaces | NO | Any `src/` file |

**Container/presentation split within components:**

Registered components should be **thin containers** — they call host hooks and pass the result to a pure presentation component. This keeps data-fetching logic testable in isolation.

**Mandatory data access order for registered components:**
1. Prefer the host-provided `data` prop / `useData()` when the page or nearest provider already owns the query.
2. Prefer manifest `dataSource` scoping and `<Children />` composition for parent -> child data flow.
3. If descendants need transformed parent data, wrap them with `<Children dataOverride={...} />`.
4. If the manifest should own a second query, use page `dataSources` or `fc.provider.graphql` instead of hiding the fetch in component code.
5. Use `useQuery()` only when the data is truly component-private or the host context is unavailable (for example user action field dialogs).

```typescript
// OrderSummary.tsx — container (registered, calls hooks)
export const OrderSummary: FC<OrderSummaryProps> = ({ data, title }) => {
  const { context } = useAuth();
  const settings = useSettings({ key: 'order.display.config' });
  return <OrderSummaryView order={data} retailerId={context.current.contextId} config={settings} title={title} />;
};

// OrderSummaryView.tsx — presentation (NOT registered, pure render)
export const OrderSummaryView: FC<OrderSummaryViewProps> = ({ order, retailerId, config, title }) => {
  // Pure rendering — no hooks, no side effects, easy to test and reuse
  return (
    <Card title={title}>
      <StatusBadge status={order?.status} />
      <CurrencyDisplay amount={order?.totalPrice} />
    </Card>
  );
};
```

**When to create `shared/`:** Generate the `shared/` directory structure when `--components` has 3+ entries, or when the project already has 3+ registered components. For 1-2 component projects, the flat structure is fine — don't over-engineer.

### Build and deploy workflow

```bash
cd accounts/<PROFILE>/SOURCE/frontend/<project-name>

# 1. Install dependencies (first time only)
yarn install

# 2. Development — hot-reload at localhost:3001
yarn start

# 3. Production build → dist/bundle.[hash].js + dist/version.json + dist/i18n/
yarn build              # webpack --mode production && build tests

# 4. Webpack only (no tests)
yarn bundle

# 5. Run tests
yarn test               # Jest with coverage

# 6. Storybook — visual component testing
# NOTE: Node 18+ requires --openssl-legacy-provider for Storybook 6.x (all 5 OOTB plugins use this)
yarn storybook          # serves on port 6006

# 7. Lint
yarn lint               # ESLint check
yarn lint:fix           # ESLint auto-fix

# 8. Deploy: host dist/ contents on a CDN (S3, Vercel, etc.)
#    Then reference in manifest via plugins[] array:
#    "plugins": [{ "type": "url", "src": "https://cdn.example.com/my-plugin/" }]
```

### Mandatory Documentation + Quality Gates

Every scaffolded or extended SDK project must include implementation guidance and pass a repeatable quality gate before handoff.

**Documentation gate (required):**
- Ensure a project `README.md` exists and is updated with:
  - Purpose and scope of the plugin
  - Local setup (`yarn install`, `yarn start`, `yarn test`, `yarn build`)
  - Registered aliases and where they are declared (`src/index.tsx`)
  - Component data-access strategy (`props.data` / `useData`, `dataSource`, `Children`, provider-owned queries, any justified `useQuery`)
  - Manifest plugin configuration (localhost and production folder URL with trailing `/`)
  - Deployment and rollback notes (including `version.json` behavior)
  - Troubleshooting notes for common runtime issues (missing globals, stale bundle, wrong plugin URL)

**Code clarity gate (required):**
- Add succinct comments only for non-obvious logic (complex data transforms, hook orchestration, side-effects).
- Do not add noisy comments for obvious assignments or JSX structure.

**Quality gate (required):**
1. `yarn check-types` (or `npx tsc --noEmit`)
2. `yarn lint`
3. `yarn test --coverage`
4. `yarn build`
5. Review each registered component's data contract: what owns the query, how data reaches descendants, and why any `useQuery()` call cannot be replaced by `useData()`, `dataSource`, or `fc.provider.graphql`
6. Verify `dist/version.json` and at least one `dist/bundle.[hash].js` exist

If any gate fails, fix issues before declaring READY.

### Component Modularization (projects with 3+ components)

For projects with more than a couple of components, enforce internal structure that separates registered entry points from reusable internals:

```text
src/
├── index.tsx                        # ONLY registry calls — thin, no logic
├── components/                      # Registered ComponentRegistry entries (containers)
│   ├── OrderSummary/
│   │   ├── OrderSummary.tsx         # Data-fetching container (uses useData/useQuery)
│   │   ├── OrderSummaryView.tsx     # Pure presentation (receives props, no hooks)
│   │   ├── OrderSummary.test.tsx
│   │   ├── OrderSummary.stories.tsx
│   │   └── index.ts
│   └── StoreMap/
│       └── ...
├── fields/                          # Registered FieldRegistry entries
│   └── AppeasementAmount/
│       └── ...
├── shared/                          # Internal reuse — NOT registered with any registry
│   ├── components/                  # Presentational building blocks (StatusBadge, CurrencyDisplay)
│   ├── hooks/                       # Custom hooks (useEntityStatus, useFormattedCurrency)
│   ├── utils/                       # Pure functions (formatDate, buildQueryFilter)
│   └── constants.ts                 # Shared constants, enums
└── types/                           # Shared TypeScript interfaces
    ├── order.ts                     # Entity-specific types
    └── common.ts                    # Cross-entity types
```

**Key principles:**

1. **Registered components are thin containers.** They call hooks (`useData`, `useQuery`, `useAuth`) and pass results to internal presentational components. This makes presentational components testable without mocking Mystique hooks.

2. **Shared internals are never registered.** `shared/components/StatusBadge.tsx` is imported by multiple registered components but is not in any registry. It is purely internal to the bundle.

3. **Container/presentation split.** The container fetches data and manages state. The view/presentation component receives typed props and renders JSX. This split enables:
   - Unit testing the view with plain props (no hook mocking)
   - Reusing the view in Storybook with static data
   - Swapping data sources without touching the UI

4. **Shared hooks extract repeated logic.** If `OrderSummary` and `StoreMap` both need formatted currency, create `shared/hooks/useFormattedCurrency.ts` rather than duplicating the logic.

5. **One bundle = one domain.** All components in one project share the same bundle. Split into separate projects only when: (a) components serve completely unrelated domains, (b) teams need independent deploy cycles, or (c) bundle size exceeds 200KB.

#### Cross-Project Reuse

For implementations with multiple SDK projects sharing common utilities:

| Approach | When to use |
|---|---|
| Internal `shared/` folder | Single project (most cases) — simplest, no external deps |
| Copy with convention | 2 projects sharing a few utilities — pragmatic, most teams do this |
| Shared npm package (`@acme/mystique-shared`) | 3+ projects with substantial shared code — publish hooks, utils, types as a dev dependency |

Most Fluent implementations have 1-2 SDK projects. The internal `shared/` folder handles the vast majority of reuse needs.

### Three registries — pick the right one

| Registry | Use when | Registration pattern |
|----------|----------|---------------------|
| `ComponentRegistry` | Custom visual component for manifest `"component": "alias"` | `ComponentRegistry.register(['alias'], Component, {category: 'content'})` |
| `FieldRegistry` | Custom form field for user action dialogs | `FieldRegistry.register(['typeName'], Field)` — workflow attribute `"type": "typeName"` maps to this |
| `TemplateRegistry` | Custom Handlebars helper for template strings | `TemplateRegistry.register('helperName', fn)` |

All registrations happen in `src/index.tsx`. The manifest references components by their registered alias.

### Naming Convention (MANDATORY — consistent across all registries)

All registries use the same `<namespace>.<segment>.<kebab-name>` dot-separated pattern:

| Registry | Pattern | Example |
|----------|---------|---------|
| `ComponentRegistry` | `<namespace>.<category>.<kebab-name>` | `appeasement.content.create-appeasement-action` |
| `FieldRegistry` | `<namespace>.fields.<kebab-name>` | `appeasement.fields.amount-calculator` |
| `TemplateRegistry` | `<namespace>.helpers.<kebab-name>` | `appeasement.helpers.format-currency` |

**Rules:**
1. **Namespace** — derived from project name (see Namespace Detection). Prefer a custom namespace over `fc.` (used by OOTB). `fc.custom.*` is acceptable but a project-specific namespace is safer.
2. **Segment** — `content`, `page`, `layout`, `filter` for ComponentRegistry; `fields` for FieldRegistry; `helpers` for TemplateRegistry.
3. **Name** — kebab-case, descriptive. Match the component/field directory name.
4. **No camelCase, no PascalCase** in aliases — always kebab-case for the name segment.
5. **Register one canonical alias** per component/field. Do NOT register multiple aliases (e.g., both dot-separated and camelCase) unless migrating from a legacy name.

### Component Category Quick Matrix

Choose `--category` based on rendering role and data behavior:

| Category | Use when | Data behavior | `<Children />` impact | Typical API |
|---|---|---|---|---|
| `page` | Replacing full route/page shell | Unscoped page query result | Core pattern; usually required | `useData`, `useUserActions`, `<Children />` |
| `layout` | Composing descendants/layout regions | Scoped by parent `dataSource` | Core pattern; often required | `<Children />`, `dataOverride` |
| `content` | Rendering normal widget/card/action block (default) | Scoped by parent `dataSource` | Optional | `<DynamicValue />`, `TemplateRegistry.render`, `useData` |
| `filter` | Changing query variables for list/search/filter | Scoped + mutable variables | Usually none | `useData().variables.setVariables()` |

**Category applies to ComponentRegistry only.** FieldRegistry and TemplateRegistry do not use categories.

**Key behaviors:** `filter` components calling `setVariables(newVars, true)` re-execute the page query — all sibling components re-render. `page` components own `useUserActions()` — only they should render workflow action buttons. Layout components use `<Children index={N} />` for slot-based rendering.

**Wrong category → what breaks:** `content` as `page` = unscoped data (wrong/empty rendering). `page` as `layout` = `useUserActions()` returns empty (no action buttons). `filter` as `content` = works technically, but validation tooling won't flag missing variable bindings.

When in doubt, use `content`. Full decision tree and category/data-behavior matrix: `/fluent-mystique-sdk-reference`.

## Source Layout Convention (Backend vs Frontend)

Use a clean split under `accounts/<PROFILE>/SOURCE/`:

```text
accounts/<PROFILE>/SOURCE/
├── backend/   # Java modules, plugins, workflow deployment modules
└── frontend/  # OMX Component SDK projects (Mystique)
```

For this skill, always scaffold and extend UI projects in `accounts/<PROFILE>/SOURCE/frontend/`. When searching for existing SDK projects, use recursive search under `SOURCE/**` so both legacy flat layouts and split layouts are detected.

## Pre-Check: Build vs Configure

**ALWAYS run this check FIRST. Most UI requirements can be met with manifest configuration alone — only scaffold a custom SDK component when OOTB components genuinely cannot cover the need.**

```
User asks: "I need a UI component" / "Create a custom component"
|
+-- Step 0: Build vs Configure (MANDATORY)
|   Grep components/*.md in /fluent-mystique-builder for matching capability
|   +-- Found a match? → STOP. Redirect to /fluent-mystique-builder (configure via manifest)
|   +-- Close match? → STOP. Compose OOTB components (fc.conditional + fc.repeater + fc.provider.graphql)
|   +-- Need a custom form field only? → Lightweight: FieldRegistry.register() (see below)
|   +-- Genuinely no OOTB equivalent? → Proceed to Step 1 (scaffold)
|
|   SDK is needed ONLY for: novel visualizations, drag-and-drop, external service
|   integrations, real-time/WebSocket features, Canvas rendering, or interaction
|   patterns not covered by user action forms + OOTB components.
```

## Pre-Check: New Project or Extend Existing?

**If Step 0 confirmed an SDK component is needed, run this decision tree before scaffolding. Do NOT skip.**

```
+-- 1. Discover existing SDK projects in workspace
|   Search: accounts/<PROFILE>/SOURCE/frontend/**/package.json (look for mystique deps)
|   Search: accounts/<PROFILE>/SOURCE/frontend/**/webpack.config.*
|   Search: accounts/<PROFILE>/SOURCE/frontend/**/@types/mystique/
|   List found projects with their registered components
|
+-- 2. Check deployed plugins in live manifests
|   Look for plugins[] array entries in deployed manifests
|   Cross-reference with local SOURCE/frontend/
|
+-- 3. Evaluate: does the new component fit an existing project?
|   +-- YES -> Add component to existing project (just generate component files)
|   +-- NO -> Genuinely new domain, proceed with full scaffolding
|   +-- UNCLEAR -> Ask user
```

### Source Code Availability Check

Before extending an existing project, verify the source is accessible:

| Source State | Action |
|---|---|
| `accounts/<PROFILE>/SOURCE/frontend/<project>/` exists with `package.json` + `@types/mystique/` | Ready -- add component files directly |
| Plugin deployed but no source in `SOURCE/frontend/` | Ask user to clone repo into `SOURCE/frontend/` |
| Source exists but registered components unknown | Read `src/index.tsx` to discover existing registrations |

## Planning Gate

### Pre-flight Chain (Three-Level)

Before scaffolding any SDK component project, run the three-level pre-flight check matching the backend and manifest-builder rigor:

1. **Feature check:** If `accounts/<PROFILE>/features/<slug>/status.json` exists for this work:
   - Check `spec: "APPROVED"` -- If missing, BLOCK -- redirect to `/fluent-use-case-discover`
   - Check `plan: "APPROVED"` -- If missing, BLOCK -- redirect to `/fluent-feature-plan`
   - If both approved, proceed with implementation

2. **Standalone SDK project work** (no feature context):
   - Write plan to `accounts/<PROFILE>/features/<slug>/plan.md` (NOT `tasks/`) -- create feature directory with status.json
   - status.json: `{ "status": "PLANNING", "spec": null, "plan": "PENDING" }` (spec skipped for standalone SDK work with explicit user acknowledgment)
   - Plan must cover the items listed below
   - Wait for user approval -- set `plan: "APPROVED"` before scaffolding

3. **Multi-artifact work** (SDK component + manifest + workflows + settings):
   - STOP. Invoke `/fluent-feature-plan` first -- this is the unified entry point
   - Feature plan must include SDK component sections and be approved

### Plan Verification

After the pre-flight chain passes, verify the plan covers SDK-scaffold-specific concerns. Same pattern as `/fluent-module-scaffold`.

**Mystique-scaffold specific emphasis -- ensure these are covered:**

1. **Component inventory** -- names, aliases, categories, props interface for each component
2. **Data dependencies** -- what GraphQL entities/queries each component will need
3. **Styling approach** -- Material-UI theme extension or custom CSS via Emotion
4. **Integration points** -- which manifest pages will use these components
5. **Testing strategy** -- unit tests, Storybook stories, Cypress E2E
6. **Hosting strategy** -- where the production bundle will be deployed (Vercel, S3, CDN)
7. **i18n strategy** -- multi-language requirement (see i18n section below)

**Write the plan to:** `accounts/<PROFILE>/features/<slug>/plan.md` (create directory if needed). Set `Status: PENDING` in status.json.

Present the full plan content to the user and wait for approval before generating any files. On approval, update status.json to `plan: "APPROVED"`. If the user says "just do it", proceed directly (still write the file for audit trail).

## Handoff Protocol

### Signals emitted by this skill

| Signal | Condition | Example |
|--------|-----------|---------|
| `-> READY: <path>` | Project directory scaffolded | `-> READY: accounts/MY_PROFILE/SOURCE/frontend/mystique-plugin-curbside/` |
| `-> NEXT: /fluent-<skill>` | Ready for manifest wiring | `-> NEXT: /fluent-mystique-builder` |
| `-> BLOCKED: <reason>` | Cannot proceed | `-> BLOCKED: PLAN_REQUIRED -- Write a plan via /fluent-feature-plan` |
| `-> SKIP: <reason>` | Existing project covers the domain | `-> SKIP: Extend existing project mystique-plugin-hm. Add component files directly` |

### Error codes

| Code | Condition | Recovery |
|------|-----------|----------|
| `PLAN_REQUIRED` | Scaffolding attempted without approved plan | Run `/fluent-feature-plan` first |
| `VALIDATION_FAILED` | Project name conflicts or invalid component names | Fix input parameters |

## When to Use

- Creating a brand-new Mystique SDK component project from scratch
- Starting a greenfield UI plugin that needs webpack, TypeScript, Storybook, Jest, and component registration
- Bootstrapping a component project for a new feature requiring custom UI beyond built-in `fc.*` components
- Generating a project shell to be populated incrementally with new components

## Ownership Boundary

This skill owns:

- Creating the complete SDK project directory structure
- Generating `package.json` with correct dependencies and scripts
- Generating `webpack.config.ts` with proper externals (React, ReactDOM, Material-UI, Mystique)
- Generating `tsconfig.json` with strict TypeScript configuration
- Generating `jest.config.js` with ts-jest, mocks, and coverage thresholds
- Generating `.babelrc` with React/TypeScript/Emotion presets
- Copying `@types/mystique/` type definitions (7 files) and generating `@types/mystique-barrel.d.ts`
- Generating `lib/` SDK initialization files (init.js, mystique.js, mystique-export.js, material-ui.js)
- Generating Storybook configuration (`.storybook/main.ts`, `preview.js`, `helpers.ts`)
- Generating component files with test and story for each `--components` entry
- Generating `src/index.tsx` with ComponentRegistry registrations
- Generating example manifest in `manifests/`
- Generating `src/index.html` for dev server
- Generating `.gitignore`, `.eslintrc.js`

This skill does **not** own:

- Creating or editing Mystique manifests --> `/fluent-mystique-builder`
- Validating manifest JSON --> `/fluent-mystique-validate`
- Analyzing existing manifests --> `/fluent-mystique-analyze`
- Deploying manifests as settings --> `/fluent-settings`
- Building/deploying Java modules --> `/fluent-build`, `/fluent-module-deploy`

## Inputs

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `project-name` | Yes | -- | Project directory name (e.g., `mystique-plugin-curbside`). Used for directory name and package.json name. Lowercase alphanumeric with hyphens. |
| `--components` | No | -- | Comma-separated PascalCase component names to scaffold (e.g., `OrderTracker,StoreMap`). Each gets a `.tsx`, `.test.tsx`, `.stories.tsx`, and `index.ts`. |
| `--category` | No | `content` | Default component category for ComponentRegistry registration. Valid: `page`, `layout`, `content`, `filter`. |
| `--namespace` | No | Auto-detect from project name | Component alias prefix (e.g., `acme` produces aliases like `acme.content.order-tracker`). |
| `--profile` | No | Active profile | Fluent CLI profile for path resolution |
| `--i18n` | No | `en` | Comma-separated locale codes (e.g., `en,fr,de`). Creates translation files per locale. Use `en` for English-only projects. |

## i18n Strategy — Guided Decision

During scaffold, determine the i18n approach. If not specified via `--i18n`, ask:

**Question:** "Does this project need multi-language support?"

| Answer | Action |
|--------|--------|
| **English-only** (internal tools, admin dashboards, single-market) | Create `i18n/locales/en/translation.json` only. Use `translateOr` with English fallbacks. |
| **Multi-language** (customer-facing, multi-market, Store app) | Create `i18n/locales/{locale}/translation.json` for each locale. Add all user-visible strings as i18n keys. |
| **Deferred** (don't know yet) | Create `en` only. Add a `// TODO: Add locales when i18n requirements are known` comment in webpack copy plugin config. |

**i18n key naming convention (MUST follow):**

```
{company}.{app}.{area}.{component}.{element}.{attribute}
```

Examples from Fluent's own plugins:
```
fc.sf.ui.pack.index.title              → "Pack"
fc.sf.ui.wave.createWave.list.header.customer  → "Customer"
fc.sf.ui.returns.scan.toast.none       → "Scanned item not found"
fc.sf.ui.pack.snackbar.maxQuantity.label → "Item {{scannedValue}} maximum quantity already reached"
```

For custom projects, replace `fc.sf` with `{company}.{app}`:
```
acme.oms.appeasement.field.amount.label → "Appeasement Amount"
acme.store.pack.toast.scanSuccess       → "Item scanned: {{barcode}}"
```

**Rules:**
- Every user-facing string MUST use `translateOr(['key', 'English fallback'])` — never hardcode
- Interpolation uses `{{variableName}}` — Handlebars syntax inside i18n values
- Manifest `title`, `label`, `menuLabel` should use `i18n:key` prefix for framework resolution
- Settings-driven configs with labels should use `recursiveValueDecorator` for bulk translation (see `/fluent-mystique-sdk-reference`)

## Pre-Check: Project Already Exists?

Before creating anything, check if the target directory already exists:

```
accounts/<PROFILE>/SOURCE/frontend/<project-name>/
```

If it exists, **abort** with message:
```
Project directory already exists: accounts/<PROFILE>/SOURCE/frontend/<project-name>/
Use this skill with --components to add components to the existing project, or choose a different name.
```

## Namespace Detection

The namespace is used in ALL registry aliases following the pattern `<namespace>.<segment>.<kebab-name>`. Detection order:

```
1. If --namespace provided, use it directly

2. Else derive from project-name:
   mystique-plugin-curbside    -> curbside
   mystique-plugin-acme-custom -> acme
   fluent-component-acme       -> acme
   Strip "mystique-plugin-" or "fluent-component-" prefix, take first word

3. Fallback: "custom"
   Warn user: "Could not derive namespace. Components will use 'custom.*' aliases."
```

## Generated Directory Structure

```
accounts/<PROFILE>/SOURCE/frontend/<project-name>/
+-- package.json                    # Dependencies, scripts, browserslist
+-- tsconfig.json                   # TypeScript config (strict mode, ES6 target)
+-- webpack.config.ts               # Bundle output with content hash, externals
+-- jest.config.js                  # Jest with ts-jest, coverage thresholds
+-- .babelrc                        # Babel presets for React/TypeScript/Emotion
+-- .eslintrc.js                    # ESLint config for TypeScript + React
+-- .gitignore
+-- sdk-version.json                # SDK version tracking
+-- .storybook/
|   +-- main.ts                     # Storybook webpack config with externals
|   +-- preview.js                  # Decorators, viewport config
|   +-- helpers.ts                  # Story template utility
|   +-- Storyshots.test.ts          # Snapshot testing for stories
+-- @types/
|   +-- images.d.ts                 # Image import declarations
|   +-- mystique-barrel.d.ts        # Barrel modules + runtime-accurate useQuery signature
|   +-- mystique/                   # Mystique SDK type definitions
|       +-- index.d.ts              # Common types (QueryResponse, Connection, Edge)
|       +-- manifest.d.ts           # Full manifest schema types (MystiqueManifest, Route, Page, Section)
|       +-- components.d.ts         # Component prop interfaces (Card, List, Children, DynamicValue, Loading)
|       +-- hooks.d.ts              # Hook definitions (useAuth, useQuery, useSettings, useI18n, useData, useRest, useUserActions)
|       +-- services.d.ts           # Service types (MystiqueThemeColours)
|       +-- registry.d.ts           # Registry interfaces (ComponentRegistry, FieldRegistry, TemplateRegistry)
|       +-- frame.d.ts              # Modal/Drawer/Toast utilities (pushModal, pushDrawer, pushToast)
+-- i18n/
|   +-- locales/
|       +-- en/
|           +-- translation.json    # Initial i18n keys
+-- lib/
|   +-- init.js                     # Global setup: React, ReactDOM, MaterialUI, Emotion on globalThis
|   +-- material-ui.js              # MaterialUI UMD global (bundled for Storybook/Jest)
|   +-- mystique.js                 # Mystique global object (bundled for Storybook/Jest)
|   +-- mystique-export.js          # Named exports from globalThis.Mystique for import resolution
+-- src/
|   +-- index.tsx                   # Entry point -- ComponentRegistry.register() calls
|   +-- index.html                  # Dev server HTML with CDN React/ReactDOM
|   +-- setup-tests.ts              # Jest setup (Emotion matchers)
|   +-- components/                 # Registered components (containers)
|   |   +-- <ComponentName>/
|   |       +-- <ComponentName>.tsx       # Container: hooks + data fetching
|   |       +-- <ComponentName>View.tsx   # Presentation: pure render (3+ component projects)
|   |       +-- <ComponentName>.test.tsx  # Unit test
|   |       +-- <ComponentName>.stories.tsx  # Storybook story
|   |       +-- index.ts                  # Re-export
|   +-- shared/                     # Internal reuse — NOT registered (3+ component projects)
|   |   +-- hooks/                  # useEntityStatus, useFormattedCurrency
|   |   +-- utils/                  # formatDate, buildQueryFilter, extractEdgeNodes
|   |   +-- components/             # StatusBadge, CurrencyDisplay, LoadingCard
|   +-- types/                      # Shared TypeScript interfaces (3+ component projects)
|   |   +-- index.ts
|   +-- utils/
|       +-- GqlUtils.ts             # GraphQL document-to-string utility
|       +-- TestUtils.tsx           # MaterialUI classname fix for test snapshots
+-- manifests/

## Companion Files

This skill uses companion templates plus the shared Mystique SDK reference skill. Read these at execution time:

- **TEMPLATES.md** (companion) — All file templates (package.json, webpack, tsconfig, jest, babel, storybook, component/test/story, build plugins, .gitignore)
- **`/fluent-mystique-sdk-reference`** — shared SDK API reference (hooks, registries, component patterns, field development, build lifecycle, Material-UI constraints)

## Execution Flow

```
1. VALIDATE inputs
   a. project-name: must match /^[a-z][a-z0-9-]*$/ (lowercase, hyphens allowed)
   b. component names (if --components): must match /^[A-Z][a-zA-Z0-9]*$/ (PascalCase)
   c. category (if --category): must be page|layout|content|filter

2. PRE-CHECK: Project already exists?
   a. Check accounts/<PROFILE>/SOURCE/frontend/<project-name>/ exists
   b. If exists -> ABORT with guidance (or add components if --components specified)

3. DETECT namespace
   a. If --namespace provided -> use it
   b. Else derive from project-name
   c. Fallback: "custom" with warning

4. COMPUTE derived values
   a. PROJECT_TITLE = title-case of project-name with hyphens as spaces
   b. KEBAB_NAME = kebab-case of each component name
   c. CATEGORY = from --category or default "content"
   d. Alias = <namespace>.<category>.<kebab-name>

5. CREATE directory structure
   a. Create all directories listed in the structure section
   b. Ensure all parent directories exist before writing files
   c. If --components has 3+ entries, also create: src/shared/hooks/, src/shared/utils/, src/shared/components/, src/types/
   d. Generate README.md in the project root from the README template in TEMPLATES.md

6. COPY @types/mystique/ from reference SDK
   a. Search for reference SDK: `omx-component-sdk/@types/mystique/` in the workspace
   b. If not found, ask user to download from `https://fluent.apps.fluentcommerce.com/_sdk/latest/omx-component-sdk.zip` and extract
   c. Copy all 7 .d.ts files
   d. Also copy @types/images.d.ts
   e. Generate @types/mystique-barrel.d.ts from TEMPLATES.md (barrel modules + runtime-accurate useQuery signature)

7. COPY lib/ files from reference SDK
   a. Copy mystique.js and material-ui.js (large bundled files, cannot be generated)
   b. Generate init.js, mystique-export.js from templates

8. GENERATE project config files
   a. package.json with substituted project name and description
   b. webpack.config.ts
   c. tsconfig.json
   d. jest.config.js
   e. .babelrc
   f. .gitignore
   g. sdk-version.json
   h. .storybook/main.ts, preview.js, helpers.ts

9. GENERATE source files
   a. src/index.tsx with ComponentRegistry.register() for each component + StylesProvider wrapper with createGenerateClassName({ productionPrefix: '<namespace-prefix>' })
   b. src/index.html with project title
   c. src/setup-tests.ts
   d. src/utils/GqlUtils.ts, TestUtils.tsx (includes MUI classname fix AND Mystique hook mock utilities: mockUseQuery, mockUseSetting, mockI18nProvider, mockUseAuth)
   e. manifests/fc.mystique.manifest.example.ts
   f. manifests/fc.mystique.manifest.fragment.example.ts
   g. build/GenerateVersionPlugin.ts, GenerateManifestsPlugin.ts
   h. i18n/locales/{locale}/translation.json for each locale from --i18n (default: en only)
      - en/translation.json: seed with keys for each component using naming convention: {namespace}.{app}.{component}.{element}
      - Other locales: copy en keys with empty string values (to be translated)
      - Example seed for component "OrderTracker": { "acme.oms.orderTracker.title": "Order Tracker", "acme.oms.orderTracker.loading": "Loading order data..." }

10. FOR EACH component in --components (if specified):
    a. Create src/components/<Name>/ directory
    b. Generate <Name>.tsx using component template (container — calls hooks, passes data)
    c. If 3+ components: generate <Name>View.tsx (presentation — pure render, no hooks)
    d. Generate <Name>.test.tsx using test template
    e. Generate <Name>.stories.tsx using story template
    f. Generate index.ts re-export
    g. Add import and ComponentRegistry.register() to src/index.tsx

10a. IF 3+ components: GENERATE shared layer
    a. Create src/shared/hooks/.gitkeep, src/shared/utils/.gitkeep, src/shared/components/.gitkeep
    b. Generate src/types/index.ts with placeholder interfaces for shared data types
    c. Generate src/shared/utils/extractEdgeNodes.ts — standard Relay connection → array helper
    d. Add comment in src/index.tsx: "// Shared internals: src/shared/ (hooks, utils, components) — NOT registered"

11. GENERATE README.md
    a. Create README.md from the README template in TEMPLATES.md
    b. Substitute all template variables (PROJECT_NAME, PROJECT_TITLE, NAMESPACE, component table, aliases)
    c. Include: project description, component table, build instructions, manifest configuration, deploy + rollback notes, troubleshooting
    d. Add succinct code comments for non-obvious logic only (complex transforms, hook orchestration, side-effects)
    e. Add `@see /fluent-mystique-sdk-reference` header comment in generated src/index.tsx

11b. GRAPHQL VALIDATION GATE (if components contain queries)
    For each generated component that includes a useQuery() call or GraphQL template string:
    a. Extract the query string from the generated .tsx file
    b. Call: graphql.validate({ query: '<extracted query>' })
    c. Check response.valid (NOT response.ok)
    d. If valid: false → fix the query in the generated file, re-validate
    e. If valid: true → proceed to quality gate
    f. If MCP unavailable → add // TODO: Validate GraphQL comment in generated file, proceed
    Full protocol: knowledge/platform/graphql-preflight.md

12. QUALITY GATE
    a. If yarn is available: yarn install (if first run)
    b. yarn check-types (or npx tsc --noEmit)
    c. yarn lint
    d. yarn test --coverage (fallback to `yarn test` if script already includes coverage/ignore flags)
    e. yarn build
    f. verify dist/version.json + dist/bundle.[hash].js exist

13. REPORT generated files
    List all files created with their full paths.
    Include quality gate pass/fail summary.
    Print next steps:
    - "Project scaffolded at: accounts/<PROFILE>/SOURCE/frontend/<project-name>/"
    - "Install dependencies: cd accounts/<PROFILE>/SOURCE/frontend/<project-name> && yarn install"
    - "Test locally (recommended first): /fluent-frontend-build dev (starts localhost:3001, wires manifest, hot-reload)"
    - "Run tests: yarn test"
    - "Run Storybook: yarn storybook (serves on http://localhost:6006)"
    - "Production build: /fluent-frontend-build full (7-gate pipeline → dist/bundle.[hash].js)"
    - "Next: Wire components into a manifest with /fluent-mystique-builder"
```

## Integration with Other Skills

| Skill | Relationship |
|-------|-------------|
| `/fluent-mystique-builder` | After scaffolding, use this to create or edit manifests that reference the new components via their registered aliases. |
| `/fluent-mystique-validate` | Validate manifests that reference the new components. Checks that component aliases are known and props are well-formed. |
| `/fluent-mystique-analyze` | Analyze deployed manifests to understand existing component usage before adding new ones. |
| `/fluent-settings` | Deploy the compiled manifest JSON as a Fluent Setting for production use. |
| `/fluent-frontend-build` | Run local dev loop (`dev`) and production quality gates (`full`) for the scaffolded SDK project. |
| `/fluent-frontend-review` | Audit code quality and SDK compliance before release deployment. |
| `/fluent-frontend-readme` | Generate/update README from actual source registrations and usage patterns. |
| `/fluent-ui-test` | Verify end-to-end browser behavior after deployment (rendering, actions, data loading). |
| `/fluent-feature-plan` | Required for multi-artifact work (SDK + manifest + workflows). Produces the comprehensive plan. |

### Post-Scaffold Workflow

```
/fluent-mystique-scaffold mystique-plugin-curbside --components CurbsideStatus,StoreMap --category content
    |
    v
/fluent-frontend-build dev   (start localhost hot-reload loop on http://localhost:3001/)
    |
    v
/fluent-mystique-builder   (manifest plugins[] -> http://localhost:3001/ and wire component aliases)
    |
    v
/fluent-ui-test   (verify local behavior; iterate quickly on code-only fixes)
    |
    v
/fluent-frontend-build full   (run production quality gates + bundle output verification)
    |
    v
/fluent-mystique-validate   (validate manifest before release deploy)
    |
    v
vercel deploy --prod   (deploy bundle to hosting)
    |
    v
/fluent-settings   (switch manifest plugins[] from localhost to CDN URL and deploy)
    |
    v
/fluent-ui-test   (verify end-to-end behavior in browser)
    |
    v
FAIL? -> local loop: /fluent-frontend-build dev -> fix -> retest -> then /fluent-frontend-build full -> redeploy -> /fluent-ui-test
```

## Edge Cases

### No components specified

When `--components` is omitted:
- `src/index.tsx` contains only a comment: `// Register your components here`
- No component directories are created
- The project is still buildable (produces a bundle with no registrations)
- This is valid as a starting point -- add components incrementally

### Project name conflicts

Check for any directory matching the project name:

```bash
ls accounts/<PROFILE>/SOURCE/frontend/ | grep -i "<project-name>"
```

If found, abort. Do NOT overwrite an existing project.

### Reference SDK not available

If no `omx-component-sdk/` directory is found in the workspace:

1. **Ask the user first**: "Do you already have an OMX Component SDK source folder/repo I should use?"
2. **If user has source**, use that path directly (do not download).
3. **If user wants download**, fetch and extract the latest SDK:
   - **PowerShell (Windows):**
   ```powershell
   Invoke-WebRequest -Uri "https://fluent.apps.fluentcommerce.com/_sdk/latest/omx-component-sdk.zip" -OutFile ".\omx-component-sdk.zip"
   Expand-Archive -Path ".\omx-component-sdk.zip" -DestinationPath ".\" -Force
   Remove-Item ".\omx-component-sdk.zip"
   ```
   - **Bash (macOS/Linux):**
   ```bash
   curl -L -o "./omx-component-sdk.zip" "https://fluent.apps.fluentcommerce.com/_sdk/latest/omx-component-sdk.zip"
   unzip "./omx-component-sdk.zip" -d "./"
   rm "./omx-component-sdk.zip"
   ```
4. **If user declines download**:
   - Generate `@types/mystique/` files from the embedded templates (all 7 SDK files + `@types/mystique-barrel.d.ts`)
   - Warn about missing `lib/mystique.js` and `lib/material-ui.js`
   - The project will build but tests and Storybook will fail without these lib files

### Windows path handling

- All webpack paths use forward slashes (Node.js standard)
- Use `path.join()` and `path.resolve()` in webpack config, not hardcoded separators
- Build scripts use `yarn` (cross-platform) rather than shell-specific commands

### Duplicate component names

If `--components` contains duplicates, deduplicate silently and warn:
```
Warning: Duplicate component name 'OrderTracker' removed from list.
```

### Component name validation

Reject component names that:
- Start with a lowercase letter or digit
- Contain hyphens, underscores, or spaces (must be PascalCase)
- Are empty or longer than 50 characters
- Conflict with built-in Mystique components (e.g., `Card`, `List`, `Loading`)

## Build & Development Lifecycle

### Development Cycle

```
1. Scaffold project
   /fluent-mystique-scaffold my-plugin --components OrderTracker,StoreMap

2. Install dependencies
   cd accounts/<PROFILE>/SOURCE/frontend/my-plugin/
   yarn install

3. Check if dev server already running (mandatory)
   curl -s http://localhost:3001/version.json
   -> If valid JSON is returned, reuse existing server (another agent/session may already be running it)
   -> If no response, proceed to step 4

4. Start dev server (only if step 3 found none)
   yarn start
   -> Serves on http://localhost:3001
   -> Outputs bundle.[hash].js with CORS headers

5. Point manifest plugins[] to localhost
   IMPORTANT: plugins[] goes in the ROOT manifest (fc.mystique.manifest.<app>),
   NEVER in fragment settings. Fragments contain routes[] only.
   In the ROOT app manifest (via Settings or /fluent-mystique-builder):
   {
     "plugins": [
       { "type": "url", "src": "http://localhost:3001/" }
     ]
   }

6. Test in Fluent OMX App
   -> Load the OMX app in browser
   -> The host app fetches version.json from localhost:3001
   -> Loads the hashed bundle
   -> Your components are now available in the manifest

7. Write tests
   yarn test              # Run Jest with coverage
   yarn storybook         # Visual component testing on port 6006

8. Iterate
   -> Webpack HMR reloads on save
   -> Refresh the OMX app to pick up changes
```

### Production Deployment

```
1. Build the bundle
   yarn build
   -> Produces dist/bundle.[contenthash].js
   -> Produces dist/version.json (maps bundle filename)
   -> Produces dist/manifests/*.json (compiled manifest examples)
   -> Runs build tests to verify output

2. Deploy to hosting
   Fluent Commerce does NOT host custom component bundles.
   The bundle must be self-hosted. Options:

   a) Vercel (recommended for simplicity):
      vercel deploy
      -> Returns URL like https://my-plugin.vercel.app/

   b) AWS S3 + CloudFront:
      aws s3 sync dist/ s3://my-bucket/my-plugin/ --cache-control max-age=31536000

   c) Any static hosting / CDN:
      Upload dist/ contents to your hosting provider

3. Update manifest plugins[] with production URL
   {
     "plugins": [
       {
         "type": "url",
         "src": "https://my-plugin.vercel.app/",
         "name": "my-plugin"
       }
     ]
   }

   NOTE: The trailing "/" in the src URL enables version.json auto-discovery.
   The host app fetches <src>/version.json, reads the bundle filename,
   then loads <src>/<bundle-filename>.

4. Deploy manifest to Fluent environment
   Use /fluent-mystique-builder to update the manifest, then
   /fluent-settings to upload it as a Fluent Setting.
```

### Key Deployment Facts

- **Fluent Commerce does NOT host custom component bundles.** The bundle must be self-hosted on Vercel, S3, CDN, or any static file server.
- **The manifest `plugins[]` array loads bundles by URL at runtime.** The OMX host app fetches each plugin URL, executes the JavaScript, and the `ComponentRegistry.register()` calls make components available.
- **Webpack externals ensure React, ReactDOM, and Material-UI are NOT bundled.** These are provided by the host app. Including them would cause version conflicts and dramatically increase bundle size.
- **Bundle output uses `[contenthash]` for cache busting.** The `version.json` file maps the current hash, allowing the host app to discover the latest bundle without hardcoding the hash in the manifest.
- **For local development, webpack dev server serves on port 3001** with CORS headers enabled so the host app on a different domain can load the bundle.

## Session Tracking

When invoked, log the following to the session tracking protocol (consumed by `/fluent-session`):

**On entry:**
```json
{ "skill": "fluent-mystique-scaffold", "timestamp": "<ISO-8601>", "arguments": { "projectName": "<name>", "components": ["<list>"], "category": "<cat>" } }
```

**On exit:**
```json
{ "skill": "fluent-mystique-scaffold", "outcome": "<completed|failed|skipped>", "changesProduced": ["<seq-numbers>"], "toolCallsProduced": ["<seq-numbers>"], "nextRecommended": "/fluent-mystique-builder" }
```

## Handoff

| Output Artifact | Consumed By | Path |
|----------------|-------------|------|
| SDK project with components | `/fluent-mystique-builder` (creates manifest referencing components) | `accounts/<PROFILE>/SOURCE/frontend/<project-name>/` |
| Built bundle | Manifest `plugins[]` array (loaded at runtime by host app) | `accounts/<PROFILE>/SOURCE/frontend/<project-name>/dist/bundle.[hash].js` |
| Compiled manifests | `/fluent-mystique-validate` (validates before deploy) | `accounts/<PROFILE>/SOURCE/frontend/<project-name>/dist/manifests/` |

## Error Reporting

Errors from this skill follow the standard format:

| Field | Description |
|-------|-------------|
| `phase` | Skill phase where error occurred (e.g., `pre-check`, `validation`, `generation`, `verification`) |
| `severity` | `CRITICAL` (blocks downstream), `HIGH` (needs fix), `MEDIUM` (advisory), `LOW` (informational) |
| `message` | Human-readable error description |
| `resolution` | Suggested fix or downstream skill to invoke |

## Code Documentation Standards

All generated code MUST include documentation:

### JSDoc on Components
Every generated component .tsx file must have a JSDoc block:
```tsx
/**
 * {{ComponentName}} — {{category}} component for {{description}}.
 *
 * @alias {{namespace}}.{{category}}.{{kebab-name}}
 * @category {{category}}
 * @see /fluent-mystique-sdk-reference for hook usage patterns
 */
```

### JSDoc on Props
Every Props interface must document fields:
```tsx
interface {{ComponentName}}Props {
  /** The component data from page query context */
  data?: Record<string, unknown>;
  /** Component configuration props from manifest */
  [key: string]: unknown;
}
```

### src/index.tsx Header
The entry point must have a header comment:
```tsx
/**
 * {{PROJECT_TITLE}} — Fluent Commerce Mystique Plugin
 *
 * Components registered:
 * {{#each COMPONENTS}}
 *   - {{NAMESPACE}}.{{CATEGORY}}.{{KEBAB_NAME}}
 * {{/each}}
 *
 * @see README.md for configuration and deployment
 */
```

### README.md
Every scaffolded project includes a README.md generated from the README template in TEMPLATES.md. Run `/fluent-frontend-readme` to regenerate after adding components.

## Gotchas

- **`lib/mystique.js` is ~5MB** and `lib/material-ui.js` is ~1.2MB. These are bundled Fluent Commerce SDK files that cannot be generated -- they must be copied from the reference SDK distribution. Without them, Jest will fail with `Cannot read properties of undefined (reading 'ComponentRegistry')`.
- **Storybook uses directory-based mocks, NOT lib/ UMD bundles.** The `lib/*.js` UMD bundles depend on `window.React`/`window.ReactDOM` globals which don't exist in Storybook. Instead, `.storybook/main.ts` must: (1) NOT externalize React, ReactDOM, or MaterialUI — let them resolve from `node_modules`, (2) add a webpack alias `mystique` → `.storybook/mocks/mystique/` directory with mock files matching import paths (`hooks/index.js`, `hooks/useQuery.js`, `registry/FieldRegistry.js`, `registry/ComponentRegistry.js`). Each mock exports no-op functions.
- **Webpack externals are order-sensitive (production only).** The three externals (`static map`, `externalMaterialUI`, `externalMystique`) in `webpack.config.ts` must be in an array. These are for the PRODUCTION bundle only — Storybook's `main.ts` should have NO externals.
- **OOTB externals note:** Official plugins use Webpack 4 externals callback signature `(_, module, callback)`. New projects on Webpack 5 should use the standard `({ request }, callback)` signature. Both work — Webpack 5 is backwards-compatible with the Webpack 4 form.
- **`@material-ui/core` subpath imports** (e.g., `@material-ui/core/Button`) are routed to `window.MaterialUI.Button` by the `externalMaterialUI` function in the production webpack config. The `styles` subpath is special-cased to return the root `MaterialUI` object.
- **`mystique/*` imports** (e.g., `mystique/hooks/useQuery`) all resolve to `window.Mystique` at runtime in the production bundle. In Jest, they resolve via `lib/mystique-export.js`. In Storybook, they resolve via `.storybook/mocks/mystique/`. The TypeScript type declarations in `@types/mystique/` provide compile-time safety across all three environments.
- **React 17 is the baseline.** The host Fluent OMX app provides React 17. Newer SDK versions (v1.2024.9+) support React 18 — check `sdk-version.json` before using React 18 APIs (`useId`, `useSyncExternalStore`, `useTransition`, `createRoot`).
- **OOTB canonical versions:** React 17.0.1 (17.0.2 also fine), Material-UI 4.12.x, TypeScript 4.1.3 (newer is fine), Webpack 5.74.0, Storybook 6.x, Jest 26 (29 is an acceptable upgrade). These are the versions used by all 5 OOTB reference plugins (OMS, Store, Returns, Analytics, Pack). Deviating is acceptable but note compatibility risk.
- **Storybook requires `NODE_OPTIONS='--openssl-legacy-provider'`** on Node 18+ due to OpenSSL 3.0 changes. All 5 OOTB plugins set this in their package.json scripts: `"storybook": "NODE_OPTIONS='--openssl-legacy-provider' start-storybook -p 6006"` and `"build-storybook": "NODE_OPTIONS='--openssl-legacy-provider' build-storybook"`. Without this, Storybook fails with `ERR_OSSL_EVP_UNSUPPORTED`.
- **Content hash in filename** means the URL changes on every build. The `version.json` file is the stable discovery mechanism -- the manifest `plugins[].src` should point to the directory (with trailing `/`), not the specific bundle file.
- **CORS headers are essential** for local development. Without `Access-Control-Allow-Origin: *` and `Access-Control-Allow-Private-Network: true` on the dev server, the host app cannot load the bundle from localhost:3001.
- **Storybook 6.5.x** is the last version compatible with this SDK's webpack 5 setup. Do not upgrade to Storybook 7+ without verifying compatibility.
- **The `@emotion/react` external** is mapped to `emotionReact` (not `Emotion`). This matches how `lib/init.js` sets `globalThis.emotionReact = Emotion`.
- **Manifest `plugins[]` type field:** Use `{ "type": "url", "src": "..." }` for URL-based plugins (production bundles) or `{ "type": "setting", "setting": "..." }` for setting-based plugin references.
- **Chrome Private Network Access (PNA)** blocks HTTPS pages from fetching HTTP localhost resources. The `Access-Control-Allow-Private-Network: true` header in the dev server config is required. Without it, Chrome blocks the version.json request with `net::ERR_FAILED` and `Permission was denied for this request to access the loopback address space`. If the header alone doesn't fix it (e.g., headless Chrome or Chrome DevTools MCP), launch Chrome with `--disable-features=PrivateNetworkAccessRespectPreflightResults`.

## Knowledge References

- **TEMPLATES.md** (companion) — File templates for all generated files (package.json, webpack, tsconfig, jest, babel, component, test, story, storybook, build plugins, .gitignore)
- `/fluent-mystique-sdk-reference` — SDK API reference (hooks, registries, component patterns, field development, Material-UI constraints)
- `/fluent-mystique-component` — Adding components/fields/helpers to existing SDK projects
- `../fluent-mystique-builder/components/index.md` — OOTB component alias catalog
- `../fluent-mystique-builder/SKILL.md` — Manifest patterns and troubleshooting

## Post-Execution: Feedback Capture

After completing this skill (whether success or failure), write a feedback record:

1. **Classify outcome:** `SUCCESS` (completed cleanly), `PARTIAL_SUCCESS` (completed after fixing issues), `FAILURE` (could not complete), `BLOCKED` (prereq missing), `USER_CORRECTED` (user overrode approach)
2. **Build record:** Create a `feedback-record-v1` JSON object with:
   - `skill`: `"fluent-mystique-scaffold"`
   - `feature`: feature slug if applicable, null otherwise
   - `phases`: trace of each phase with PASS/FAIL/SKIP
   - `learnings`: any gotchas discovered during execution
   - `userCorrections`: any corrections the user provided
3. **Redact secrets:** Strip tokens, passwords, API keys. Keep business identifiers.
4. **Append** one JSON line to `accounts/<PROFILE>/feedback/fluent-mystique-scaffold.jsonl`
5. **Update** `accounts/<PROFILE>/feedback/index.json` counters (create with `mkdir -p` if missing)

**Skip capture if:** The execution was trivially simple (e.g., user asked a question, no actual write operation happened).

## Known Pitfalls
<!-- feedback-promoted: managed section, updated by feedback loop -->

_(No promoted learnings yet.)_

<!-- end feedback-promoted -->
