---
name: step-04-backend
description: Generate backend code using MCP scaffold_extension
prev_step: steps/step-03-roles.md
next_step: steps/step-05-frontend.md
---

# Step 4: Backend Generation

## MANDATORY EXECUTION RULES

- ALWAYS use MCP `scaffold_extension` tool - NEVER use templates
- ALWAYS generate Entity + Service + Controller as a unit
- NEVER skip controller generation - API is required
- YOU ARE AN ORCHESTRATOR calling MCP, not a generator

## YOUR TASK

Call the SmartStack MCP `scaffold_extension` tool with type "feature" to generate:
1. Domain Entity with EF Configuration
2. Application Service (Interface + Implementation)
3. API Controller with NavRoute attribute
4. DTOs (Response, Create, Update)

---

## AVAILABLE STATE

From previous steps:

| Variable | Description |
|----------|-------------|
| `{level}` | context, application, module, or section |
| `{code}` | kebab-case identifier |
| `{full_path}` | Complete navigation path (navRoute) |
| `{labels}` | Object with fr, en, it, de |

---

## EXECUTION SEQUENCE

### 1. Derive Entity Name

Convert `{code}` to PascalCase for entity name:

```
code: "products"        → entityName: "Product"
code: "order-items"     → entityName: "OrderItem"
code: "user-profiles"   → entityName: "UserProfile"
```

### 2. Determine Table Prefix

Based on navigation context:

| Context | Prefix |
|---------|--------|
| platform.administration | `auth_` or `cfg_` |
| platform.support | `support_` |
| business.* | `ref_` or domain-specific |
| personal.* | `usr_` |

### 3. Call MCP scaffold_extension

```
Tool: mcp__smartstack__scaffold_extension
Args:
  type: "feature"
  name: "{entityName}"  # PascalCase
  options:
    navRoute: "{full_path}"
    tablePrefix: "{prefix}"
    schema: "core"
    withDtos: true
    withValidation: true
    withRepository: false  # Use service pattern
    skipComponent: true    # Frontend in next step
    dryRun: false
```

### 4. Parse MCP Response

The tool generates (paths organized by navRoute hierarchy `{context}.{application}.{module}`):
- `Domain/{Context}/{Application}/{Module}/{EntityName}.cs` - Entity with BaseEntity
- `Infrastructure/Persistence/Configurations/{Module}/{EntityName}Configuration.cs` - EF Config
- `Application/Common/Interfaces/I{EntityName}Service.cs` - Service Interface
- `Infrastructure/Services/{Module}/{EntityName}Service.cs` - Service Implementation
- `Api/Controllers/{Context}/{EntityName}Controller.cs` - REST Controller
- `Application/{Context}/{Application}/{Module}/DTOs/{EntityName}ResponseDto.cs` - Response DTO
- `Application/{Context}/{Application}/{Module}/DTOs/Create{EntityName}Dto.cs` - Create request
- `Application/{Context}/{Application}/{Module}/DTOs/Update{EntityName}Dto.cs` - Update request

### 5. Present Output to User

```markdown
## Backend Code Generated

### Domain Layer
- `Domain/{Context}/{Application}/{Module}/{EntityName}.cs`

### Infrastructure Layer
- `Persistence/Configurations/{Module}/{EntityName}Configuration.cs`
- `Services/{Module}/{EntityName}Service.cs`

### Application Layer
- `Common/Interfaces/I{EntityName}Service.cs`
- `{Context}/{Application}/{Module}/DTOs/{EntityName}ResponseDto.cs`
- `{Context}/{Application}/{Module}/DTOs/Create{EntityName}Dto.cs`
- `{Context}/{Application}/{Module}/DTOs/Update{EntityName}Dto.cs`

### API Layer
- `Controllers/{Context}/{EntityName}Controller.cs`
  - NavRoute: `{full_path}`
  - Endpoints:
    - GET /api/{code} - List all
    - GET /api/{code}/{id} - Get by ID
    - POST /api/{code} - Create
    - PUT /api/{code}/{id} - Update
    - DELETE /api/{code}/{id} - Delete

### Next Steps
1. Add DbSet to ICoreDbContext: `public DbSet<{EntityName}> {EntityName}s => Set<{EntityName}>();`
2. Register service in DI: `services.AddScoped<I{EntityName}Service, {EntityName}Service>();`
3. Run: `dotnet ef migrations add core_vX.X.X_XXX_Add{EntityName}`
```

### 6. Entity Seeding (Optional)

> Ask the user if they want to seed initial data for the entity.
> This creates runtime seed data (applied at startup via DevDataSeeder), following the same
> architecture as core (SeedData provider pattern).

```yaml
questions:
  - header: "Seed Data"
    question: "Would you like to generate initial seed data for {EntityName}?"
    options:
      - label: "Yes - Generate SeedData provider"
        description: "Creates {EntityName}SeedData.cs + registers in DevDataSeeder (same pattern as core)"
      - label: "No - Skip seeding"
        description: "Entity starts empty (can add seed data later)"
    multiSelect: false
```

#### If User Selects YES:

**Reference:** See `templates-seed.md` section "TEMPLATE: ENTITY SEED DATA (SeedData Provider)"

**Generate the following files:**

1. **`Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs`**

   Follow the SmartStack.app pattern (same architecture as core):
   - Static class with `internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()`
   - Use deterministic GUIDs (NEVER `Guid.NewGuid()`)
   - Include 3-5 sample entities with varied, realistic data
   - Internal record class `{EntityName}SeedItem` with all entity properties
   - For multi-tenant entities: organize by tenant using `GetTenant1{EntityName}s()` helper methods
   - Reference existing tenant/user IDs from `TenantSeedData`/`UserSeedData` for foreign keys

   ```csharp
   // Infrastructure/Persistence/Seeding/Data/{Domain}/{EntityName}SeedData.cs

   public static class {EntityName}SeedData
   {
       public static readonly Guid Sample1Id = Guid.Parse("...");
       public static readonly Guid Sample2Id = Guid.Parse("...");
       public static readonly Guid Sample3Id = Guid.Parse("...");

       internal static IEnumerable<{EntityName}SeedItem> GetAll{EntityName}s()
       {
           return new[]
           {
               new {EntityName}SeedItem { Id = Sample1Id, /* ... */ },
               new {EntityName}SeedItem { Id = Sample2Id, /* ... */ },
               new {EntityName}SeedItem { Id = Sample3Id, /* ... */ }
           };
       }
   }

   internal class {EntityName}SeedItem
   {
       public Guid Id { get; init; }
       // ... all required entity properties
   }
   ```

2. **Update `Infrastructure/Persistence/Seeding/DevDataSeeder.cs`**
   - Add `using` for the new SeedData namespace
   - Add `await Seed{EntityName}sAsync(cancellationToken);` in `SeedAsync()` method
   - Add private seeding method:

   ```csharp
   private async Task Seed{EntityName}sAsync(CancellationToken cancellationToken)
   {
       _logger.LogInformation("Seeding demo {EntityName}s...");

       var existingCount = await _context.{EntityName}s.CountAsync(cancellationToken);
       if (existingCount > 0)
       {
           _logger.LogWarning("{EntityName}s already seeded ({Count} exist), skipping.", existingCount);
           return;
       }

       var createdCount = 0;
       foreach (var seedItem in {EntityName}SeedData.GetAll{EntityName}s())
       {
           var entity = {EntityName}.Create(/* map seedItem properties */);
           typeof({EntityName}).GetProperty("Id")?.SetValue(entity, seedItem.Id);
           _context.{EntityName}s.Add(entity);
           createdCount++;
       }

       if (createdCount > 0)
           await _context.SaveChangesAsync(cancellationToken);

       _logger.LogInformation("Created {Count} demo {EntityName}s.", createdCount);
   }
   ```

#### If User Selects NO:

Skip this section and proceed to storing entity info.

```markdown
> Skipping entity seed data. You can generate it later using the SeedData provider pattern
> documented in templates-seed.md.
```

### 7. Store Entity Info

Store entity information for frontend generation:

```
{entity_name} = "{EntityName}"
{entity_code} = "{code}"
{api_route} = "/api/{code}"
{has_seed_data} = true/false  // Whether SeedData provider was generated
```

---

## CONTROLLER NAVROUTE

The generated controller uses NavRoute attribute:

```csharp
[NavRoute("{full_path}")]
[ApiController]
[Authorize]
public class {EntityName}Controller : ControllerBase
{
    [HttpGet]
    [RequirePermission(Permissions.{Context}.{Application}.{Module}.Read)]
    public async Task<ActionResult<IEnumerable<{EntityName}Dto>>> GetAll() { ... }

    // ... other CRUD methods
}
```

This ensures:
- API route is derived from navigation path
- Permissions use the constants from Permissions.cs
- Frontend can discover API path from NavRoute registry

---

## MCP RESPONSE HANDLING

### Success Case

If MCP returns successfully:
- Display all generated files
- Show DbSet and DI registration instructions
- Ask about entity seeding (section 6)
- Store entity info for frontend
- Proceed to step-05-frontend.md

### Error Case

If MCP call fails:
- Display error message
- Suggest checking entity name format
- Do NOT proceed automatically

---

## POST-GENERATION VERIFICATION (MANDATORY)

**Before proceeding to step-05, run these checks on ALL generated backend files:**

### Check 1: Backend Build (BLOCKING)

```bash
dotnet build {SolutionName}.sln --no-restore
```

IF build fails:
- Read the error output carefully
- Fix compilation errors in generated files (common: missing `using`, wrong namespace, type mismatch)
- Re-run build until it succeeds
- DO NOT proceed to step-05 until the backend builds successfully

### Check 2: DbSet Registration (BLOCKING)

Verify the entity DbSet is registered in the DbContext interface:

```
Search for: DbSet<{EntityName}>
In: **/I{DbContextName}.cs or **/{DbContextName}.cs
```

IF NOT found: Add the DbSet declaration immediately:
```csharp
public DbSet<{EntityName}> {EntityName}s => Set<{EntityName}>();
```

### Check 3: DI Registration (BLOCKING)

Verify the service is registered in the DI container:

```
Search for: I{EntityName}Service
In: **/DependencyInjection.cs
```

IF NOT found: Add the service registration immediately:
```csharp
services.AddScoped<I{EntityName}Service, {EntityName}Service>();
```

### Check 4: RequirePermission Attributes (BLOCKING)

Verify ALL controller actions have `[RequirePermission]` attributes:

```
Search for: [HttpGet], [HttpPost], [HttpPut], [HttpDelete]
In: **/Controllers/**/{EntityName}Controller.cs
```

Each HTTP action MUST have a corresponding `[RequirePermission(Permissions.{Context}.{Application}.{Module}.{Action})]`.
IF any action is missing the attribute: Add it immediately.

### Check 5: Entity Configuration (BLOCKING)

Verify the EF Core configuration file exists and has correct structure:

```
Search for: {EntityName}Configuration
In: **/Persistence/Configurations/**/*Configuration.cs
```

Verify:
- `builder.ToTable("{table_prefix}{EntityName}s")` uses the correct table prefix
- `builder.HasKey(e => e.Id)` is present
- `builder.HasIndex` is defined for unique fields (e.g., Code)

IF configuration is incomplete: Fix it before continuing.

---

## SUCCESS METRICS

- MCP scaffold_extension called successfully
- Entity, Service, Controller generated
- DTOs generated
- NavRoute attribute included
- Entity seeding offered to user (SeedData.cs + DevDataSeeder if accepted)
- Entity info stored for frontend
- Post-generation verification passed (all 5 checks)
- Proceeded to step-05-frontend.md

## FAILURE MODES

- MCP call failed (display error, stop)
- Invalid entity name (must be PascalCase)
- Invalid navRoute format

---

## NEXT STEP

After backend code is generated and entity seeding is handled,
proceed to `./step-05-frontend.md`
