---
name: development-workflow
description: >
  Development workflow index — how a validated PRD becomes a production-ready
  SmartStack extension (NuGet + npm): the 6 autonomous phases of `/ba-develop`,
  their scaffolder CLIs, their BLOCKING gates, and the map of every skill under
  `development/`.
phase: development
allowed-tools: [Read, Glob, Grep]
---

# Development Workflow

Transforms the PRD produced by the Business Analysis skills (`/ba-create-prd` —
`.smartstack/ba/<APP>/<MODULE>/prd*.md` + `pagespecs/*.md`) into a client
extension consuming the SmartStack SDK — backend (Clean Architecture + CQRS on
the NuGet packages) and frontend (PageRegistry + Slot/Fill on the
`@atlashub/smartstack` npm package) — with tests at every layer.

## Workflow — the 6 phases of `/ba-develop`

```
/ba-create-plan-development → /ba-develop-plan (waves) → /ba-develop (6 phases, gated) → /uat → /documentation
```

Planning is `/ba-create-plan-development` (module dependency waves) driven by
the multi-module orchestrator `ba-develop-plan`; execution is `/ba-develop`,
whose subagents write NO `.cs` / `.tsx` by hand — every artefact comes from a
deterministic CLI, and every phase ends on a BLOCKING gate
(`ba-develop/references/gates.md`). No step is human-driven.

| Phase | Scaffolder CLIs (skill) | Emits | Gate (BLOCKING) |
|-------|-------------------------|-------|-----------------|
| **0** Core Foundation Seed | `scaffold-core-seed` (`backend/core-seed`) | per application: 6 `IClientSeedDataProvider` under `Persistence/Seeding/Applications/{AppPascal}/Core/`, the DI marker blocks, `.smartstack/core-seed/{app}.state.json`, `CoreSeedScriptRunner` | `dotnet build` + `audit-dev-core` CLI + the pre-entry greps (module nav coverage, permission floor) + DEV-CORE-011 grant parity (`derive-rbac-grants --mode check`) |
| **1** Entities | `scaffold-entity`, `scaffold-migration` (+ `scaffold-seed`, `scaffold-extension-search`, `scaffold-data-scope`, `scaffold-coded-entity`, `scaffold-time-entry-refs`) (`backend/data-layer`, `backend/seed-data`) | `Domain/Entities/{App}/{Module}/`, `Persistence/Configurations/{App}/{Module}/`, the EF migration, module seed providers | `dotnet build` + `dotnet test` + `audit-dev-domain` + `audit-dev-data` CLIs; the migration applied through `/efcore` (destructive scan first) |
| **2a** API integration | `scaffold-business`, `scaffold-controller`, `scaffold-core-lookups` (`backend/business-layer`, `backend/controller`, `backend/core-lookups`) | `Application/{App}/{Module}/{Commands,Queries,Handlers,Validators,DTOs,Interfaces}/`, `Infrastructure/Services/{App}/{Module}/`, `Api/Controllers/{App}/{Module}/` (`[NavRoute]` → `/api/{module}/{section}`), the permission constants | `dotnet build` + `dotnet test` + `audit-dev-api` CLI (DEV-API-008..034) |
| **2b** API screen-driven | `scaffold-screen-controller` (`backend/screen-controller`) — **retired from the canonical path** (`ba-develop/SKILL.md` § note: generated apps route `[NavRoute]`-only); kept for existing apps | `Api/Controllers/{App}/{Module}/{Section}/{EntityPlural}ScreenController.cs`, `Application/{App}/{Module}/DTOs/Screens/` | `audit-dev-api --rules DEV-API-012,DEV-API-013,DEV-API-014` |
| **3.0** Theme, layout, primitives | `scaffold-theme`, `scaffold-layout`, `scaffold-ui-primitives`, `scaffold-dashboard-primitives`, `scaffold-frontend-auth` (`frontend/{theme,layout,ui-primitives,dashboard,auth}`) | `src/index.css`, `src/components/ui/*`, `src/components/dashboard/*`, `src/components/auth/PermissionGuard.tsx`, `src/business/auth/useAuth.ts` | `tsc --noEmit` |
| **3a** Pages | `scaffold-component` + `validate-page` (`frontend/component`), `/ui-design` (the judgment overlay) | `src/pages/{app}/{module}/{section}/{Plural}ListPage.tsx` / `{Entity}DetailPage.tsx` / `{Entity}FormPage.tsx` / …, `src/i18n/locales/{fr,en,it,de}/{module}.json` | `validate-page` green on every page |
| **3b / 3c** Hooks, routes, registry | `scaffold-api-client`, `scaffold-routes`, `aggregate-component-registry`, `scaffold-extension-config` (+ `scaffold-pwa` / `aggregate-outbox` when the PRD plans offline pages) | `src/features/{app}/{module}/{entity}/{services,hooks}/`, `src/extensions/{app}-{module}Registry.ts`, `{app}-{module}Routes.ts`, `componentRegistry.generated.ts`, `moduleResources.generated.ts` | `tsc --noEmit` + `npm test` |
| **3.5 / 3d / 3e** Polish and wire-up | `audit-dev-frontend --mode apply`, `ui-polish --mode apply` (mechanical fixes only — never a regeneration from a finding), then `audit-dev-wire`, `audit-dev-customised`, `run-smoke` (`smoke-test`) | fixed pages; `_audit/dev-wire-{module}.md`, `_audit/smoke-{module}.md` | `audit-dev-frontend` (DEV-UI-000..049) + `audit-dev-actions-alignment` + `audit-dev-wire` + the smoke gate |
| **4** Acceptance tests | `scaffold-tests-from-ac` (+ `scaffold-tests` per layer) (`testing`) | `Tests/{App}/{Module}/{Section}/{Section}AcceptanceTests.cs` — one `[Fact]` per BA acceptance criterion, its body filled by the subagent | `dotnet test` + `audit-dev-tests` CLI (DEV-TEST-001..011) |

**Tests are MANDATORY at every phase** — the gate's `dotnet test` / `npm test`
must be green before the next phase starts; a red gate auto-heals
(`ba-develop/references/auto-healing.md`) or DEFERS with a blocker, never
silently continues.

### DONE criteria per phase

The per-phase criteria ARE the gates — `ba-develop/references/gates.md` is the
single list (build, tests, the deterministic `audit-dev-*` CLI of the layer,
the `DEV-<PACK>-000` coverage rule that refuses a green scan of nothing). Two
things this index used to claim and that were WRONG:

- the `// TODO[BR-…]` / `// TODO[UC-…]` / `// TODO[AC-NN]` markers are
  DESIGNED — the gates DEV-API-008/009 and DEV-TEST-002 fail while any remains,
  so a phase is done only once the subagent has filled them (never strip a
  marker without writing the body);
- a failed gate NEVER rolls a phase back by deleting generated files (`NEVER
  rm -rf`, `lib/guarded-rm`) — it re-runs the scaffolder (idempotent,
  `@customised` preserved) or defers.

Conventions the gates enforce: 4-segment permission paths
`{app}.{module}.{section}.{action}` (DEV-API-021, DEV-UI-011), `componentKey`
kebab-case in 2–5 segments matching the seeded navigation (DEV-UI-046), tables
prefixed with the BA `**Préfixe table**` as `{prefix}_{EntityPlural}`
(DEV-DAT-002), random Guids, a `@generated-by` marker on every generated file.

## Skills Index (`templates/skills/development/`)

### Backend (`backend/`)
- `structure/` — target Clean Architecture, 4 layers, the `<App>/<Module>` file classification (reference doc)
- `core-seed/` — `scaffold-core-seed` (the Phase 0 bundle per application) + `derive-seed-delta` (the release SQL delta from the state snapshot)
- `core-lookups/` — `scaffold-core-lookups`: the `/api/core/{users,roles,departments,…}/lookup` BRIDGE the generated `use{E}Lookup` hooks call until the socle serves it natively (`remove` mode retires it)
- `data-layer/` — `scaffold-entity`, `scaffold-migration`, `scaffold-extension-search`, `scaffold-time-entry-refs`, `scaffold-data-scope`, `scaffold-coded-entity`
- `seed-data/` — `scaffold-seed`: module reference data (`**Valeurs initiales**`), the business test dataset (`jeu-de-test.md`), dev test users
- `business-layer/` — `scaffold-business`: CQRS commands / queries / handlers / validators / DTOs + `{E}Service`
- `controller/` — `scaffold-controller`: the integration controller + `{Mod}Permissions.{Section}` constants
- `screen-controller/` — `scaffold-screen-controller`: the screen-driven controller (Phase 2b — retired from the canonical path)

### Frontend (`frontend/`)
- `structure/` — target React 19 + Vite 7 layout (reference doc)
- `theme/` — `scaffold-theme`: `src/index.css` design tokens (+ `--dataviz-*`)
- `layout/` — `scaffold-layout`: `PageTemplate.tsx` only (the chrome ships in the package)
- `ui-primitives/` — `scaffold-ui-primitives`: `EntityLookup`, `DateInput`, `EnumSelect`, `MultiSelect`, `DataTable`, `ResponsiveDataTable`, `TabStrip`, `SectionCard`, …
- `dashboard/` — `scaffold-dashboard-primitives`: `src/components/dashboard/*` (Recharts, theme-driven palette)
- `auth/` — `scaffold-frontend-auth`: the `useAuth` adapter + the `PermissionGuard` seam
- `component/` — `scaffold-component` (pages from a pagespec) + `validate-page` (the per-page gate) + the 5 pattern sheets
- `api-client/` — `scaffold-api-client`: services + React Query hooks (+ the outbox spec per offline-write entity)
- `routes/` — `scaffold-routes`, `aggregate-component-registry`, `split-component-registry`
- `extension-config/` — `scaffold-extension-config`: `ExtensionConfig` + the slot catalogue (`lib/slot-names`)
- `pwa/` — `scaffold-pwa` + `aggregate-outbox`: the PWA transform, offline read/write, the mobile-shell config
- `ui-polish/` — `ui-polish`: design-rule audit + mechanical fixes (`tokens.json` hard rules)

### Testing (`testing/`, `smoke-test/`)
- `testing/` — `scaffold-tests` (per-layer test projects), `scaffold-tests-from-ac` (one `[Fact]` per acceptance criterion), `test-report`
- `testing/fix-build/` — the build fixer (`claude -p`)
- `testing/smoke-http/` — the HTTP prober (Studio runner; `/ba-develop` does not invoke it)
- `testing/ui-test/` — `build-manifest` + `run-ui-test`: manifest-driven browser scenarios per role
- `smoke-test/` — `run-smoke`: the runtime gate (boots both apps; HTTP + browser + nav-consistency + custom-action probes)

### Audits (`audit-dev-*/`, one deterministic CLI each)
- `audit-dev-core/` — DEV-CORE-000..011 (the Phase 0 bundle layout; 011 = grant parity through `derive-rbac-grants`)
- `audit-dev-domain/` — DEV-DOM-001..008 (BA entities ↔ Domain classes)
- `audit-dev-data/` — DEV-DAT-000..010 (migrations, FK constraints, indexes, the test dataset)
- `audit-dev-api/` — DEV-API-000..034 (rules, actions, pagination, tenant filter, guards, seams)
- `audit-dev-frontend/` — DEV-UI-000..049 (+ `audit-dev-actions-alignment`, ACTION-DRIFT-001..006)
- `audit-dev-wire/` — DEV-WIRE-000/001 (frontend URL ↔ backend route parity)
- `audit-dev-customised/` — DRIFT-001/002 (`@customised` pages vs the regenerated contract)
- `audit-dev-tests/` — DEV-TEST-001..011 (AC / BR coverage, no stub assertion)
- `audit-dev-pwa/` — DEV-PWA-001..012 (offline + mobile shell; run by `/pwa`, not wired into `/ba-develop`)
- `audit-dev-external-api/` — DEV-XAPI-001..014 (the public machine-to-machine stratum of `/external-api`)
- `audit/` — the prose conventions audit (report-only) + `audit/routing-dynamic/` (the skills themselves vs the DB-driven routing architecture)

### Debug / Run
- `debug/` — the router (`claude -p`, non-interactive) → `debug/backend/`, `debug/frontend/` runbooks; `debug/audit-bug/`, `debug/discuss-bug/`, `debug/fix-bug/` (triage → discussion → fix committed through the gitflow CLI)
- `run/` — `run/backend/`, `run/frontend/` (orchestrated by the top-level `dev-start`)

Related, outside this folder: `../external-api/` (`/external-api`, the public stratum), `../audit-fix/` (runs the audits and executes the remedies that exist), `../uat/`, `../documentation/`.

## Architecture Target

Generated code extends SmartStack via packages:
- **Backend (NuGet)**: `SmartStack.Core`, `SmartStack.Application`, `SmartStack.Infrastructure`, `SmartStack.Api`
  - Clean Architecture + CQRS + MediatR + FluentValidation; files classified under `<App>/<Module>` (`lib/app-classification.ts` says which namespaces stay flat)
  - Generated services inject `IExtensionsDbContext` (the client extension's context abstraction — `ExtensionsDbContext : SmartStackExtensionDbContext`); `ICoreDbContext` is the boundary of the Core seed providers. Never reference a concrete DbContext.
  - Tenant isolation is a NAMED filter mounted per entity (`<<< TENANT-FILTERS >>>`, DEV-API-032); `FindAsync` is banned (it bypasses every filter)
- **Frontend (npm)**: `@atlashub/smartstack`
  - PageRegistry + DynamicRouter + ProtectedRoute + Slot/Fill + ExtensionConfig; `SmartStackProvider` wraps the app at root (`main.tsx`)
  - Pages under `src/pages/{app}/{module}/{section}/`, hooks under `src/features/{app}/{module}/{entity}/`, i18n under `src/i18n/locales/{locale}/{module}.json`
- **Data**: `IClientSeedDataProvider` per application (the Core bundle) and per module (reference data, test dataset), idempotent and hierarchical
- **Tests**: xUnit (`[Trait("Category","…")]`, `[Trait("Type","Unit"|"Integration")]`, `[Trait("AC","<UC>#AC-NN")]`, `[Trait("BR","BR-NNN")]`) + Vitest
