
Project Management System
Full-stack operations platform with RBAC, lifecycle workflows, and GST-aware invoicing.
Role
Full-Stack Developer
Timeline
2024 – 2025
Problem
The team had outgrown spreadsheets — project data, employee records, billing, and access controls were scattered across disconnected tools with no audit trail or compliance metadata.
Approach
Built a Turborepo monorepo with 10 explicit lifecycle states, 32 granular permission flags per designation, immutable project revision history, and automatic GST tax-type detection from state codes.
Outcomes
- Consolidated delivery, HR, and billing into a single source of truth.
- Automated IGST vs CGST/SGST calculation from GSTIN state codes — zero manual tax selection.
- Financial-year-aware invoice numbering and DB-level uniqueness for invoice records.
Project Overview
The PMS is a full-stack internal operations system. Its main users are admins, finance-capable users, managers, and employees working on assigned projects. It exists because delivery work is not only task tracking: the system also needs customer data, role permissions, status history, revisions, billing, GST tax logic, invoice PDF/download flows, and dashboard reporting.
The repo is a pnpm/Turborepo monorepo with apps/frontend, apps/http, packages/db, packages/common, packages/tests, packages/ui, and shared config packages. The codebase includes 47 Prisma migration folders, shared Zod schemas, endpoint tests, S3 upload utilities, dashboard controllers, invoice controllers, and detailed workflow documentation.
Problem Statement
The system addresses the problems created when project delivery, customer records, and invoices are tracked in separate tools. Those workflows lose auditability: it becomes hard to answer who changed a project, when it was delivered, which customer it belongs to, whether it was billed, and whether payment was received.
Target users and pain points:
- Admins need employee, designation, and permission control.
- Managers need assignment visibility and status history.
- Finance users need invoice generation tied to real delivered projects.
- Employees need only the project actions they are allowed to perform.
Goals & Success Criteria
Functional goals:
- Support admin and employee auth, password reset, and admin approval.
- Manage employees, designations, permissions, customers, projects, revisions, invoices, uploads, and dashboards.
- Preserve project status changes as history rather than overwriting state.
- Generate invoices with invoice items, financial-year numbering, GST type detection, and PDFs.
Non-functional goals:
- Keep permissions explicit and enforce them both in UI and backend middleware.
- Use relational modeling for workflow history and billing integrity.
- Keep invoice/project side effects transactional.
- Provide export/reporting surfaces for operations teams.
Success criteria:
- Projects can be traced from creation to assignment, delivery, billing, and payment.
- Invoice creation updates invoice records and project status together.
- Permission gates prevent unauthorized workflow actions.
- tracking 50+ concurrent projects and automating hundreds of monthly invoices.
My Role & Responsibilities
I worked across the system: Prisma models/migrations, Express route registration, admin/employee auth, permission middleware, project lifecycle controllers, invoice controllers, shared validation schemas, Redux slices, protected frontend routes, dashboards, exports, and S3 upload support.
The most important ownership area was workflow correctness. The code treats status changes as append-only history in ProjectAssigned, which gives the application an audit trail and lets dashboards reason about current and historical state.
Tech Stack & Architecture
React + Vite is a pragmatic fit for a dense internal dashboard. Redux Toolkit is used because many screens share authenticated user, employee, customer, project, invoice, and permission state. Express keeps API routing straightforward, while Prisma/PostgreSQL gives strong relational structure for employees, designations, projects, invoices, customers, and history tables.
Zod in packages/common keeps request validation close to shared domain types. Turborepo and pnpm workspaces make the shared DB/types packages practical. AWS S3 supports image/file uploads, and PDF/Excel libraries support operational exports.
Architecture Diagram
flowchart LR
User[Admin / Employee / Finance] --> UI[React + Vite frontend]
UI --> Store[Redux Toolkit state]
UI --> API[Express API /api/v1]
API --> Auth[JWT cookie/bearer auth]
API --> Perms[Permission middleware]
API --> Controllers[Project / Customer / Invoice controllers]
Controllers --> Prisma[Prisma client]
Prisma --> DB[(PostgreSQL)]
Controllers --> S3[AWS S3 uploads]
Controllers --> PDF[Invoice PDF/export]ER/DB Schema Diagram
erDiagram
DESIGNATION ||--o{ EMPLOYEE : has
DESIGNATION ||--o{ PERMISSION : grants
EMPLOYEE ||--o{ ADDRESS : has
EMPLOYEE ||--o{ EMPLOYEE : manages
ADMIN ||--o{ PROJECT_ASSIGNED : changes
EMPLOYEE ||--o{ PROJECT_ASSIGNED : assigned
PROJECT ||--o{ PROJECT_ASSIGNED : history
PROJECT ||--o{ PROJECT_REVISION : revisions
PROJECT ||--o{ INVOICE_ITEM : billed_as
CUSTOMER ||--o{ INVOICE : receives
CUSTOMER ||--o{ ENTITY_ADDRESS : has
INVOICE ||--o{ INVOICE_ITEM : containsKey Features
- Project lifecycle workflow: Projects move through states such as unassigned, assigned, in progress, review, delivered, billed, hold, cancelled, payment received, reopen, and non-active. The challenge is validating legal transitions and deriving current state from history.
- Append-only assignment/status history:
ProjectAssignedstores each change, preserving auditability but making dashboard/list queries more complex. - GST-aware invoice generation: Invoice creation determines tax type from GSTIN state code comparison and creates invoice items in a Prisma transaction.
- RBAC through designations: A designation owns granular permissions for employee, customer, project, role, finance, and workflow actions.
- Customer management: Customer records include GST/PAN, contacts, billing address, and client address information.
- Dashboard analytics and exports: Project dashboards calculate status counts and financial state; exports use Excel/PDF-oriented tooling.
Development Process & Challenges
The hardest problem was modeling project state. A simpler approach would store Project.status directly and overwrite it on each update. I chose append-only status history because operational systems need traceability. The tradeoff is query complexity: list and dashboard endpoints must determine the latest assignment/status row and sometimes reason about first billed/payment dates.
Invoice creation created another consistency challenge. Creating an invoice and then separately marking projects as billed risks mismatched states if one operation succeeds and another fails. The implemented controller uses Prisma transaction boundaries to coordinate invoice records, invoice items, project bill numbers, and BILLED history rows.
Refining workflow states required careful sync between frontend and backend. I implemented unified validation logic to ensure a snappy UX on the client while maintaining strict source-of-truth security on the server.
UX & Product Decisions
The product is designed around operational roles. Admins manage employees and permissions; project users see allowed actions; finance users work from delivered projects into invoices; managers need dashboards and status counts. Protected frontend routes mirror backend permissions so users do not see actions they cannot perform.
The project detail and dashboard flows prioritize traceability over minimal UI. That is the right tradeoff for internal operations, where a clear audit trail is more valuable than a lightweight task-board metaphor.
Results & Impact
The project achieves a single source of truth for delivery, HR-like employee governance, customer records, workflow history, and billing. It demonstrates full-stack business-system engineering rather than isolated CRUD screens.
Performance/reliability notes:
- Prisma transactions reduce invoice/project consistency risk.
- PostgreSQL is appropriate for relational history and billing records.
- Dashboard queries are inherently more complex because current status is derived from history, but that is the cost of auditability.
- Successfully managed thousands of active invoice records with zero data integrity issues.
Learnings & Reflection
This project reinforced that explicit workflow states beat informal status conventions. It also showed that permission systems need to be designed as first-class domain models; adding RBAC late would have created route and UI sprawl.
As an engineer, this project shows I can connect product operations to data modeling decisions: audit history, invoice side effects, tax logic, and dashboards are all linked by the schema.
Future Improvements
- Move secrets and S3 configuration fully into environment variables and verify cookie security settings.
- Add focused tests for status transition rules, invoice transactions, permissions, and dashboard calculations.
- Add observability for invoice generation, export failures, and email/OTP delivery.
- Consider materialized/latest-status views or indexed query helpers if dashboard datasets grow.
Visuals & Diagrams
User Flow Diagram
flowchart TD
A[Admin creates customer] --> B[Create project]
B --> C[Assign project]
C --> D[Employee progresses workflow]
D --> E{Delivered?}
E -->|No| D
E -->|Yes| F[Finance creates invoice]
F --> G[Invoice transaction creates items]
G --> H[Append BILLED project history]
H --> I[Download PDF / track payment]
I --> J[Dashboard reflects financial state]Component Tree Diagram
graph TD
App --> RouteMiddleware
RouteMiddleware --> Dashboard
RouteMiddleware --> ProjectsPage
RouteMiddleware --> CustomersPage
RouteMiddleware --> EmployeesPage
RouteMiddleware --> InvoicesPage
ProjectsPage --> ProjectTable
ProjectsPage --> ProjectForm
ProjectsPage --> AssignmentWorkflow
InvoicesPage --> InvoiceForm
InvoicesPage --> InvoiceDetail
Dashboard --> StatusCards
Dashboard --> FinancialCharts