---
name: step-03-execute
description: Orchestrate code creation via existing skills and MCP tools
model: opus
prev_step: steps/step-02-plan.md
next_step: steps/step-04-examine.md
---

# Step 3: Execute

**CRITICAL PRINCIPLE: /apex ORCHESTRATES. It NEVER writes SmartStack code directly.**
All code goes through skills (/controller, /application, /ui-components, /efcore) or MCP tools.

## LOAD CONDITIONALLY

> **CONTEXT REUSE:** `smartstack-api.md` (loaded in step-01) and `smartstack-layers.md` (loaded in step-02) are already in context. Do NOT re-read them.

- **ALWAYS** read `references/smartstack-frontend.md` — lazy loading, i18n, page structure, CSS variables, EntityLookup, compliance gates (sections 1-9)
- If NOT `{economy_mode}` AND Layer 1 has parallel work: read `references/agent-teams-protocol.md`
- If `{delegate_mode}` AND seedData tasks exist: read `references/core-seed-data.md` — comprehensive seed data templates
- If build failure during execution: read `references/error-classification.md` — error diagnosis categories A-F

---

## Foundation Mode Detection

**IF `{foundation_mode}` == true:**

This is a foundation-only execution (called by ralph-loop Phase 0). Execute ONLY:
- Layer 0: Domain entities + EF configs + Migration

**SKIP ALL OTHER LAYERS:**
- Layer 1: Application + API + Seed Data → SKIP
- Layer 2: Frontend → SKIP
- Layer 3: Tests → SKIP

After Layer 0 completes and builds successfully:
- Commit with message: `chore(foundation): entities for {module_code}`
- Jump to step-04 for POST-CHECKs (domain + infrastructure only)
- End execution

**IF `{foundation_mode}` == false:**
Execute ALL layers normally (Layer 0 → Layer 1 → Layer 2 → Layer 3).

---

## Layer 0 — Domain + Infrastructure (sequential, agent principal)

### Domain Entities

```
For each entity to create/modify:
  → MCP scaffold_extension (type: "entity", target: entity_name)
  → Verify: inherits BaseEntity, implements ITenantEntity + IAuditableEntity
  → Verify entity matches patterns in references/smartstack-api.md
```

### EF Core Configurations

```
For each entity:
  → MCP scaffold_extension (type: "configuration", target: entity_name)
  → Verify: table name, relationships, indexes
  → Register DbSet in ExtensionsDbContext if new entity
```

### Migration (BLOCKING)

> **CRITICAL — Migration must cover ALL entities, not just the first batch.**
> Root cause (test-apex-007): Migration was created once for 3 entities, then 4 more entities
> were added later without re-running migration → 4 entities had no database tables.
> **RULE:** Create/update migration AFTER ALL entities and EF configs are registered in DbContext.
> If entities are added incrementally, create a NEW migration for each batch.

```
1. Verify ALL entities have been added as DbSet in ExtensionsDbContext
2. Verify ALL EF configurations are registered (ApplyConfigurationsFromAssembly or individual)
3. MCP suggest_migration → get standardized name
4. dotnet ef migrations add {Name} --project src/{Infra}.csproj --startup-project src/{Api}.csproj -o Persistence/Migrations
5. dotnet ef database update (if local DB)
6. dotnet build → MUST PASS
7. Verify: dotnet ef migrations has-pending-model-changes → MUST report "No pending model changes"
```

**BLOCKING:** If build fails after migration, fix EF configs before proceeding.
**BLOCKING:** If `has-pending-model-changes` reports pending changes, entities are missing from the migration — create a new migration.

### Post-Layer 0 Build Gate

```bash
dotnet build
# Note: WSL bin\Debug cleanup handled by PostToolUse hook (wsl-dotnet-cleanup.sh)
```

**MUST PASS before Layer 1. If NuGet error, run `dotnet restore` first. If file lock (MSB3021), use `--output /tmp/{project}_build`.**

---

## Layer 1 — Application + API + Seed Data

> **Layer 1 rules** are in `references/smartstack-layers.md` (already in context from step-02):
> - NavRoute and permission kebab-case (Layer 1 - API section)
> - Controller route attributes (FORBIDDEN: [Route] alongside [NavRoute])
> - Validators DI registration
> - DateOnly vs string for DTO date fields
> - Code generation patterns (ICodeGenerator<T> registration, see references/code-generation.md)

### Backend Tasks (sequential or parallel)

- **Services/DTOs:** MCP scaffold_extension
- **Controllers:** use /controller skill for complex, MCP scaffold_extension for simple
- **IMPORTANT:** ALL GetAll endpoints MUST support `?search=` query parameter (enables EntityLookup on frontend)
- **Seed data:** MCP generate_permissions, then follow smartstack-layers.md templates

### Frontend Tasks (sequential or parallel)

> **Frontend patterns** are in `references/smartstack-frontend.md` (already loaded above):
> - API client generation (MCP scaffold_api_client)
> - Route scaffolding (MCP scaffold_routes) — section 1 + 3b
> - Page types (ListPage, DetailPage, CreatePage, EditPage) — section 3
> - FK field handling (EntityLookup component) — section 6
> - Form structure (ZERO modals — all full pages) — section 3b
> - Detail page tabs (local state only) — section 3 "Tab Behavior Rules"
> - Testing patterns (co-located form tests) — section 8
> - Section-level routes and permissions — section 3b
> - I18n JSON structure and registration — section 2
> - Compliance gates (5 mandatory checks) — section 9

### If NOT economy_mode: Agent Teams (parallel)

> **Protocol:** See `references/agent-teams-protocol.md`

```
TeamCreate("apex-exec", description: "Execute Layer 1 in parallel")

Spawn 2 teammates (Opus, full tools):

1. exec-backend (team_name: "apex-exec", name: "exec-backend"):
   "Execute these Layer 1 backend tasks for module {module_code}:
    {list of application + api + seed data tasks from plan}

    For each task:
    - Application services/DTOs: MCP scaffold_extension
    - Controllers: use /controller skill for complex, MCP scaffold_extension for simple
    - IMPORTANT: ALL GetAll endpoints MUST support ?search= query parameter (enables EntityLookup on frontend)
    - Seed data: MCP generate_permissions, then follow smartstack-layers.md templates

    After ALL tasks done:
    SendMessage(type:'message', recipient:'team-lead', content:'BACKEND_COMPLETE', summary:'Backend layer done')"

2. exec-frontend (team_name: "apex-exec", name: "exec-frontend"):
   "Execute these Layer 1 frontend tasks for module {module_code}:
    {list of frontend + i18n tasks from plan}

    **MANDATORY: Read references/smartstack-frontend.md FIRST** — contains all required patterns.

    For each task:
    - API client: MCP scaffold_api_client
    - Routes: MCP scaffold_routes (outputFormat: 'clientRoutes') → generates lazy imports + Suspense
    - Pages: use /ui-components skill — MUST follow smartstack-frontend.md patterns:
      → React.lazy() for all page imports (named export wrapping)
      → <Suspense fallback={<PageLoader />}> around all lazy components
      → Page structure: hooks → useEffect(load) → loading → error → content
      → CSS variables only: bg-[var(--bg-card)], text-[var(--text-primary)]
      → SmartTable/SmartFilter/EntityCard (NEVER raw HTML)
    - **FORM PAGES (CRITICAL):** Create/Edit forms are FULL PAGES with own routes:
      → EntityCreatePage.tsx with route /{module}/create
      → EntityEditPage.tsx with route /{module}/:id/edit
      → ZERO modals/popups/drawers/dialogs for forms
      → Back button with navigate(-1) on every form page
      → See smartstack-frontend.md section 3b for templates
    - **TABS ON DETAIL PAGES (CRITICAL):** Tabs MUST switch content LOCALLY:
      → Tab click handler: setActiveTab(tabKey) ONLY — NEVER navigate() to another page
      → Tab content: render inline with {activeTab === 'tabKey' && <TabContent />}
      → Sub-resource data: fetch via API filtered by parent ID, display in tab panel
      → FORBIDDEN: navigate('../leaves?employee=${id}') in tab handler
      → See smartstack-frontend.md section 3 'Tab Behavior Rules'
    - **FK FIELDS (CRITICAL):** Foreign key Guid fields (e.g., EmployeeId) MUST use EntityLookup:
      → NEVER render FK fields as `<input>` — users cannot type GUIDs
      → NEVER render FK fields as `<select>` — even with API-loaded options, `<select>` is NOT acceptable
      → ONLY use `<EntityLookup />` from @/components/ui/EntityLookup for searchable selection
      → Each FK field needs: apiEndpoint, mapOption (display name), search support on backend
      → FORBIDDEN: `<select value={formData.departmentId}>`, `<option value={dept.id}>`, `e.target.value` for FK fields
      → See smartstack-frontend.md section 6 for the full EntityLookup pattern
    - **FORM TESTS (MANDATORY):**
      → EntityCreatePage.test.tsx (co-located next to page)
      → EntityEditPage.test.tsx (co-located next to page)
      → Cover: rendering, validation, submit, pre-fill, navigation, errors
      → See smartstack-frontend.md section 8 for test templates
    - **PERMISSIONS:** Call MCP generate_permissions for the module permission root (2 segments: {app}.{module}),
      then also call MCP generate_permissions for EACH section (3 segments: {app}.{module}.{section}).
    - **SECTION ROUTES:** Add section child routes to the module's children array.
      Wire PermissionGuard for section routes with section-level permissions.
    - I18n: Generate 4 JSON files per module namespace (fr, en, it, de)
      → Follow JSON template from smartstack-frontend.md
      → Keys: actions, labels, errors, validation, columns, form, messages, empty
      → ALL t() calls MUST use namespace prefix + fallback: t('ns:key', 'Default text')
    - MUST use src/pages/{App}/{Module}/ hierarchy (NOT flat)

    After ALL tasks done:
    SendMessage(type:'message', recipient:'team-lead', content:'FRONTEND_COMPLETE', summary:'Frontend layer done')"

Wait for both teammates to report completion.

Build verification:
  dotnet build  (backend)
  npm run typecheck           (frontend, if applicable)

shutdown_request → shutdown_response → TeamDelete("apex-exec")
```

---

## Layer 1 — Skill Delegation

| Skill | When | Context to provide |
|-------|------|--------------------|
| /controller | Custom routes, complex auth, file upload | entity, CRUD actions, permissions, routes |
| /application | Full app/module from scratch | app, module names |
| /ui-components | Complex pages (tables, grids, dashboards) | entity, fields, page type |
| /efcore | Complex EF configs, inheritance | relationships, indexes |
| /notification | In-app or email notifications | trigger, recipients, template |
| /workflow | Automated workflows | trigger, steps, conditions |

---

## Layer 2b — Documentation (after frontend pages exist)

> **After frontend pages are created, generate module documentation via `/documentation` skill.**

```
Invoke /documentation {module_code} --type user

This generates:
- src/pages/docs/business/{app}/{module}/doc-data.ts (data file)
- src/pages/docs/business/{app}/{module}/index.tsx (page wrapper)
- src/i18n/locales/fr/docs-{app}-{module}.json (French doc translations)
- Updates App.tsx routing for doc page
- Updates docs-manifest.json
```

**Verify DocToggleButton presence in list/detail pages:**
- Every `*ListPage.tsx` and `*DetailPage.tsx` MUST import and render `DocToggleButton` in their header
- Import: `import { DocToggleButton } from '@/components/docs/DocToggleButton';`
- Placement: inside the header actions area (see `smartstack-frontend.md` section 7)

---

## Layer 2 — Final Seed Data + Validation (sequential)

After Layer 1 completes:

```
1. Verify seed data completeness:
   - NavigationModuleSeedData.cs with 4 languages
   - PermissionsSeedData.cs with Guid.NewGuid()
   - RolesSeedData.cs with context-based role mapping
   - IClientSeedDataProvider updated
   - DI registration added

2. Build gate:
   dotnet build → MUST PASS
   npm run typecheck → MUST PASS (if frontend)
```

---

## FRONTEND COMPLIANCE GATE (MANDATORY before commit)

> **Reference:** See `references/smartstack-frontend.md` section 9 "Compliance Gates" for all 5 mandatory checks:
> 1. CSS Variables (theme system)
> 2. Forms as Pages (ZERO modals/drawers/slide-overs)
> 3. I18n File Structure (4 languages, separate JSON files)
> 4. Lazy Loading (React.lazy() — no static imports)
> 5. useTranslation in Pages (all text translated)

**BLOCKING:** Do NOT commit frontend changes until ALL 5 gates pass.

When delegating to `/ui-components` skill, include explicit instructions:
- "CSS: Use CSS variables ONLY — `bg-[var(--bg-card)]`, `text-[var(--text-primary)]`."
- "Forms: Create/Edit forms are FULL PAGES with own routes (e.g., `/create`, `/:id/edit`)."
- "I18n: ALL text must use `t('namespace:key', 'Fallback')`. Generate JSON files in `src/i18n/locales/`."

---

## PRD State Update (delegate mode only)

> **After completing EACH layer**, update the PRD file so `/ralph-loop` can track progress.

```
IF delegate_mode:
  After each layer completes successfully:
    Read {delegate_prd_path}
    For each task executed in this layer:
      task.status = 'completed'  (or 'failed' if errors)
      task.completed_at = new Date().toISOString()
      task.iteration = 1  (delegate mode = single iteration)
      task.commit_hash = $(git rev-parse --short HEAD)
      task.files_changed = { created: [...files created...], modified: [...files modified...] }
      task.validation = "APEX_PASS" (or error details)
    prd.updated_at = new Date().toISOString()
    Write back to {delegate_prd_path}
```

---

## Commits Per Layer

After each layer completes, gates pass, and builds pass:

```
Layer 0: feat({module}): [domain+infra] {short description}
Layer 1: feat({module}): [app+api] {short description}
Layer 1: feat({module}): [frontend] {short description}  # if applicable — AFTER all 5 gates pass
Layer 2: feat({module}): [seed] {short description}       # if applicable
```

---

## Save Output (if save_mode)

Write to `{output_dir}/03-execute.md` with execution log per layer.

---

## NEXT STEP

Load `steps/step-04-examine.md`
