PROJECTTEMPLATE

REST/GraphQL API Skeleton

A backend skeleton for people who already know which stack they want and why. It carries the decisions that hurt to change later: JWT auth, money stored in cents, soft deletes via deleted_at, consistent error shapes. Disagree with any of them if you like, but disagree now, before the agent generates forty endpoints on top of them.

markdown
# API Project Spec

## Project

A REST API for [BUSINESS NAME]'s [APP TYPE] app. Powers the frontend
at [FRONTEND URL].

## Stack

- Language: Python 3.12.
- Framework: FastAPI.
- Database: PostgreSQL 16.
- ORM: SQLAlchemy 2.x with async support.
- Migrations: Alembic.
- Auth: JWT in Authorization header. Refresh tokens stored in
  database.
- Package management: uv.
- Container: Docker.

(Alternative: skip this entire spec, use Devii to auto-generate the
API from the database. Use this template only if you need custom
business logic that Devii's process rules don't cover.)

## Resources

For each resource, the standard CRUD endpoints:

- `GET /api/{resource}` — list with pagination and filters.
- `GET /api/{resource}/{id}` — single item.
- `POST /api/{resource}` — create.
- `PATCH /api/{resource}/{id}` — partial update.
- `DELETE /api/{resource}/{id}` — soft-delete (sets `deleted_at`).

Resources to expose:
- `customers`
- `orders`
- `products`
- `users` (admin only for write operations)

For each resource, specify:
- Required fields, optional fields, computed fields.
- Validation rules.
- Permissions per role.
- Side effects (events fired, emails sent, audit log entries).

(Use the format from section 5.6 for each endpoint.)

## Auth Endpoints

- `POST /api/auth/login` — email + password → access token + refresh
  token.
- `POST /api/auth/refresh` — refresh token → new access token.
- `POST /api/auth/logout` — invalidate refresh token.
- `GET /api/auth/me` — return current user info.

## Conventions

- All responses return JSON with `Content-Type: application/json`.
- Errors return:
  ```json
  {
      "error": {
          "code": "VALIDATION_ERROR",
          "message": "human-readable",
          "details": { "field_name": "what's wrong" }
      }
  }
  ```
- Timestamps in ISO 8601 UTC.
- All money values in integer cents (no floats for money).
- Soft delete via `deleted_at` column, never hard-delete.

## Permissions

See `roles.md`. Implement as a dependency that wraps each route.

## Rate Limiting

- 60 requests/minute per authenticated user.
- 10 requests/minute per IP for unauthenticated routes.

## Verification Checklist

- [ ] All resources respond to all 5 standard endpoints.
- [ ] Auth flow works end-to-end.
- [ ] Role-based permissions enforced.
- [ ] Validation errors return the documented shape.
- [ ] Rate limits trigger at the documented thresholds.
- [ ] Database migrations apply cleanly to a fresh database.