Last Updated: January 25, 2026
Purpose: Simple REST API for task management (learning project)
| Component | Technology |
|---|---|
| Runtime | Node.js 20+ |
| Language | TypeScript |
| Framework | Express.js |
| Database | PostgreSQL |
| ORM | Prisma |
| Testing | Vitest |
| Validation | Zod |
Critical Rule: All commands must pass before committing.
| Command | Purpose | Expected |
|---|---|---|
npm test |
Tests | All tests pass |
npm run type-check |
Type Check | No TypeScript errors |
npm run lint |
Lint | No ESLint errors |
// All routes in src/routes/*.ts
app.get('/api/tasks', async (req, res) => {
const tasks = await prisma.task.findMany();
res.json(tasks);
});Why: Consistent REST pattern, easy to test
// Using Zod for all request validation
const createTaskSchema = z.object({
title: z.string().min(1).max(100),
completed: z.boolean().optional()
});
const body = createTaskSchema.parse(req.body);Why: Type-safe validation, clear error messages
// Global error middleware in src/middleware/errors.ts
app.use((err, req, res, next) => {
if (err instanceof ZodError) {
return res.status(400).json({ error: err.errors });
}
res.status(500).json({ error: 'Internal server error' });
});Why: Consistent error responses, proper status codes
Rules that must NEVER be violated:
-
All API endpoints require validation
- What: Every POST/PUT/PATCH must use Zod schema
- Why: Prevents invalid data from reaching database
- Example:
const data = schema.parse(req.body)
-
Tests before commits
- What: Run
npm testbefore every git commit - Why: Prevents breaking changes from being pushed
- Example: Use git hooks or manual check
- What: Run
-
Database migrations are versioned
- What: Never edit existing migration files
- Why: Breaks production databases
- Example: Create new migration with
prisma migrate dev
-
Prisma Client not updated
- Problem: Schema changes don't reflect in code
- Solution: Run
npx prisma generateafter changing schema.prisma
-
Environment variables missing
- Problem: App crashes on startup
- Solution: Copy
.env.exampleto.envand fill in DATABASE_URL
-
Port already in use
- Problem: "EADDRINUSE: address already in use"
- Solution: Kill process on port 3000:
lsof -ti:3000 | xargs kill
npm install
cp .env.example .env
# Edit .env with your DATABASE_URL
npx prisma migrate dev
npm run devnpm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # With coveragenpm run dev # Start with hot reload
npm run build # TypeScript compile
npm start # Run production buildtask-api/
├── src/
│ ├── routes/ # API endpoints
│ ├── middleware/ # Express middleware
│ ├── lib/ # Database, utilities
│ └── index.ts # App entry point
├── prisma/
│ └── schema.prisma # Database schema
└── test/ # Vitest tests
Key directories:
src/routes/- One file per resource (tasks.ts, users.ts)src/middleware/- Reusable middleware (auth, errors, logging)prisma/- Database schema and migrations
Decision: Use Prisma ORM for database access
Rationale: Type safety, migrations, easier testing
Trade-offs:
- ✅ Auto-generated types from schema
- ✅ Query builder prevents SQL injection
⚠️ Learning curve for ORM patterns⚠️ Slightly slower than hand-optimized SQL
Decision: Use Zod for all request validation
Rationale: TypeScript-first, composable schemas
Trade-offs:
- ✅ Infers TypeScript types automatically
- ✅ Great error messages
⚠️ Adds bundle size
For new features or breaking changes:
- Create feature branch
- Write tests first (TDD)
- Implement feature
- Run full validation suite
- Create PR, get review
- Merge and deploy
Skip formal process for: Typos, config tweaks, dependency patches
# Reset database (WARNING: destroys data)
npx prisma migrate reset
# Open Prisma Studio (database GUI)
npx prisma studio
# Run single test file
npm test -- tasks.test.ts- Prisma Docs: https://www.prisma.io/docs
- Zod Docs: https://zod.dev
- Express Docs: https://expressjs.com
This file is the single source of truth for AI assistants working on this project. Keep it updated and concise.