IssueFlow is a NestJS/TypeScript backend for a lightweight project and issue tracking system. It exposes REST APIs for users, projects, tickets, comments, audit logs, dependencies, attachments, CSV import/export, soft delete/restore, mentions, workload reporting, auto-assignment, and overdue escalation.
- NestJS 10
- TypeScript
- PostgreSQL
- TypeORM
- Docker Compose for local PostgreSQL
- Jest and Supertest for tests
- JWT-protected API endpoints with
POST /auth/loginandPOST /auth/logout. - Users with roles
ADMINandDEVELOPER. - Projects with soft delete and admin restore.
- Project developer membership via
POST /projects/:projectId/members. - Tickets with lifecycle enforcement:
TODO -> IN_PROGRESS -> IN_REVIEW -> DONE. - Optimistic concurrency on ticket and comment updates through a required
versionfield. - Dependency/blocker rules: dependencies must stay inside one project, and tickets cannot move to
DONEwhile blockers are unresolved. - Comments with persisted known
@usernamementions. Unknown handles do not block comment creation. - Mentions lookup newest-first via
GET /users/:userId/mentions. - Attachments with 10 MB max size and MIME allowlist:
image/png,image/jpeg,application/pdf,text/plain. - CSV ticket import/export.
- Audit logs for state-changing actions.
- Auto-assignment to the least-loaded project developer, with ties broken by oldest user registration.
- Auto-escalation of overdue tickets with persisted
is_overdueandauto_escalation_countstate.
All API endpoints are protected by a global JWT guard except:
GET /POST /auth/login
On startup, the app creates a default admin if one does not already exist:
username: admin
password: admin
Login:
curl -X POST http://localhost:3000/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin"}'Use the returned token:
curl http://localhost:3000/users \
-H "Authorization: Bearer <accessToken>"PATCH /tickets/:ticketIdrequires the currentversion.PATCH /tickets/:ticketId/comments/:commentIdrequires the currentversion.- Restore endpoints use the authenticated JWT user as the actor; the user must be
ADMIN. - Explicit ticket assignees must be developer members of the ticket project.
- If a ticket is created without
assigneeId, the app assigns it to the least-loaded developer in that project. If the project has no developer members, the ticket remains unassigned. - Manual priority changes reset auto-escalation state.
See run.md for exact setup, build, run, and test commands.
Quick start:
npm install
docker compose up -d db
npm run startnpm run lint
npm test -- --runInBand
npm run build
npm run test:e2eThe unit suite covers the main business rules. The e2e suite boots the full Nest app against PostgreSQL, verifies the JWT guard, and runs an authenticated workflow through HTTP: login, create developer, create project, add project member, create auto-assigned ticket, move the ticket forward, and reject an illegal backward transition.
The repository also includes a GitHub Actions workflow at .github/workflows/ci.yml that starts PostgreSQL and runs lint, unit tests, build, and e2e tests.
The code is split into focused Nest services by domain:
AuthServicehandles login, JWT validation, logout, and token revocation.UsersServicehandles users, default admin creation, password hashing, and admin checks.ProjectsServicehandles projects, project membership, workload, and assignee eligibility.TicketsServicehandles tickets, lifecycle rules, dependency rules, CSV import/export, assignment, and escalation.CommentsServicehandles comments and mentions.AttachmentsServicehandles upload validation and attachment persistence.AuditServicecentralizes audit log writes and reads.IssueflowServiceis now a thin facade kept for controller compatibility; business logic lives in the domain services above.
For a production version, I would also replace TypeORM synchronize: true with migrations, move the escalation loop to a dedicated worker or queue, and split these services into separate Nest modules once the project grows.