3.8 KiB
3.8 KiB
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 pagesGET /pages/{slug}— single published page by slugGET /posts— list published posts (pagination:?page=1&per_page=10, ordered bycreated_atdesc)GET /posts/{slug}— single published post by slugGET /settings— site settings singleton
Protected (JWT required):
POST / PUT / DELETEfor pages and postsPUT /settingsPOST /auth/login— acceptsemail+password, returns JWT access + refresh tokensPOST /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.pyscript that creates a default admin user and sample content - Add a
Dockerfileanddocker-compose.yml(API + Postgres) - Include a
.env.examplewith all required env vars documented - Write basic pytest tests for auth flow and one CRUD resource
- Add OpenAPI tags and descriptions so the
/docspage 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_pagesmetadata