# `docs/api/`

API reference for LOMA-PORTAL. Generated + hand-written.

## Live Swagger / OpenAPI

| API                    | URL (local)                   | Source                                           |
| ---------------------- | ----------------------------- | ------------------------------------------------ |
| .NET API (canonical)   | http://localhost:5080/swagger | `dotnet/src/Api/Extensions/SwaggerExtensions.cs` |
| NestJS API (secondary) | http://localhost:3001/docs    | `apps/api-nest/src/main.ts`                      |

In production, Swagger UI is gated behind auth; the raw OpenAPI doc is served for tooling integration.

## Generated types

`packages/api-contracts/` holds Zod schemas (the single source of runtime + types). A Phase 9+ task wires `pnpm generate:openapi` to consume the .NET Swagger doc and reconcile any drift against the Zod schemas (the script lands when the contract-test runner does).

## Conventions every endpoint follows

- Response: `ApiResponse<T>` — `{ success, message, data }`.
- List response: `PagedResponse<T>` — `ApiResponse<T[]> + { page, pageSize, total }`.
- Errors: RFC 7807 `application/problem+json` with `traceId` (= correlation-id).
- Auth: `Authorization: Bearer <jwt>`; cookies for the Next.js Server Actions.
- Correlation: `X-Correlation-Id` echoed in every response.
- Rate limits: `/api/auth/*` 10/min/IP, `/api/*` 100/min/IP, login burst 5.

## Headers

| Header                                   | Direction | Purpose                                                |
| ---------------------------------------- | --------- | ------------------------------------------------------ |
| `Authorization: Bearer …`                | request   | JWT access token                                       |
| `X-Correlation-Id`                       | both      | Cross-service trace id                                 |
| `Accept-Language`                        | request   | `en` or `th` — server-rendered error messages honor it |
| `Content-Type: application/json`         | both      | Default                                                |
| `Content-Type: application/problem+json` | response  | On 4xx/5xx — RFC 7807                                  |

## Pagination

Default: `?page=1&pageSize=20`. Max `pageSize=200`.

For large lists, prefer keyset cursors:

```
GET /api/audit?cursor=<last-id>&limit=50
```

The endpoint advertises this in its OpenAPI description.

## Versioning

Today there is no `/v1/` prefix — we move forward in one stream and treat breaking changes as ADR-worthy events. If we add versioning, it'll be a path prefix.

## Cross-references

- `packages/api-contracts/README.md`
- `docs/decisions/0005-jwt-plus-refresh-token-strategy.md`
- `.claude/skills/auth-flow/SKILL.md`
