---
name: Generate - Author content, then run scaffold-doc
description: Author the doc page + i18n content from the extract-doc report, then run scaffold-doc to write i18n/manifest and emit the wiring plan
next_step: step-03-validate.md
---

## STEP 02: Generate — author content, then `scaffold-doc`

### Division of labour

| Deterministic (CLI) | LLM (you) |
|---------------------|-----------|
| i18n locale files (4 langs, FLAT), `docs-manifest.json` upsert, wiring **plan** | the doc page body (faithful Mock UI), the i18n **content**, curated rules/use-cases/FAQ |

So: **you author** the page + the i18n content, then **`scaffold-doc` writes the files + manifest and hands back a wiring plan** you apply.

### A. Author the doc page

#### `user` type — standalone annotated Mock UI

Generate a **standalone TSX page** (~400-600 lines) that faithfully reproduces
the real page read in step-01. **Do NOT use DocRenderer.** Follow `templates.md`
for the full structure (9 sections) and the canonical `Annotation` component.

- **Header is a FIXED block** (identical across pages — see `templates.md` "Header
  obligatoire"): title + icon, then a **REQUIRED accent tagline** `t('summary')`
  (`text-xl text-[var(--color-accent-600)] font-medium`), then `t('subtitle')`, then
  a **stats line** rendered **inline** as `<span>{N} {t('header.businessRules')}</span> · …`
  — count is a sibling text node, **never** pills and **never** `t('header.x', {count})`
  (the number vanishes if the i18n value lacks `{{count}}`). Omitting the tagline fails
  the step-03 gate (`existingDoc.missingRequired` = `['summary']`).
- **Section 1 is ALWAYS "Objectif"** — a short factual description of what the
  module does / what it is for, written as an objective (no problème/solution, no
  pitch). It is its **own numbered section** rendering `t('objective')` under the
  `t('sections.objective')` heading. The header `subtitle` does **not** replace it —
  even when the subtitle already summarises the module, the Objectif section stays.
  Omitting it fails the step-03 gate (`existingDoc.missingRequired` = `['objective']`).
- **You MAY adapt the middle "interface" sections** (the template's Interface /
  Création / Détail) to the real page's shape: a tabbed settings page becomes
  one section per tab; a Kanban becomes a board mock; etc. What is **fixed**:
  Section 1 = Objectif, then Accès, and the tail (Cas d'usage, Fonctionnalités,
  FAQ, Référence technique). Adapt the body, never drop the Objectif.
- Reproduce the **real page** (`report.resolved.pageTsxPath`) — same layout family (cards / table / kanban / dashboard), not a generic KPI/table.
- For every chart, match `report.charts[].mockUiPattern` (recharts type → faithful Mock UI). See `templates.md` → recharts mapping + expressive mock data.
- Annotate every Mock UI block; keep annotations INSIDE the same padded container.
- Use the curated `report.apiEndpoints` / `businessRules` in the collapsible Technical Reference.

#### `developer | database | testing` — DocRenderer

Generate `doc-data.ts` (structured `DocData`) + a ~10-line `index.tsx` wrapper
that renders `<DocRenderer data={docData} i18nNamespace="…" />`. See `templates.md`.

#### Correcting an existing doc (when `report.existingDoc` flags issues)

`extract-doc` reports two mirror structural defects on a doc already on disk. Fix
both as you regenerate — documentation leads with a factual **objective** and
carries no pitch (SKILL.md rule #12):

**a. Forbidden sections** (`report.existingDoc.forbiddenSections` non-empty) —
banned "sales" framing (problème/solution, Bénéfices, Avant/Après). For each entry,
**remove it** — do NOT carry it over:

- **`user`** — drop the section from the standalone TSX, and **omit** the
  `benefits` / `beforeAfter` / `problem` / `solution` keys from the i18n content you
  author. `scaffold-doc` **overwrites** each locale file with your authored content,
  so omitting the keys deletes them.
- **`developer | database | testing`** — remove the `benefits` / `beforeAfter`
  fields and `overview.problem` / `overview.solution` from `doc-data.ts`, and omit
  the matching keys from the authored i18n.

**b. Missing required elements** (`report.existingDoc.missingRequired` non-empty):

- **`"objective"`** — the mandatory Section 1 is absent (a stale doc predating the
  objective convention, or one that folded it into the subtitle). **Add it:** author
  `sections.objective` + `objective` (user) or `overview.objective` (DocRenderer) and
  render it as the first numbered section. Write the objective from the real page's
  purpose — what it does / what it is for — not a sales angle.
- **`"summary"`** (user) — the header accent tagline is missing (the header isn't
  identical to the other pages). **Add it:** author the `summary` key and render it
  between the title and subtitle as `<p class="text-xl text-[var(--color-accent-600)]
  font-medium">{t('summary')}</p>`, plus the inline stats line. If the doc used the
  legacy `valueProposition` key, rename it to `summary`.

The step-03 gate re-runs the scan and will not let you finish while any remain.

### B. Author the i18n content

Author the content for the 4 languages (FR source, then EN/DE/IT) **FLAT** — keys at
the root (`title`, `sections`, `objective`, …). `scaffold-doc` writes it as-is for
`user` docs (resolved via `t('title')`) and **wraps it under the namespace key** for
`developer/database/testing` docs (DocRenderer resolves `t('<namespace>.path')`).

### C. Run `scaffold-doc`

Pass the authored i18n content + the metadata from step-01's report:

```bash
npx --prefer-offline tsx skills/documentation/cli/scaffold-doc/index.ts --spec '{
  "type":"user","target":"<module>","application":"<app>",
  "namespace":"<report.namespace>","routePath":"<app>/<module>",
  "componentName":"<Module>DocPage",
  "pageImportPath":"@/pages/docs/business/<group>/<app>/<module>",
  "i18n":{"fr":{…},"en":{…},"de":{…},"it":{…}},
  "manifest":{"id":"<module>","name":"…","description":"…","version":"1.0.0"},
  "docMappings":["<app>/<module>","<app>/<module>/list","<app>/<module>/create"],
  "appDocDefault":false,
  "projectPath":"<project-root>"
}'
```

- `<group>` is the page-folder grouping (`platform` for admin/support/api, `personal` for myspace) — note the **route omits it**.
- Use `--dry_run` first to preview `filesCreated` + the wiring plan without writing.
- It writes the i18n files + upserts `docs-manifest.json`, and returns `data.wiring`.

### D. Apply the wiring plan

`report.data.wiring[]` lists each in-place edit (the CLI does NOT touch your TSX
files — you do, adapting to the real file). For each instruction:
1. If `idempotencyMarker` already appears in `file` → **skip** (already wired).
2. Else open `file`, find `anchor`, apply `insert` with `Edit`.

Targets: `i18n/config.ts` (4 points), `DocRoutes.tsx` (lazy import + child route under `/docs/business`), `DocPanelContext.tsx` (docMapping), `UserIndexPage.tsx` (module entry, user type).

### Colour / theme — delegated to ui-polish

Do **not** hand-map Tailwind colours. After the page exists, theme compliance is
enforced **deterministically** by the ui-polish CLI in step-03. While authoring,
just follow the doc-specific intents in `templates.md`: dashboard chart series use
the `--dataviz-*` palette, highlight blocks use the discreet accent pattern, brand
colour is the `--color-accent-*` ramp (never `--color-primary-*`).

### Absolute rules (kept)

1. **NEVER** hardcoded text → `useTranslation('<namespace>')`.
2. **ALWAYS** read the REAL page TSX (step-01) before writing Mock UI.
3. **ALWAYS** annotate every Mock UI block (canonical `Annotation`, children-based).
4. **ALWAYS** author i18n FLAT in all 4 languages — the CLI nests it under the namespace for DocRenderer types.
5. **ALWAYS** apply the `scaffold-doc` wiring plan, then run ui-polish (step-03).

### Annotation component contract

```tsx
import { Info } from 'lucide-react';
import type { ReactNode } from 'react';

function Annotation({ children }: { children: ReactNode }) {
  return (
    <div className="flex items-start gap-2 px-3 py-2 rounded-md border-l-2 border-[var(--color-accent-500)] bg-[var(--bg-secondary)] text-xs text-[var(--text-secondary)]">
      <Info className="w-3.5 h-3.5 mt-0.5 flex-shrink-0 text-[var(--text-tertiary)]" />
      <span className="leading-relaxed">{children}</span>
    </div>
  );
}
```

### Next step

→ **step-03-validate.md** — verify completeness + run ui-polish + final checks.
