Depot
A headless content API — the backend half of a CMS. Email/password auth with signed-cookie sessions, hashed API tokens for delivery, a Postgres content model (collections → items with a publish lifecycle), and a token-secured read API. Built with Next.js route handlers, Drizzle ORM and Neon Postgres.
What it demonstrates
Auth, two surfaces
bcrypt passwords + `jose` JWT sessions for the admin; high-entropy depot_… tokens (SHA-256 hashed) for delivery.
Typed data layer
Drizzle schema with relations, unique indexes, migrations and a JSONB content column. Neon HTTP driver — serverless-safe.
API rigor
Zod validation, a consistent error envelope, per-IP rate limiting and ownership checks on every mutation.
Delivery API
Read published content with a bearer token — CORS-open, so any frontend can consume it:
curl https://depot.vitaliipopov.dev/api/v1/articles \
-H "Authorization: Bearer depot_your_token_here"
# → { "data": [ { "slug": "hello-world", "data": { ... }, "publishedAt": "…" } ] }Endpoints
| Method | Path | Auth | Purpose |
|---|---|---|---|
POST | /api/auth/register | — | Create an admin account |
POST | /api/auth/login | — | Start a session |
GET | /api/auth/me | session | Current user |
GET/POST | /api/collections | session | List / create content types |
GET/POST | /api/collections/:slug/items | session | List / create entries |
PATCH | /api/items/:id | session | Edit / publish an entry |
POST | /api/tokens | session | Issue a delivery token |
GET | /api/v1/:collection | token | Delivery: published items |
GET | /api/v1/:collection/:slug | token | Delivery: one item |