Conduit Backend
A RealWorld (Conduit) API implementation in TypeScript + Express + Prisma + PostgreSQL, built with a hexagonal (ports & adapters) architecture: thin routes, business logic in services, persistence behind repository ports, and a composition root that wires concrete adapters via dependency injection.
Architecture
routes (driving adapters) -> services (business logic) -> repository ports
| |
DTO views Prisma adapters (driven)
- Domain (
src/domain): plain entity/data contracts, no framework imports. - Ports (
src/repositories/I*.ts,src/services/ports): abstract contracts. - Services (
src/services): orchestration, depend only on ports. - Adapters (
src/repositories/Prisma*.ts,src/services/adapters): Prisma, JWT, argon2. - API (
src/routes,src/middleware): validation + delegation only. - Composition root (
src/container): the only place concretes are instantiated.
Endpoints
| Method | Path | Auth |
|---|---|---|
| POST | /api/users | — |
| POST | /api/users/login | — |
| GET | /api/user | required |
| PUT | /api/user | required |
| GET | /api/profiles/:username | optional |
| POST | /api/profiles/:username/follow | required |
| DELETE | /api/profiles/:username/follow | required |
| GET | /api/articles | optional |
| GET | /api/articles/feed | required |
| GET | /api/articles/:slug | optional |
| POST | /api/articles | required |
| PUT | /api/articles/:slug | author |
| DELETE | /api/articles/:slug | author |
| POST | /api/articles/:slug/favorite | required |
| DELETE | /api/articles/:slug/favorite | required |
| GET | /api/articles/:slug/comments | optional |
| POST | /api/articles/:slug/comments | required |
| DELETE | /api/articles/:slug/comments/:id | author |
| GET | /api/tags | — |
List responses (GET /api/articles, GET /api/articles/feed) omit the body field.
Errors follow the RealWorld envelope: {"errors": {"body": ["message"]}}.
Scripts
| Script | Purpose |
|---|---|
npm run build | Compile TypeScript to dist/ |
npm start | Run the compiled server |
npm test | Run the Jest suite |
npm run test:coverage | Run tests with coverage gate (80%) |
npm run lint | ESLint |
npm run prisma:migrate | Apply migrations |
npm run mutation | Stryker mutation testing |
Configuration
Copy .env.example to .env. Required: DATABASE_URL, JWT_SECRET. Optional: JWT_EXPIRY (default 7d), PORT (default 3000).