---
name: backend-seed-data
description: >
  Generates module-scoped IClientSeedDataProvider implementations for
  reference data (lookup tables, enum codes) and per-module overrides. Cross-app
  navigation, roles, permissions, and role-permission mappings are NOT this
  skill's job — they live in scaffold-core-seed (Phase 0). Output goes under
  Persistence/Seeding/Applications/{AppPascal}/Modules/{ModuleCode}/ to mirror
  the per-application module layout.
phase: development/backend
cli: cli/scaffold-seed
allowed-tools: [Read, Glob, Grep, Bash]  # Bash: CLI invocation
---

# Seed Data — module-scoped IClientSeedDataProvider

Generates a per-module `IClientSeedDataProvider` for **reference data** the
module owns (lookup tables, enum codes, default rows) — anything that needs
to exist at startup but is scoped to a single module rather than to the
whole app.

## Boundary with scaffold-core-seed

| Concern | Skill | Output location |
|---|---|---|
| App-level navigation (Application + Modules + Sections + Resources) | `backend-core-seed` | `Persistence/Seeding/Applications/{AppPascal}/Core/{AppPascal}CoreNavigationSeedDataProvider.cs` |
| All roles for the app | `backend-core-seed` | `…/Core/{AppPascal}CoreRolesSeedDataProvider.cs` |
| All permissions across modules | `backend-core-seed` | `…/Core/{AppPascal}CorePermissionsSeedDataProvider.cs` |
| Role × permission wiring | `backend-core-seed` | `…/Core/{AppPascal}CoreRolePermissionsSeedDataProvider.cs` |
| Dev test users (one per role) | `backend-core-seed` | `…/Core/{AppPascal}CoreTestUsersSeedDataProvider.cs` |
| **Module-scoped reference data** (lookup tables, enums, default rows) | **`backend-seed-data` (this skill)** | `Persistence/Seeding/Applications/{AppPascal}/Modules/{ModuleCode}/{Module}SeedDataProvider.cs` |

If you find yourself passing `application`-level navigation entries to this
CLI, stop — that work belongs to `backend-core-seed` and is generated
deterministically from the BA tables in Phase 0. The validator will warn.

## When to Use

- Phase 1 of `/ba-develop` (entities phase), when an entity has
  pre-populated rows (e.g. `BudgetTransitionReason` has 6 fixed reason codes).
- When you need a module-specific override that augments the Core seed.
- NEVER for cross-app artefacts — those belong to `backend-core-seed`.

## SmartStack NuGet contract

The generated provider consumes
`SmartStack.Application.Common.Interfaces.Seeding.IClientSeedDataProvider`.
Only the methods that have content are filled in — the rest return
`Task.CompletedTask`. The orchestrator runs every provider's 4 methods in
`Order` order regardless.

## Output

- `src/{AppCode}.Infrastructure/Persistence/Seeding/Applications/{AppPascal}/Modules/{ModuleCode}/{Module}SeedDataProvider.cs`
- `src/{AppCode}.Infrastructure/Persistence/Seeding/Applications/{AppPascal}/Modules/{ModuleCode}/{Module}TestUserSeedDataProvider.cs` — only when `testUsers[]` is non-empty (legacy path; prefer `backend-core-seed` for test users so the manifest is centralised)
- `tests/ui-test/test-users.json` — gitignored manifest, only when `testUsers[]` non-empty AND `emitDevCredentialsManifest != false`

## Key Rules (still enforced)

1. **Idempotent — GUIDs as `static readonly`**: declared once at class-level so `Guid.NewGuid()` only runs once per process.
2. **Composite-key duplicate checks** — see types.ts for the exact composite per entity.
3. **`SaveChangesAsync` between hierarchy levels** when nav entries are present (legacy use case — prefer Core seed for nav).
4. **Factory methods, not anonymous objects** — EF Core cannot track anonymous shapes.

## Invocation

```bash
npx --prefer-offline tsx skills/development/backend/seed-data/cli/scaffold-seed/index.ts \
  --spec '{"module":"budgeting","appCode":"TestV2","applicationCode":"crm","navigation":[],"roles":[],"permissions":[],"projectPath":"/path/to/app"}'
```

`applicationCode` is REQUIRED and drives the per-app sub-folder
`Seeding/Applications/{AppPascal}/Modules/{Module}/`. Distinct from
`appCode` (the .NET project namespace prefix).

Reference-data inserts happen inside one of the 4 Seed*Async methods of the
generated provider (typically `SeedPermissionsAsync` historically — that
convention is unchanged for backward compat). For new entities you can also
use EF Core `HasData()` in the entity configuration — both are valid.

## Frontend alignment contract

Component keys follow the dotted form `{appCode}.{module}[.{section}[.{resource}]]`
and are seeded by `backend-core-seed` (not this skill). For every key the
frontend must have a matching `PageRegistry.register('{componentKey}', Lazy)`.
A mismatch produces a silent spinner — see `debug/frontend/SKILL.md` step 7.

## Tests Generated (by orchestrator via scaffold-tests)

- Idempotence (Seed*Async twice → no duplicates)
- Reference-data row count matches expected fixture
