A lightweight Projects + Tasks Management API, similar to a mini Jira / Trello.
- Node.js
- Express
- PostgreSQL
- Prisma ORM
- TypeScript
- Zod validation
- JWT authentication
- Pino logging
- Swagger / OpenAPI
- User signup and login
- JWT access tokens
- Refresh token rotation
- Password reset flow
- Organizations / workspaces
- Organization roles: Owner, Admin, Member
- Projects
- Tasks with status transitions
- Comments
- Tags
- Audit logs
- Invitation flow with expiration
- Background jobs
- Rate limiting
- Health endpoint
- Metrics endpoint
- Swagger docs
npm install
docker compose up -d
npx prisma migrate dev
npx prisma generate
npx tsx prisma/seed.ts
npm run devhttp://localhost:3000/api-docs
-
Start everything docker compose up -d npm run dev
-
Check curl http://localhost:3000/health curl http://localhost:3000/metrics
-
Open in browser curl http://localhost:3000/health curl http://localhost:3000/metrics
-
Sign up curl -X POST http://localhost:3000/api/v1/users/signup
-H "Content-Type: application/json"
-d '{"email":"test@example.com","password":"123456"}' -
Log in curl -X POST http://localhost:3000/api/v1/users/login
-H "Content-Type: application/json"
-d '{"email":"test@example.com","password":"123456"}' -
Copy the token and set it: export TOKEN="paste_access_token_here"
-
If login returns a refreshToken, save it too: export REFRESH_TOKEN="paste_refresh_token_here"
-
get your profile curl http://localhost:3000/api/v1/users/me
-H "Authorization: Bearer $TOKEN" -
Update your profile curl -X PATCH http://localhost:3000/api/v1/users/me
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name":"Ina"}' -
Create Organization curl -X POST http://localhost:3000/api/v1/orgs
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name":"My Org"}' -
Save the org id export ORG_ID="paste_org_id_here"
-
List organizations curl http://localhost:3000/api/v1/orgs
-H "Authorization: Bearer $TOKEN" -
Create project curl -X POST http://localhost:3000/api/v1/projects
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d "{ "name":"My Project", "organizationId":"$ORG_ID" }" -
Save the project id export PROJECT_ID="paste_project_id_here"
-
List projects with pagination curl "http://localhost:3000/api/v1/projects?organizationId=$ORG_ID&limit=10"
-H "Authorization: Bearer $TOKEN" -
Create task curl -X POST http://localhost:3000/api/v1/tasks
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d "{ "title":"My first task", "description":"Task from API", "projectId":"$PROJECT_ID" }" -
Save the task id: export TASK_ID="paste_task_id_here"
-
List tasks with filtering/sorting curl "http://localhost:3000/api/v1/tasks?projectId=$PROJECT_ID&status=TODO&sortBy=createdAt&order=desc"
-H "Authorization: Bearer $TOKEN" -
Update task status curl -X PATCH http://localhost:3000/api/v1/tasks/status
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d "{ "taskId":"$TASK_ID", "status":"DONE" }" -
Create comment curl -X POST http://localhost:3000/api/v1/comments
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d "{ "taskId":"$TASK_ID", "content":"This is my first comment" }" -
List comments curl "http://localhost:3000/api/v1/comments?taskId=$TASK_ID"
-H "Authorization: Bearer $TOKEN" -
Create tag curl -X POST http://localhost:3000/api/v1/tags
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"name":"backend"}' -
Save the tag id export TAG_ID="paste_tag_id_here"
-
List tags curl http://localhost:3000/api/v1/tags
-H "Authorization: Bearer $TOKEN" -
Attach tag to task curl -X POST http://localhost:3000/api/v1/tags/attach
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d "{ "taskId":"$TASK_ID", "tagId":"$TAG_ID" }" -
Detach tag from task curl -X POST http://localhost:3000/api/v1/tags/detach
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d "{ "taskId":"$TASK_ID", "tagId":"$TAG_ID" }" -
List audit logs curl "http://localhost:3000/api/v1/audit-logs?entity=Task"
-H "Authorization: Bearer $TOKEN" -
Refresh token curl -X POST http://localhost:3000/api/v1/auth/refresh
-H "Content-Type: application/json"
-d "{ "refreshToken":"$REFRESH_TOKEN" }" -
Logout curl -X POST http://localhost:3000/api/v1/auth/logout
-H "Content-Type: application/json"
-d "{ "refreshToken":"$REFRESH_TOKEN" }" -
Password reset request curl -X POST http://localhost:3000/api/v1/auth/password-reset/request
-H "Content-Type: application/json"
-d '{"email":"test@example.com"}' -
If returns the token in dev, save it: export RESET_TOKEN="paste_reset_token_here"
-
Password reset confirm curl -X POST http://localhost:3000/api/v1/auth/password-reset/confirm
-H "Content-Type: application/json"
-d "{ "token":"$RESET_TOKEN", "password":"newpassword123" }"
-
No token curl http://localhost:3000/api/v1/orgs
-
Invalid token curl http://localhost:3000/api/v1/orgs
-H "Authorization: Bearer badtoken" -
Validation failure curl -X POST http://localhost:3000/api/v1/users/signup
-H "Content-Type: application/json"
-d '{"email":"bad","password":"123"}'
.env DATABASE_URL=postgresql://postgres:postgres@localhost:5432/projecthub PORT=3000 JWT_SECRET=supersecretkey123 REDIS_URL=redis://localhost:6379