A minimal full-stack CRUD testbed: React + Vite frontend, FastAPI backend, SQLAlchemy ORM, SQLite.
- uv — Python toolchain
- Node.js 20+ and npm
- Docker Desktop (or Docker Engine + Compose plugin) — for containerised runs
cd backend
uv venv
uv pip install -r requirements.txtCopy the env file and edit if needed:
cp .env.example .envStart the server:
uv run uvicorn main:app --reload --port 8000API docs are available at http://localhost:8000/docs.
cd frontend
npm install
npm run devThe app runs at http://localhost:5173 and proxies /api requests to the backend.
Builds the backend and a production nginx-served frontend, wires them together, and persists the SQLite database in a named volume.
docker compose up --build| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| Backend | http://localhost:8000 |
| API docs | http://localhost:8000/docs |
Stop and remove containers:
docker compose downTo also delete the persisted database volume:
docker compose down -vcd backend
uv run pytest -v --tb=shortTests use an isolated in-memory SQLite database — no dev database is touched.
backend/
├── main.py # app factory, lifespan, CORS, router mounts
├── database.py # async engine, Base, get_session dependency
├── models/item.py # SQLAlchemy ORM model
├── schemas/item.py # Pydantic request/response schemas
├── services/ # business logic (no DB calls in routers)
├── routers/items.py # REST endpoints — calls services only
└── tests/ # pytest, in-memory SQLite, httpx async client
frontend/src/
├── api/items.js # fetch wrappers
├── hooks/useItems.js # loading/error state, add/remove
├── components/ # ItemForm, ItemList
└── pages/ItemsPage.jsx # composes hook + components
| Method | Path | Description |
|---|---|---|
| GET | /api/items/ | List all items |
| POST | /api/items/ | Create item |
| GET | /api/items/{id} | Get item |
| PATCH | /api/items/{id} | Update item |
| DELETE | /api/items/{id} | Delete item |