---
name: audit-routing-dynamic
description: Audit READ-ONLY des skills de developpement SmartStack pour verifier leur conformite a l'architecture de routing dynamique DB-driven (PageRegistry + componentRegistry + DynamicRouter). Produit un rapport textuel sans modifier aucun skill.
group: AUDIT
allowed-tools: [Read, Glob, Grep]
---

# Skill: Audit Routing Dynamique — Skills de developpement SmartStack

## Role

Tu es un agent d'audit **read-only**. Tu inspectes les `SKILL.md` du repertoire
`development/` et tu evalues si chaque skill documente correctement l'architecture
de **routing dynamique DB-driven** de SmartStack.

**Contrainte absolue** : tu ne modifies AUCUN fichier skill. Tu produits un rapport
textuel avec des recommandations que l'utilisateur appliquera manuellement.

## Input

```
audit-routing-dynamic [skill-path | all]
```

- Sans argument ou `all` : audit complet des 10 skills cibles
- Avec un chemin (ex: `frontend/component`) : audit cible

## Architecture de reference (source de verite)

SmartStack est un SDK NPM/NuGet. Toute page React doit etre enregistree via
`PageRegistry.register(componentKey, LazyComponent)`. `DynamicRouter` resout les
routes a partir du menu API DB (`GET /api/navigation/menu`).

**5 elements mandatory** :
1. `componentRegistry.generated.ts` — registre des pages (importe dans `main.tsx`)
2. `PageRegistry` — API de registration + resolution
3. `DynamicRouter` — moteur de routing unique (remplace routes statiques)
4. `ProtectedRoute` — guard API-driven (permissions + features)
5. `useRouteConfig` — hook qui transforme menu API → routes React

**24 IMPLICIT_SUFFIXES** (auto-generes par DynamicRouter) :
```
.detail  .edit  .create  .new  .duplicate  .settings  .configure
.permissions  .members  .history  .logs  .analytics  .preview
.versions  .comments  .attachments  .audit  .export  .notifications
.schedule  .workflow  .summary  .test  .runs  .import
```

**Conventions obligatoires** :
- `componentKey` dot-separated : `{app}.{module}.{section}[.{resource}]`
- `useParams<{ id: string }>()` — TOUJOURS `:id`, jamais `:userId`/`:ticketId`
- Lazy imports : `lazyWithRetry(() => import('./MyPage').then(m => ({ default: m.MyPage })))` (re-exporté depuis `@atlashub/smartstack` — wraps `React.lazy` avec retry exponentiel sur ChunkLoadError transitoires)
- Seed `ComponentKey` backend = cle PageRegistry frontend
- **Permission matching via `hasRouteAccess(permission, routeKey)`** — JAMAIS de bypass `hasFullAccess` ou de comparaison string brute. Regles :
  - `*` matche tout (super-admin uniquement)
  - `app.*` matche tout `app.module.action`
  - `app.module.read` implique acces a `app.module` (action `read` est l'acces de base)
  - Comparaison exacte sinon
- **`IsOpen` (DB column `core.nav_Applications.IsOpen`)** est propriete domaine **uniquement sur Application** (PAS sur Module/Section/Resource). Bypasse la verification permission/feature au niveau Application (ex: `myspace.*` toujours accessible). Audit doit verifier que le seed positionne `IsOpen` au bon niveau.
- **Menu API 4 niveaux DTO** : `ApplicationMenuDto > ModuleMenuDto > SectionMenuDto > ResourceMenuDto`. Chaque niveau porte son propre `ComponentKey` + `PermissionPath` (calcules au runtime depuis le chemin hierarchique). `IsOpen` n'existe que sur `ApplicationMenuDto`. `RequiredFeature` n'existe que sur `Application` et `Module` (2 niveaux, depuis `LicenseFeatureMapping`).
- **`OUTLET_SECTIONS` config** (dans `DynamicRouter`) declare les sections qui rendent leurs sous-pages via React Router `<Outlet>` (tabs). Composants resolus depuis `PageRegistry` (pas hardcode). Anti-pattern : routes Outlet ecrites en dur dans le router.

**Fichiers de reference dans SmartStack.app** (source de verite code) :
- `web/smartstack-web/src/extensions/PageRegistry.tsx`
- `web/smartstack-web/src/router/DynamicRouter.tsx` (IMPLICIT_SUFFIXES L86-119)
- `web/smartstack-web/src/generated/componentRegistry.generated.ts`
- `web/smartstack-web/src/hooks/useRouteConfig.ts`
- `web/smartstack-web/src/components/routing/ProtectedRoute.tsx`

## Skills cibles (10)

| Priorite | Skill | Categorie |
|----------|-------|-----------|
| P0 | `frontend/component` | Pages React |
| P0 | `frontend/structure` | Arborescence + main.tsx |
| P0 | `audit` | Audit generaliste existant |
| P1 | `backend/seed-data` | Seed Navigation |
| P1 | `backend/controller` | NavRoute attribute |
| P1 | `frontend/extension-config` | Slots |
| P2 | `frontend/routes` | PageRegistry scaffolding |
| P2 | `frontend/api-client` | getRoute() + React Query |
| P2 | `testing` | Tests par layer |
| P2 | `backend/structure` | Clean Architecture |

## Criteres d'audit (10 regles A-J)

Pour chaque skill, appliquer les criteres. `N/A` si hors scope du skill.

| ID | Regle | Applicable a | Pattern de detection |
|----|-------|--------------|----------------------|
| A | Mentionne `PageRegistry.register()` | frontend/* | grep `PageRegistry.register` OR `componentRegistry.generated` |
| B | Utilise `lazyWithRetry(() => import(...))` (ou legacy `lazy(`) | frontend/component, frontend/routes | grep `(lazy|lazyWithRetry)\(` avec `import(` |
| C | Documente au moins 3 IMPLICIT_SUFFIXES | frontend/routes, frontend/component | grep `.detail`, `.edit`, `.create` |
| D | Enforce `useParams<{ id: string }>()` | frontend/component | grep `useParams<{ id:` — anti-pattern si `userId`/`ticketId` |
| E | Documente format ComponentKey dot-separated | frontend/routes, frontend/component, backend/seed-data | grep `componentKey.*\.` avec exemple `app.module` |
| F | Aligne ComponentKey backend -> frontend | backend/seed-data | grep `ComponentKey` dans exemple de seed |
| G | Mentionne `[NavRoute]` attribute | backend/controller | grep `NavRoute` |
| H | Interdit routes statiques `<Route path=...>` | frontend/* | absence de `<Route path=` hors DynamicRouter |
| I | _(removed — MCP validate_frontend_routes was deleted in v5)_ | — | — |
| J | Documente integration NPM client (wiring `main.tsx`) | frontend/structure | grep `main.tsx` + `componentRegistry` |

## Plan d'execution

1. **Inventory** — Globber les `SKILL.md` cibles :
   ```
   templates/skills/development/**/SKILL.md
   ```
   Filtrer les 10 cibles ci-dessus.

2. **Evaluate** — Pour chaque skill :
   - `Read` le contenu complet
   - Pour chaque critere A-J applicable : `Grep` le pattern
   - Noter `OK` / `PARTIAL` / `MISSING` / `N/A` avec numero de ligne

3. **Score** — `X/Y` par skill (Y = nombre de criteres applicables)

4. **Report** — Afficher le rapport au format defini (section Output)

**Regles strictes** :
- JAMAIS d'`Edit` ou `Write` sur les fichiers skills
- JAMAIS de modification directe des fichiers skills audites
- Tools autorises : `Read`, `Grep`, `Glob`, `Bash` (ls uniquement)
- Si l'utilisateur demande explicitement d'ecrire le rapport sur disque :
  creer UN SEUL fichier `audit-routing-dynamic-report.md` dans le CWD (jamais dans le repertoire skills)

## Output attendu

```
━━━ Audit Routing Dynamique — Rapport ━━━
Date: 2026-04-19
Skills audites: 10
Conformite globale: 48/100

## Top 3 gaps transversaux
1. A. PageRegistry : 8/10 skills ne mentionnent jamais PageRegistry.register()
2. J. Integration NPM : 0/10 skills documentent le wiring main.tsx
3. C. IMPLICIT_SUFFIXES : 1/10 skill les documente

## Top 3 skills critiques (P0)
- frontend/component (6/10)
- frontend/structure (4/10)
- audit (2/10)

## Detail par skill

### frontend/component — 6/10
Ce qu'il genere: Pages React (List/Detail/Form), i18n, Slot/Fill
Criteres:
  A. PageRegistry        MISSING   (0 occurrence dans SKILL.md)
  B. Lazy imports        MISSING   (template utilise import direct)
  C. IMPLICIT_SUFFIXES   MISSING
  D. useParams id        PARTIAL   (L112 mentionne "key rules", pas :id explicite)
  E. ComponentKey format MISSING
  H. Routes statiques    OK        (aucun <Route> dans SKILL.md)
  I. _(removed in v5)_         N/A
Recommandations (a appliquer manuellement) :
  1. Ajouter section "PageRegistry Registration" apres L24 avec exemple
     lazyWithRetry() + register('app.module.section', Lazy)
  2. Ajouter regle "TOUJOURS useParams<{ id: string }>()" — jamais :userId
  3. Mentionner IMPLICIT_SUFFIXES (.detail/.edit/.create) avec liste complete

### frontend/structure — 4/10
[...meme format...]

[... etc pour les 10 skills ...]

━━━ Fin du rapport ━━━
```

## Format detaille d'une entree par skill

Pour chaque skill, utiliser cette structure :

```
### {skill-path} — {X}/{Y}
Ce qu'il genere : {1 phrase}
Criteres :
  A. {nom critere}       {OK|PARTIAL|MISSING|N/A}   [Line NN si applicable]
  B. ...
Recommandations (a appliquer manuellement) :
  1. {action concrete + ligne a modifier + wording exact suggere}
  2. ...
  3. ...
```

Maximum 3 recommandations par skill (les plus impactantes).

## Regles

- **READ-ONLY absolu** : aucun Edit, aucun Write sur les skills. Violation = bug du skill.
- **Citer numeros de ligne** quand possible (aide l'utilisateur a appliquer la recommandation)
- **Pas de jugement de valeur** sur le code genere (on audite la documentation du skill, pas l'execution)
- **N/A explicite** quand un critere ne s'applique pas (ex: G pour un skill frontend)
- **Score transparent** : afficher le denominateur (X/Y) pour que l'utilisateur voie combien de criteres etaient applicables
- **Pas de follow-up auto** : ce skill est read-only, ne pas modifier les fichiers audites
- **Escalade** : si l'utilisateur demande des corrections apres l'audit, rediriger vers `/apex` ou creation manuelle — ce skill ne corrige pas
