---
name: doc-templates
description: Canonical markdown skeletons for the six BA docs + index + rollup variant. The single format contract that authors (definer skills), audits, and create-prd all parse. Loaded on demand, not every turn.
phase: '*'
kind: reference
section_label: '_WORKFLOW — DOC TEMPLATES'
---

# BA doc templates — the canonical file shapes

Every file under `.smartstack/ba/` follows one of the skeletons below. The first
line is always an anchor comment (`<!-- ba:… -->`); item codes are `###`
headings so they are greppable. Write content in the user's language; keep codes
and anchors verbatim. See `ba-files.md` for the authority matrix (which level
authors vs rolls up each doc).

---

## `index.md` — every node (project / app / module / section / resource)

```markdown
<!-- ba:node kind=node level=application code=CRM -->
# CRM — Gestion commerciale

## Contexte
Application de suivi commercial : prospects, opportunités, devis.

## Hors-périmètre
- La facturation est gérée dans BILLING.
- La signature électronique passe par un service tiers (hors v1).

## Enfants
- [PIPELINE](./PIPELINE/index.md) — Pipeline d'opportunités
- [CONTACTS](./CONTACTS/index.md) — Annuaire de contacts
```

`level=project` for the root `.smartstack/ba/index.md`; its `## Enfants` lists
the applications. `out_of_scope` (the `## Hors-périmètre` bullets) cascades into
PRD non-goals downstream — keep it accurate.

### Module-level `index.md` — with optional `depends=` attribute

After `/ba-create-ba-order` (Phase 1.5), module-level `index.md` files gain a
`depends=` attribute in their anchor and a `## Dépendances` section:

```markdown
<!-- ba:node kind=node level=module code=BILLING depends=ERP/REFERENCES,ERP/CUSTOMERS -->
# BILLING — Invoicing

## Contexte
Invoices management for customers and suppliers.

## Hors-périmètre
- No online payment v1.

## Dépendances
- [REFERENCES](../REFERENCES/index.md) — uses currencies, countries, statuses
- [CUSTOMERS](../CUSTOMERS/index.md) — invoices linked to customers

## Enfants
- [invoices](./invoices/index.md) — Invoices
```

For a module **without** dependencies:

```markdown
## Dépendances
_Aucune — module fondationnel._
```

`## Dépendances` is placed between `## Hors-périmètre` (or `## Contexte` if
no out-of-scope section) and `## Enfants`. Only module-level `index.md` carries
this section — app/section/resource levels do not.

---

## `acteur.md` — authoritative at Application

```markdown
<!-- ba:acteur level=application code=CRM -->
# Acteurs — CRM

### BA-001-AC-001 — Commercial
- **Type** : internal
- **Description** : Gère son portefeuille de prospects et opportunités.
- **Périmètre** : CRM (toute l'application)
- **Origine** : conversation (2026-…)

### BA-001-AC-002 — Manager commercial
- **Type** : internal
- **Description** : Supervise l'équipe, valide les remises.
- **Périmètre** : CRM / PIPELINE
- **Origine** : code (rôle détecté)
```

`type` ∈ `internal | external | system`. Both `Description` and `Origine`
(traceability) are required. Actor codes are `BA-{analysisSeq}-AC-{NNN}`.

---

## `use-case.md` — authoritative at Section

```markdown
<!-- ba:use-case level=section code=opportunites -->
# Cas d'usage — CRM / PIPELINE / opportunites

### UC-CRM-PIPELINE-OPPORTUNITES-001 — Créer une opportunité
- **Acteur principal** : BA-001-AC-001 (Commercial)
- **Acteurs secondaires** : —
- **Préconditions** : le prospect existe.
- **Flux principal** :
  1. Le commercial ouvre le formulaire.
  2. Il saisit le montant estimé et l'échéance.
  3. Le système crée l'opportunité au statut NOUVELLE.
- **Flux alternatifs** :
  - ALT-1 : montant inconnu → enregistrement en brouillon.
- **Exceptions** :
  - EXC-1 : prospect archivé → refus avec message.
- **Postconditions** : opportunité visible dans le pipeline.
- **Règles liées** : BR-003
- **Écrans liés** : SCR-CRM-PIPELINE-OPPORTUNITES-001
- **Acceptance Criteria** :
  - [ ] AC-01 — POST /api/opportunities avec un body valide renvoie 201 + l'identifiant créé.
  - [ ] AC-02 — POST avec un montant négatif renvoie 400 et le code d'erreur `amount-positive`.
  - [ ] AC-03 — La nouvelle opportunité apparaît dans GET /api/opportunities du même owner avec statut NOUVELLE.
```

UC codes are `UC-{APP}-{MOD}-{SEC}-NNN` (section code UPPERCASED in the code).

AC codes are **local to the UC** : `AC-01`, `AC-02`, … numbered from 01 (zero-padded
2 digits), sequential, no gaps. The globally unique reference is `<UC-code>#AC-NN`
(e.g. `UC-CRM-PIPELINE-OPPORTUNITES-001#AC-02`). Each AC is a single, testable
assertion that the test-scaffolder turns into a `[Fact]` (backend) or `test()`
(Playwright) at code-generation time. Write at least one AC per `user-goal` UC
(audit `UC-012`); subfunction-level UCs may legitimately have none.

---

## `règles-métier.md` — authoritative at the rule's deepest scope

```markdown
<!-- ba:rules level=module code=PIPELINE -->
# Règles métier — CRM / PIPELINE

### BR-001 — Remise plafonnée
- **Type** : validation
- **Sévérité** : err
- **Portée** : CRM / PIPELINE
- **Condition** : QUAND une remise > 20 % est saisie ALORS exiger l'aval manager.
- **Expression** : `Discount <= 0.20 || Approval.ManagerId != null`
- **Code d'erreur** : `pipeline.discount.cap`
- **Cas valides** : remise 15 % sans aval ; remise 25 % avec aval manager.
- **Cas invalides** : remise 25 % sans aval.
- **Cas d'usage liés** : UC-CRM-PIPELINE-OPPORTUNITES-002 (étape 3)

### BR-002 — Numéro d'opportunité
- **Type** : numbering
- **Sévérité** : err
- **Portée** : CRM / PIPELINE
- **Condition** : QUAND une opportunité est créée ALORS son numéro = `OPP-{YY}-{NNNN}` (séquence par tenant, reset annuel, gapless, immuable).
- **Expression** : `reference = "OPP-" + fmt(year,"yy") + "-" + pad(nextSeq(scope=tenant, reset=yearly), 4)`
- **Code d'erreur** : `pipeline.opportunity.reference.duplicate`
- **Cas valides** : 1re de 2026 → `OPP-26-0001` ; suivante → `OPP-26-0002` ; 1re de 2027 → `OPP-27-0001`.
- **Cas invalides** : deux créations concurrentes → jamais le même numéro ; numéro modifié après création → rejeté.
- **Cas d'usage liés** : UC-CRM-PIPELINE-OPPORTUNITES-001 (postcondition)
```

Rules feed FluentValidation + form error messages downstream — keep the valid/
invalid examples concrete and testable.

---

## `rbac.md` — authoritative at Module

```markdown
<!-- ba:rbac level=module code=PIPELINE -->
# RBAC — CRM / PIPELINE

| Acteur | Permission (`module.section[.resource].action`) | Portée |
|--------|------------------------------------------|--------|
| BA-001-AC-001 (Commercial) | `crm.pipeline.opportunites.read` | toutes |
| BA-001-AC-001 (Commercial) | `crm.pipeline.opportunites.create` | les siennes |
| BA-001-AC-002 (Manager commercial) | `crm.pipeline.opportunites.approve` | équipe |
```

Permissions are `module.section[.resource].action` within the module (3 segments
for a section, 4 for a resource); the app prefix is added at the page/controller
boundary, not here.

---

## `entité.md` — authoritative at Module

```markdown
<!-- ba:entité level=module code=PIPELINE -->
# Modèle de données — CRM / PIPELINE

### ENT-001 — Opportunity (agrégat racine)
- **Préfixe table** : `pipeline_`
- **Traçabilité** : UC-CRM-PIPELINE-OPPORTUNITES-001, BR-001, BR-002

| Attribut | Type | Contraintes | Calculé |
|----------|------|-------------|---------|
| Id | Guid | PK | — |
| Amount | decimal(18,2) | ≥ 0 | — |
| Stage | enum | NOUVELLE/GAGNEE/PERDUE | — |
| WeightedAmount | decimal(18,2) | — | `Amount * Probability` |

- **Relations** : Opportunity *→1 Contact — FK ContactId, scope same-module, onDelete restrict.
- **Index** : (Stage), (ContactId).
- **Code pattern** : `OPP-{YY}-{NNNN}` — scope tenant, reset annuel, gapless (voir BR-002 ; allocateur ENT-002).

### ENT-002 — OpportunitySequence (technical)
- **Préfixe table** : `pipeline_`
- **Traçabilité** : BR-002 (numérotation `OPP-{YY}-{NNNN}`)
- **Isolation** : by-design — allocateur du compteur de référence (aucune relation métier)

| Attribut | Type | Contraintes | Calculé |
|----------|------|-------------|---------|
| Id | Guid | PK | — |
| Year | int | unique (par tenant) | — |
| NextValue | int | ≥ 1 | — |
```

Entity codes are `ENT-NNN`. The role in parentheses is the classification
(`agrégat racine` / `composant` / `lookup` / `technical`). Computed attributes
carry a non-empty **Calculé** formula (no DB column, no setter). A `technical`
allocator (sequence/counter/outbox) is isolated by nature — give it an
`- **Isolation** : by-design — <raison>` line so audit DM-009 treats the absence
of relations as intentional, not a modeling gap.

---

## `screen.md` — authoritative at Section / Resource

```markdown
<!-- ba:screen level=section code=opportunites -->
# Écrans — CRM / PIPELINE / opportunites

### SCR-CRM-PIPELINE-OPPORTUNITES-001 — Liste des opportunités (SmartListView)
- **Entité** : Opportunity (ENT-001)
- **Permission** : `crm.pipeline.opportunites.read`
- **Cas d'usage liés** : UC-CRM-PIPELINE-OPPORTUNITES-001
- **Colonnes** : Amount, Stage, Contact
- **Filtres** : Stage (select), période (date-range)
- **Actions** : create (header), edit (row), delete (row)
```

Screen codes are `SCR-{APP}-…-NNN`. The SmartComponent type (`SmartListView`,
`SmartForm`, `SmartDashboard`, …) is named in the heading. create-prd mines
these to build per-page specs.

---

## Rollup variant — non-authoritative levels

At a level where a doc is a rollup (per the authority matrix), write a short
aggregated view marked with the rollup comment, linking to the authoritative
children. **Never hand-author content here** — regenerate it whenever the
authoritative source changes.

```markdown
<!-- ba:acteur level=module code=PIPELINE -->
<!-- ba:rollup auto -->
# Acteurs — actifs sur PIPELINE
> Vue agrégée — source faisant autorité : [../acteur.md](../acteur.md)

- BA-001-AC-001 (Commercial)
- BA-001-AC-002 (Manager commercial)
```

A placeholder (node created by create-menu, concept not yet defined) is the
minimal form — anchor + a one-line note:

```markdown
<!-- ba:rules level=section code=opportunites -->
_À définir lors de la phase « règles métier »._
```

---

## Audit verdict — `_audit/<dimension>.md`

The `/ba-audit-*` skills read the tree, apply their rule set, and write a verdict
to an `_audit/` subfolder of the scope they audit (e.g. an app-scoped menu audit
→ `.smartstack/ba/<APP>/_audit/menu.md`; a module-scoped data-model audit →
`.smartstack/ba/<APP>/<MODULE>/_audit/entité.md`; a project-scoped actors audit →
`.smartstack/ba/_audit/actors.md`). This replaces the Studio `[ACTION]{auditReport}`
envelope — there are no i18n label codes, no `persist`, no frontend.

```markdown
<!-- ba:audit dimension=menu scope=CRM -->
# Audit menu — CRM
_2026-05-21 · Verdict : ⚠️ 1 warn · 0 err · 3 ok_

## ✅ Conforme
- **MENU-001** — chaque module correspond bien à son application (2 modules vérifiés).
- **MENU-003** — aucun module ne duplique le Core SmartStack.
- **MENU-004** — aucun module orphelin, aucune app/module vide.

## ⚠️ Avertissements
- **MENU-002** — le concept « Contacts » apparaît dans **CRM** et **SALES**.
  - Pourquoi : risque de doublon de données et de logique.
  - → Clarifier la frontière ou fusionner via `/ba-create-menu`.

## ❌ Bloquants
- _(aucun)_
```

- The header line carries the verdict counts; the rule codes (`MENU-001`, …) stay
  **bold** so they remain greppable, but they are explained in business terms.
- Findings are grouped by severity (`ok` / `warn` / `err`). For each non-`ok`
  finding give **what's wrong** (offending codes in bold), **why it matters**, and
  a `→` **concrete fix** naming the skill to re-run (e.g. `/ba-create-menu`).
- The skill also prints a 3–6 line summary in the chat; the file is the durable
  record. A downstream phase/dev gate that needs "did the audit pass?" reads the
  `Verdict :` header (`0 err` = pass).

