system://hasnat.dev/projects/sarkar-group-smd
← back to home
project_overview

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.

Role: Fullstack Developer (Solo Project) Scope: Full-Stack Internal Management Platform Focus: RBAC + Approval Workflows + Real-time SSE + Generic Query Layer
TypeScript Express Prisma MongoDB Next.js Redux Toolkit MUI TailwindCSS SSE Docker

// screenshots

Admin Dashboard Overview
Admin Dashboard Overview
Engineer Dashboard Overview
Engineer Dashboard Overview
Project Manager Dashboard Overview
Project Manager Dashboard Overview
All Projects
All Projects
All Employees
All Employees
All Media View
All Media View
View Employee Details
View Employee Details

// 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.