Files
gw/AGENT.md
T
ponzischeme89 6d44e05de4 v1
2026-04-18 07:23:55 +12:00

80 lines
3.8 KiB
Markdown

# Project: CMS API for SvelteKit Marketing Site
## Context
I have a public marketing website built with SvelteKit (frontend) and Python (backend). I need a secure, read/write JSON API that:
- Serves as the data layer between a CMS admin interface and the SvelteKit frontend
- Allows authenticated CMS users to create, update, and delete content
- Allows the SvelteKit frontend to read content (public, no auth required for reads)
## Tech Stack
- **API**: Python (FastAPI)
- **Database**: PostgreSQL via SQLAlchemy (async) + Alembic for migrations
- **Auth**: JWT bearer tokens for write operations (CMS admin). Read endpoints are public.
- **Validation**: Pydantic v2 models for all request/response schemas
- **Frontend consumer**: SvelteKit `load()` functions calling the API server-side
## Requirements
### Data Models
Scaffold these content types (all with `id`, `created_at`, `updated_at`, `published` boolean, `slug` unique index):
- **Page** — `title`, `slug`, `body` (rich text/HTML string), `meta_title`, `meta_description`, `og_image_url`
- **BlogPost** — `title`, `slug`, `excerpt`, `body`, `author`, `featured_image_url`, `tags` (array of strings)
- **SiteSettings** — singleton row: `site_name`, `tagline`, `logo_url`, `footer_text`, `social_links` (JSON object)
### API Endpoints
All under `/api/v1/`:
**Public (no auth):**
- `GET /pages` — list published pages
- `GET /pages/{slug}` — single published page by slug
- `GET /posts` — list published posts (pagination: `?page=1&per_page=10`, ordered by `created_at` desc)
- `GET /posts/{slug}` — single published post by slug
- `GET /settings` — site settings singleton
**Protected (JWT required):**
- `POST / PUT / DELETE` for pages and posts
- `PUT /settings`
- `POST /auth/login` — accepts `email` + `password`, returns JWT access + refresh tokens
- `POST /auth/refresh` — rotate refresh token
### Security
- Passwords hashed with bcrypt
- JWT access tokens: 15 min expiry. Refresh tokens: 7 day expiry, stored server-side, revocable.
- All write endpoints behind `Depends(get_current_user)` FastAPI dependency
- CORS: allow the SvelteKit origin only (configurable via env var `ALLOWED_ORIGINS`)
- Rate limiting on `/auth/*` endpoints (e.g. slowapi, 5 req/min per IP)
- Input sanitisation: strip/reject dangerous HTML in body fields (bleach or nh3)
### Project Structure
```
backend/
├── app/
│ ├── main.py # FastAPI app, CORS, lifespan
│ ├── config.py # pydantic-settings BaseSettings from .env
│ ├── database.py # async engine, sessionmaker, get_db dependency
│ ├── models/ # SQLAlchemy ORM models
│ ├── schemas/ # Pydantic request/response schemas
│ ├── routers/ # pages.py, posts.py, settings.py, auth.py
│ ├── services/ # business logic layer
│ ├── auth/ # JWT creation, verification, password hashing
│ └── middleware/ # rate limiting, request logging
├── alembic/ # migrations
├── alembic.ini
├── requirements.txt
├── .env.example
└── Dockerfile
```
### Additional
- Include a `seed.py` script that creates a default admin user and sample content
- Add a `Dockerfile` and `docker-compose.yml` (API + Postgres)
- Include a `.env.example` with all required env vars documented
- Write basic pytest tests for auth flow and one CRUD resource
- Add OpenAPI tags and descriptions so the `/docs` page is well-organised
## Constraints
- Python 3.12+
- Do NOT use any ORM magic for auth — keep JWT logic explicit and auditable
- All database calls must be async
- Return proper HTTP status codes (201 on create, 204 on delete, 404/422/401/403 as appropriate)
- Pagination responses must include `total`, `page`, `per_page`, `total_pages` metadata