modules/ai-guide/Write-AiGuide-WebApi.ps1

param(
    [string]   $ProjectName,
    [string]   $OutputPath
)

. (Join-Path (Split-Path $MyInvocation.MyCommand.Path) "..\core\Utils.ps1")

$guideDir = Join-Path $OutputPath "ai-guide"
function Write-Guide($fileName, $content) {
    Write-CoreFile (Join-Path $guideDir $fileName) $content
}

$webapiGuideContent = @'
# WebApi Layer AI Developer Guide
 
You are an AI assistant helping developers build the WebApi Layer of the {P} solution.
This layer is the entry point of the API, managing HTTP routing, controller endpoints, validation filters, authorization, and exception handling.
 
---
 
## Strict WebApi Rules
 
1. **Lightweight Controllers:** Controllers must not contain business logic or DB calls. They only accept inputs, invoke MediatR (`_mediator.Send`), and return the result.
2. **ApiResponse Wrapper:** All HTTP actions must return responses wrapped in the `ApiResponse<T>` wrapper (e.g. `return Ok(ApiResponse<CategoryDto>.Ok(result));`).
3. **No Controller Try/Catch:** Do not write try/catch blocks inside controllers. The `GlobalExceptionHandler` automatically intercepts exceptions and returns standardized `ProblemDetails`.
4. **Authorization Policies:** Secure endpoints using role policies like `[Authorize(Policy = "AdminOnly")]` or `[Authorize(Policy = "UserOnly")]`.
 
---
 
## How to Add a Controller
 
When adding a controller for a new entity (e.g. `Category`), implement it in `{P}-backend/src/{P}.WebApi/Controllers`.
 
**Required endpoints per entity:**
- `GET api/categories` — returns all (internal/admin use)
- `GET api/categories/paged` — paginated list for public-facing UI (**always use this for lists**)
- `POST api/categories` — create new
- `DELETE api/categories/{id}` — soft delete (AdminOnly)
 
```csharp
// {P}-backend/src/{P}.WebApi/Controllers/CategoriesController.cs
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using {P}.Application.Common;
using {P}.Application.Features.Categories;
using {P}.Application.Features.Categories.Commands.AddCategory;
using {P}.Application.Features.Categories.Commands.DeleteCategory;
using {P}.Application.Features.Categories.Queries.GetAllCategories;
using {P}.Application.Features.Categories.Queries.GetPagedCategories;
using {P}.Domain.Common;
 
namespace {P}.WebApi.Controllers;
 
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class CategoriesController : ControllerBase
{
    private readonly IMediator _mediator;
    public CategoriesController(IMediator mediator) => _mediator = mediator;
 
    [HttpGet]
    public async Task<IActionResult> GetAll()
        => Ok(ApiResponse<object>.Ok(await _mediator.Send(new GetAllCategoriesQuery())));
 
    [HttpGet("paged")]
    public async Task<IActionResult> GetPaged([FromQuery] int page = 1, [FromQuery] int size = 20)
        => Ok(ApiResponse<object>.Ok(await _mediator.Send(new GetPagedCategoriesQuery(page, size))));
 
    [HttpPost]
    public async Task<IActionResult> Add([FromBody] AddCategoryCommand cmd)
        => Ok(ApiResponse<object>.Ok(new { id = await _mediator.Send(cmd) }));
 
    [HttpDelete("{id}")]
    [Authorize(Policy = "AdminOnly")]
    public async Task<IActionResult> Delete(int id)
        => Ok(ApiResponse<object>.Ok(await _mediator.Send(new DeleteCategoryCommand(id))));
}
```
 
---
 
## Global Exception Handling
 
Errors are captured globally by `GlobalExceptionHandler.cs`. The response format automatically maps based on the exception type:
- **ValidationException:** Returns HTTP 400 with a dictionary of validation failures.
- **KeyNotFoundException:** Returns HTTP 404.
- **UnauthorizedAccessException:** Returns HTTP 401.
- **Other Exceptions:** Returns HTTP 500.
 
Do not write custom error-wrapping catch blocks; allow the handler to output standardized problem details automatically.
'@
.Replace("{P}", $ProjectName)

Write-Guide "webapi-guide.md" $webapiGuideContent