# Controller NavRoute and Folder Hierarchy

> Referenced from `steps/step-04-backend.md` — Controller file organization and NavRoute conventions.

---

## Controller File Location

Controllers are organized by **application** (matching SmartStack.app pattern):

```
Api/Controllers/
├── Administration/            ← administration.*
│   ├── {Module}/              ← Module sub-folder (e.g., AI/, Communications/, Tenants/)
│   │   └── {EntityName}Controller.cs
│   └── {EntityName}Controller.cs  ← Direct controllers (no module sub-folder)
├── Support/                   ← support.*
│   └── {EntityName}Controller.cs
├── {ApplicationPascal}/       ← Other applications (e.g., Sales/, HumanResources/)
│   └── {EntityName}Controller.cs
├── MySpace/                   ← myspace.*
│   └── {EntityName}Controller.cs
└── {SharedControllers}.cs     ← Root-level (Auth, Config, Navigation, etc.)
```

## Application-to-Folder Mapping

| NavRoute Application | Controller Folder | Example |
|-----------------|-------------------|---------|
| `administration` | `Administration` | `Controllers/Administration/TenantsController.cs` |
| `administration.{module}` | `Administration/{Module}` | `Controllers/Administration/AI/AiPromptsController.cs` |
| `support` | `Support` | `Controllers/Support/TicketsController.cs` |
| `{application}` | `{ApplicationPascal}` | `Controllers/Sales/ProductsController.cs` |
| `myspace` | `MySpace` | `Controllers/MySpace/PreferencesController.cs` |

## Controller Attributes

The generated controller uses NavRoute attribute:

```csharp
[ApiController]
[NavRoute("{full_path}")]
[Microsoft.AspNetCore.Authorization.Authorize]
[Produces("application/json")]
[Tags("{EntityNamePlural}")]
public class {EntityName}Controller : ControllerBase
{
    private readonly ISender _mediator;

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

    [HttpGet]
    [RequirePermission(Permissions.{Application}.{Module}.View)]
    [ProducesResponseType(typeof(List<{EntityName}ListDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    public async Task<ActionResult<List<{EntityName}ListDto>>> GetAll(CancellationToken ct)
        => Ok(await _mediator.Send(new Get{EntityNamePlural}Query(), ct));

    // ... 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
- Controller file is in the correct application folder
