---
name: step-05-frontend
description: Generate frontend code using MCP tools (component, API client, routes, i18n)
prev_step: steps/step-04-backend.md
next_step: steps/step-06-migration.md
---

# Step 5: Frontend Generation

## MANDATORY EXECUTION RULES

- ALWAYS use MCP tools for frontend generation
- ALWAYS generate i18n for 4 languages (fr, en, it, de)
- ALWAYS use nested routes (not flat)
- YOU ARE AN ORCHESTRATOR calling MCP, not a generator

## YOUR TASK

Use MCP tools to generate:
1. React component (scaffold_extension type: component)
2. TypeScript API client (scaffold_api_client)
3. Route configuration (scaffold_routes)
4. i18n files (scaffold_translations for UI)

---

## AVAILABLE STATE

From previous steps:

| Variable | Description |
|----------|-------------|
| `{full_path}` | Complete navigation path (navRoute) |
| `{entity_name}` | PascalCase entity name |
| `{entity_code}` | kebab-case code |
| `{labels}` | Object with fr, en, it, de |
| `{api_route}` | API endpoint path |

---

## EXECUTION SEQUENCE

### 1. Generate Frontend Pages (conventions-compliant)

```
Tool: mcp__smartstack__scaffold_extension
Args:
  type: "page"
  name: "{entity_name}"
  options:
    navRoute: "{full_path}"
    outputPath: "web/src/pages/{context}/{application}/{module}"
    dryRun: false
```

This generates (all natively compliant with /ui-components conventions):
- `{EntityName}Page.tsx` — List page wrapper with i18n
- `{EntityName}ListView.tsx` — EntityCard grid + DataTable + ViewToggle + responsive + loading/error/empty states
- `{EntityName}DetailPage.tsx` — Detail page with back button + pill tabs + info cards
- `use{EntityName}Preferences.ts` — Preferences hook (viewMode, sorting, filters, columns)
- i18n files for 4 languages (fr, en, it, de)

> **Note:** The `type: "page"` scaffold already includes CSS variables, EntityCard, responsive grid,
> semantic HTML, memo/useCallback, and all ui-components conventions. No manual corrections needed.

### 2. Generate API Client

```
Tool: mcp__smartstack__scaffold_api_client
Args:
  navRoute: "{full_path}"
  name: "{entity_name}"
  methods: ["getAll", "getById", "create", "update", "delete"]
  options:
    includeTypes: true
    includeHook: true
```

This generates:
- `services/api/{entityCode}Api.ts` - API service
- `types/{entityName}.types.ts` - TypeScript interfaces
- `hooks/use{EntityName}Api.ts` - React Query hook (optional)

### 3. Generate Route Configuration

```
Tool: mcp__smartstack__scaffold_routes
Args:
  source: "controllers"
  scope: "all"
  options:
    includeGuards: true
    generateRegistry: true
    outputFormat: "clientRoutes"
```

This generates:
- `navRoutes.generated.ts` - Route registry (NavRoute to API/web path mapping)
- `clientRoutes.generated.tsx` - Route fragments grouped by context with page imports

### 4. Wire Routes to App.tsx (BLOCKING)

> **CRITICAL:** This step is MANDATORY. Without it, routes exist as files but are invisible to the React Router. The page will be BLANK.

After `scaffold_routes` generates the route files, you MUST manually insert the routes into `App.tsx`:

**Step 4a:** Import the page components at the top of App.tsx:

```tsx
import { {EntityName}Page } from '@/pages/{Context}/{Application}/{Module}/{EntityName}Page';
// Or lazy-loaded:
const {EntityName}Page = lazy(() => import('@/pages/{Context}/{Application}/{Module}/{EntityName}Page'));
```

**Step 4b:** Find the correct Layout wrapper block in App.tsx:

| Context | Layout block to find |
|---------|---------------------|
| `platform.*` | `<Route path="/platform" element={<AdminLayout />}>` |
| `business.*` | `<Route path="/business" element={<BusinessLayout />}>` |
| `personal.*` | `<Route path="/personal/myspace" element={<UserLayout />}>` |

**Step 4c:** Insert route entries INSIDE the Layout block (as children, using relative paths):

```tsx
// ✅ CORRECT - Route added INSIDE the layout wrapper
<Route path="/business" element={<BusinessLayout />}>
  {/* ... existing routes ... */}
  <Route path="{application}/{module}" element={<{EntityName}Page />} />
</Route>

// ❌ FORBIDDEN - Route added OUTSIDE layout (shell will NOT render!)
<Route path="/business/{application}/{module}" element={<{EntityName}Page />} />
```

**Step 4d:** ALSO add the same routes inside the tenant-prefixed block:

Find `<Route path="/t/:slug">` and locate the matching `<Route path="{context}" element={<{Layout} />}>` inside it.
Add the **same route entries** there.

**Step 4e:** Verify wiring:

```
Tool: mcp__smartstack__validate_frontend_routes
Args:
  scope: "routes"
```

If `appWiring.issues` is not empty, fix the wiring before proceeding.

**For new applications (no existing layout route for the context):**

If the context doesn't have a layout route yet, create one wrapping all child routes:

```tsx
<Route path="/{context}/{application}" element={<{Context}Layout />}>
  <Route index element={<Navigate to="{default_module}" replace />} />
  <Route path="{module}" element={<{EntityName}Page />} />
</Route>
```

**FORBIDDEN:**
- Adding routes OUTSIDE the Layout wrapper (shell will not render)
- Adding routes only in the standard block but not in the tenant block
- Using `createBrowserRouter` (SmartStack uses `BrowserRouter` with JSX `<Routes>`)

### 5. Verify i18n Files

> **Note:** i18n files are now auto-generated by `type: "page"` scaffold (step 1).
> Verify the 4 language files were created and customize the `title`/`subtitle` with the proper labels.

If the generated translations need customization (e.g., replacing generic title with `{labels.fr}`):
- `i18n/locales/fr/{entityCode}.json` → set `"title": "{labels.fr}"`
- `i18n/locales/en/{entityCode}.json` → set `"title": "{labels.en}"`
- `i18n/locales/it/{entityCode}.json` → set `"title": "{labels.it}"`
- `i18n/locales/de/{entityCode}.json` → set `"title": "{labels.de}"`

### 6. Present Output to User

```markdown
## Frontend Code Generated

### Pages
- `pages/{context}/{application}/{module}/{EntityName}Page.tsx`
- `pages/{context}/{application}/{module}/{EntityName}ListView.tsx`

### Components
- `components/{context}/{module}/{EntityName}.tsx`
- `hooks/use{EntityName}.ts`

### API Client
- `services/api/{entityCode}Api.ts`
- `types/{entityName}.types.ts`

### Routes
- Updated `navRoutes.generated.ts`
- Generated `clientRoutes.generated.tsx`
- Wired routes in `App.tsx` (standard + tenant blocks)

### i18n
- `locales/fr/{entityCode}.json`
- `locales/en/{entityCode}.json`
- `locales/it/{entityCode}.json`
- `locales/de/{entityCode}.json`

### Route Configuration
```tsx
// In routes.tsx - NESTED routes (not flat!)
<Route path="{application}">
  <Route index element={<Navigate to="{module}" replace />} />
  <Route path="{module}" element={<{EntityName}Page />} />
</Route>
```
```

---

## ROUTING RULES

See [references/frontend-verification.md](../references/frontend-verification.md) for detailed routing rules with code examples:
- **Rule 1:** Routes MUST be inside Layout wrappers (BusinessLayout, AdminLayout, UserLayout)
- **Rule 2:** Use NESTED routes (not flat) — flat routes bypass layout and break the shell

---

## I18N STRUCTURE

All i18n files must follow this structure:

```
locales/
├── fr/
│   └── {entityCode}.json
├── en/
│   └── {entityCode}.json
├── it/
│   └── {entityCode}.json
└── de/
    └── {entityCode}.json
```

---

## POST-GENERATION VERIFICATION (MANDATORY)

**Before proceeding to step-06, run all 7 checks on generated frontend files.**

See [references/frontend-verification.md](../references/frontend-verification.md) for the complete checklist:
1. CSS Variables (BLOCKING) — no hardcoded Tailwind colors
2. API Client (BLOCKING) — use configured client, not raw axios
3. EntityCard — use EntityCard component for grid/card views
4. i18n (BLOCKING) — exactly 4 language files with identical keys
5. Route (BLOCKING) — inside Layout wrapper, nested, correct path convention
6. States — loading, error, empty states present
7. TypeScript Build (BLOCKING) — `npx tsc --noEmit` passes for generated files

---

## SUCCESS METRICS

- React component generated
- API client generated with types
- Routes updated (nested structure)
- Routes wired in App.tsx (standard + tenant blocks)
- i18n files created (4 languages)
- Post-generation verification passed (all 7 checks + route wiring check)
- Proceeded to step-06-migration.md

## FAILURE MODES

- Component generation failed (check entity name)
- API client generation failed (check navRoute)
- Route configuration failed (check existing routes)
- Hardcoded colors detected → Fix before continuing
- Missing language files → Generate all 4 before continuing

---

## NEXT STEP

After displaying frontend code, proceed to `./step-06-migration.md`
