# Controller & DTO Code Templates

> Referenced from `steps/step-03-generate.md` — C# templates for controller, DTOs, and security patterns.

---

## Controller Template

**Target path:** `src/SmartStack.Api/Controllers/{ApplicationPascal}/{ModulePascal}/{entity}Controller.cs`

> Application mapping: `administration` → `Administration`, `support` → `Support`, `myspace` → `MySpace`
> Deep hierarchy: navRoute segments map to folder levels.

```csharp
using MediatR;
using Microsoft.AspNetCore.Mvc;
using SmartStack.Api.Authorization;
using SmartStack.Api.Routing;
using SmartStack.Application.Common.Authorization;

namespace SmartStack.Api.Controllers.{area};

[ApiController]
[NavRoute("{app}.{module}")]
[Microsoft.AspNetCore.Authorization.Authorize]
[Produces("application/json")]
[Tags("{namePlural}")]
public class {entity}Controller : ControllerBase
{
    private readonly ISender _mediator;

    public {entity}Controller(ISender mediator) => _mediator = mediator;

    // Endpoints generated based on plan...
}
```

**Key conventions:**
- `ISender _mediator` (MediatR) — NOT `IApplicationDbContext` or `I{Name}Service`
- `[Microsoft.AspNetCore.Authorization.Authorize]` — fully qualified
- `[NavRoute]` is the ONLY route attribute — do NOT combine with `[Route("api/...")]`
- `[Tags]` and `[Produces("application/json")]` always present
- `[RequirePermission]` on every endpoint — `[Authorize]` alone has no RBAC

---

## GET Endpoint Example

```csharp
[HttpGet]
[RequirePermission(Permissions.{Module}.{Resource}.View)]
[ProducesResponseType(typeof(List<{entity}ListDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<List<{entity}ListDto>>> GetAll(CancellationToken ct)
{
    var result = await _mediator.Send(new Get{entityPlural}Query(), ct);
    return Ok(result);
}
```

**Endpoint attributes to include:**
1. `[HttpGet]`, `[HttpPost]`, etc.
2. `[RequirePermission(Permissions.{Module}.{Resource}.View)]` — permission constants
3. `[ProducesResponseType(typeof(...), StatusCodes.Status200OK)]` — StatusCodes constants
4. `[ProducesResponseType(StatusCodes.Status401Unauthorized)]`
5. `[ProducesResponseType(StatusCodes.Status403Forbidden)]`

---

## Return Types by Endpoint

| Endpoint | Return Type | Notes |
|----------|-------------|-------|
| GetAll | `Task<ActionResult<List<{entity}ListDto>>>` | List DTO for summary |
| GetById | `Task<ActionResult<{entity}DetailDto>>` | Detail DTO with full data |
| Create | `Task<ActionResult<{entity}DetailDto>>` | Returns 201 with CreatedAtAction |
| Update | `Task<ActionResult<{entity}DetailDto>>` | Check `result.IsNotFound` |
| Delete | `Task<IActionResult>` | Returns 204 NoContent or 404 |

---

## DTO Templates

**Target paths:**
```
src/SmartStack.Application/{Application}/{Module}/DTOs/{entity}ListDto.cs
src/SmartStack.Application/{Application}/{Module}/DTOs/{entity}DetailDto.cs
src/SmartStack.Application/{Application}/{Module}/DTOs/Create{entity}Request.cs
src/SmartStack.Application/{Application}/{Module}/DTOs/Update{entity}Request.cs
```

> DTOs are in `Application/{Domain}/.../DTOs/` — NOT in `Application/DTOs/{module}/`.

**ListDto (for GetAll):**
```csharp
public record {entity}ListDto(
    Guid Id,
    string Name,
    // ... summary properties
    DateTime CreatedAt
);
```

**DetailDto (for GetById, Create, Update):**
```csharp
public record {entity}DetailDto(
    Guid Id,
    string Name,
    // ... all properties
    DateTime CreatedAt,
    DateTime? UpdatedAt
);
```

**CreateRequest:**
```csharp
public record Create{entity}Request(
    string Name
    // ... required properties
);
```

**UpdateRequest:**
```csharp
public record Update{entity}Request(
    string? Name
    // ... optional properties
);
```

---

## Security Logging Templates

```csharp
// Create
_logger.LogInformation("User {User} created {entity} {Id}",
    _currentUser.Email, entity.Id);

// Update
_logger.LogInformation("User {User} updated {entity} {Id}",
    _currentUser.Email, entity.Id);

// Delete (Warning level)
_logger.LogWarning("User {User} deleted {entity} {Id} ({Name})",
    _currentUser.Email, id, entity.Name);
```

---

## System Account Protection

```csharp
// Before modify/delete operations
if (entity.UserType == UserType.System || entity.UserType == UserType.LocalAdmin)
{
    _logger.LogWarning("Attempt to modify system account {Id} by {User}",
        entity.Id, _currentUser.Email);
    return BadRequest(new { message = "Cannot modify system accounts" });
}
```
