Sarkar Group — SMD Internal Management System
Sarkar Group SMD replaces fragmented spreadsheet workflows with a unified internal platform. It handles the full operational lifecycle: registering and assigning construction and marine equipment, managing multi-department projects with engineers and clients, processing financial requisitions and payments, handling HR applications across 8 types, publishing company media with rich text, and delivering real-time SSE notifications to all relevant users on every workflow action — all within a clean role-based access system.
// screenshots







// overview
vision
Replace disconnected manual processes with a single, permission-driven platform that every company role can use confidently — from the CEO approving requisitions to engineers submitting leave applications and uploading project site photos.
audience
Internal company staff across construction, marine, and engineering departments — admins, project managers, engineers, and clients — each with a purpose-built dashboard that surfaces exactly the data and actions relevant to their role.
outcome
A production-live system actively used for day-to-day company operations with 5 fully operational user roles, 15+ REST API modules, 20+ database models, real-time push notifications, and a Dockerized health-checked deployment on Vercel and MongoDB Atlas.
// problem
The company managed construction equipment, marine vessels, engineering projects, and a multi-department workforce through manual, disconnected processes. Core challenges included enforcing strict role-based permissions across every route and UI view without duplicating logic, tracking equipment across complex lifecycle states with a request/approval flow, running three parallel financial workflows (payments, requisitions, equipment requests) each needing submit → review → approve/reject cycles with notification feedback, supporting 8 distinct HR application types with document uploads and audit trails, delivering real-time notifications to relevant users without introducing WebSocket infrastructure complexity, and building a reusable query layer that supports search, filter, sort, paginate, and relation-include across 15+ modules without code duplication.
// solution
I designed and built the entire platform solo. The backend uses a structured Express Rocket server class (load → initiate → launch lifecycle) with JWT authentication, a role-array authGuard middleware on every protected route, and a generic chainable PrismaQueryBuilder that serves all 15+ modules — accepting any Prisma delegate and supporting .search() / .filter() / .sort() / .paginate() / .includeRelations() in a single reusable class. A singleton NotificationService maintains a Map<userId, Set<Response>> for all SSE connections, broadcasts to admin roles on workflow submissions, and sends targeted notifications to employees on approval or rejection, with 20-second keepalive pings and automatic connection cleanup. Role-specific dashboard endpoints use Prisma $transaction to run 10–15 parallel aggregation queries — KPI counts, month-over-month deltas, and recent records — in a single database round trip. The frontend uses Next.js 16 App Router with role-gated route groups, Redux Toolkit with redux-persist, MUI and TailwindCSS for UI, TipTap for rich media editing, and react-pdf for in-app document viewing.
// my_role
Fullstack Developer (Solo Project)
- › Designed the full MongoDB schema: 20+ Prisma models, enums, relations, and join tables (ProjectsEngineers, ProductsProjects)
- › Built generic PrismaQueryBuilder — chainable class with .search() / .filter() / .sort() / .paginate() / .includeRelations() reused across all 15+ modules
- › Implemented JWT auth system: sign/verify/decode/blacklist Token utilities, role-array authGuard middleware, SSE-compatible sseAuthGuard with query-param token support
- › Architected and implemented all 15+ API modules: users, admins, engineers, project managers, clients, projects, products, crews, payments, requisitions, applications, medias, project galleries, request products, notifications, dashboard
- › Built singleton NotificationService: SSE client registry (Map<userId, Set<Response>>), broadcast-to-roles, targeted send, 20s keepalive pings, and connection lifecycle cleanup
- › Designed role-specific dashboard aggregation using Prisma $transaction with 10–15 parallel queries and month-over-month delta calculations
- › Implemented equipment assignment validation chain: project status check → equipment STAND_BY check → join record creation; reused in request-product auto-approval flow
- › Built structured Rocket server class (load/initiate/launch) with CORS, cookie-parser, modular route registration, and global error handler
- › Set up Next.js App Router with role-gated route groups, Redux Toolkit + redux-persist state management, next-auth session handling
- › Built reusable frontend components: SMDDataTable, ProjectCard, DockUpload, ImageUploadField, PdfViewer, ViewFile, RichTextEditor (TipTap)
- › Configured Docker multi-stage build (deps → builder → runner) with dumb-init, non-root user, health check endpoint, and Docker Compose orchestration
// tech_stack
backend
TypeScript, Express.js, Prisma ORM, MongoDB, JWT (jsonwebtoken), Zod, Bcrypt, UUID, Nodemailer, EJS, Multer, Axios, cookie-parser, CORS
frontend
Next.js 16 (App Router), React 18, Redux Toolkit, redux-persist, next-auth, MUI v6, TailwindCSS, Lucide React, Sonner, react-hook-form, Zod
richContent
TipTap (heading, table, image, color, highlight, underline, text-align, font-family, placeholder), react-pdf, pdfjs-dist
fileStorage
Cloudinary (profile images, equipment photos, documents, media posts), Multer (upload middleware)
realtime
Server-Sent Events (SSE) via Express res.write(), singleton NotificationService with per-user client registry
infrastructure
Docker (multi-stage), Docker Compose, dumb-init, Vercel, MongoDB Atlas, devcontainer, Vitest
// key_features
- › 5 isolated role dashboards: SUPER_ADMIN, ADMIN, PROJECT_MANAGER, ENGINEER, CLIENT
- › Project lifecycle management with engineer assignment, equipment linking, and status tracking
- › Equipment registry with status tracking (WORKING / RUNNING / STAND_BY / BREAK_DOWN) and crew assignment
- › Equipment request workflow: employee requests → admin approve/reject → auto-assign on approval
- › Payment and requisition workflows with document upload, decline reason enforcement, and approval engine
- › 8 HR application types: leave, resignation, transfer, salary advance, loan, complaint, grievance, expense reimbursement
- › Real-time SSE notifications pushed to all relevant users on every workflow event
- › Rich media/blog system with TipTap editor, image upload, keyword tagging, and comment threads
- › Project gallery with site photo uploads and team commenting
- › Role-specific dashboards with KPI cards, month-over-month deltas, and parallel Prisma transaction aggregation
// contributions
- › Designed and implemented full Prisma MongoDB schema with 20+ models, complex relations, enum-driven status fields, and atomic $transaction blocks
- › Built PrismaQueryBuilder — generic chainable class eliminating query boilerplate across all 15+ modules with zero duplication
- › Implemented JWT auth with Token.sign / Token.verify / Token.decode / Token.blacklist; authGuard middleware accepting role arrays; sseAuthGuard for query-param token on SSE routes
- › Built NotificationService singleton: SSE client registry, broadcast-to-roles on submission events, targeted send on approval/rejection, keepalive pings, cleanup on close/finish/error
- › Designed role-specific dashboard endpoints: Prisma $transaction with parallel aggregation queries, employee count deltas, application/requisition/product change indicators
- › Implemented equipment assignment validation: project completion check → equipment STAND_BY check → create join record; called internally by request-product auto-approval
- › Built approval workflow engine shared across payments, requisitions, and applications: PENDING → APPROVED/REJECTED with decline reason enforcement and SSE notification dispatch
- › Set up Next.js role-gated routing: /(auth)/ for login/forgot-password, /(dashboard)/ with admin, project_manager, and engineer sub-routes
- › Implemented TipTap rich text editor integration with heading, table, image, color, highlight, underline, text-align, and font-family extensions
- › Configured Docker multi-stage build (deps → builder → runner), non-root user setup, dumb-init process management, and health check at /smd/api/v1/health
// challenges_&_solutions
Generic Query Layer Across 15+ Modules
Problem: Every module needed search, filter, sort, paginate, and relation-include. Duplicating this in each service would mean hundreds of lines of near-identical Prisma query code across 15+ services with no consistency.
Solution: Built a generic PrismaQueryBuilder<TModel, TWhereInput, TOrderByInput, TSelect, TInclude> class that accepts any Prisma delegate (findMany + count). All services instantiate it with their specific delegate and chain only the operations they need — .search(fields) / .filter(enumFields, additionalFilters) / .sort() / .paginate() / .includeRelations(include). One class, zero duplication across the entire API surface.
Real-time Notifications Without WebSocket Infrastructure
Problem: Employees needed instant feedback when admins acted on their payment, requisition, or application submissions. Adding WebSocket infrastructure (socket.io, separate WS server) would add significant deployment complexity and resource overhead.
Solution: Implemented SSE via Express res.write(). A singleton NotificationService holds a Map<userId, Set<Response>> for all active connections. On workflow events it creates a DB record and pushes the payload to matching connections. A setInterval sends keepalive comment frames every 20 seconds to prevent proxy timeouts. Connection cleanup runs on res close, finish, and error events automatically.
Equipment Assignment Validation Chain
Problem: Equipment can only be added to a project if the project is not Completed and the equipment status is STAND_BY. The request-product approval flow needed to auto-assign equipment on approval without bypassing these business rules or duplicating the validation logic.
Solution: All assignment operations are routed through ProjectService.addProduct which validates project status and equipment status before writing. When RequestProductsService.declineOrAccept sets status to APPROVED, it calls ProjectService.addProduct internally — reusing the exact same validation path. One source of truth, no bypass possible.
Role-Specific Dashboard Aggregation Performance
Problem: Each role's dashboard required 10–15 different data points: total counts, month-over-month deltas, recent records, and active project lists. Running these sequentially would create unacceptable latency for a page that loads on every login.
Solution: Each dashboard endpoint wraps all queries in a single Prisma $transaction array, running them in parallel. Admin dashboard executes 15 simultaneous queries — employee aggregates, application deltas, requisition deltas, product deltas, latest clients, active projects, and personal schedule — resolved in one round trip with destructured results.
// impact
15+ API Modules
Full coverage of every business domain: users, admins, engineers, project managers, clients, projects, products, crews, payments, requisitions, applications, medias, project galleries, request products, notifications, and dashboard — all with search, filter, sort, paginate, and relation queries.
5 User Roles — Full Isolation
Complete permission isolation across SUPER_ADMIN, ADMIN, PROJECT_MANAGER, ENGINEER, and CLIENT with role-gated API routes and purpose-built frontend dashboards. Each role only sees and acts on what they're authorized for.
Real-time SSE Push
Instant notification delivery to all relevant users on every workflow event — payment submitted, requisition approved, application rejected — with no polling and no missed updates.
Production Live
Dockerized with multi-stage build, health checks, and Docker Compose orchestration. Deployed to Vercel (frontend) and MongoDB Atlas (database), actively used for day-to-day company operations.
// what_i_learned
This project deepened my understanding of designing multi-role enterprise systems where access control must be consistent across both the API and UI layers. Building the generic PrismaQueryBuilder taught me the value of abstraction — one well-designed utility eliminated hundreds of lines of repetitive query code across 15+ modules. Implementing SSE from scratch gave me practical experience with HTTP streaming, connection lifecycle management, and the trade-offs versus WebSockets for one-directional push scenarios. Designing parallel dashboard aggregation with Prisma $transaction highlighted the importance of minimizing database round trips for data-heavy endpoints. The project also reinforced clean module architecture — thin controllers, service-layer business logic, route-level Zod validation — as the pattern that scales best when a codebase grows to 15+ interconnected modules with complex permission requirements.