ERP System
Scattered spreadsheets became one production ERP across job orders, quotations, inventory, and sales.

How the project is put together
6 layers / 5 directed links
100%
- 01Interface
Role-aware ERP screens for jobs, inventory, quotations, sales, warranties, and administration.
Angular 21 / PrimeNG / Tailwind CSS / FullCalendar - 02Application
Typed frontend services and access guards coordinate module state and API boundaries.
Angular services / Guards / Interceptors / RxJS - 03Services/API
REST controllers, realtime events, uploads, validation, and quotation PDF generation.
Node.js / Express / Socket.IO / PDFKit - 04Data
Flexible business documents, inventory movements, users, products, and persistent uploaded files.
MongoDB 7 / Mongoose / Uploads volume - 05Auth/Permissions
Module/action-level access control across admin, manager, and staff workflows.
JWT / bcrypt / Roles / Granular permissions - 06Runtime
Containerized frontend, API, database, volumes, and deploy path for single-VPS operations.
Docker Compose / Nginx / GHCR / Dokploy
From broken workflow to operating system
Manual tracking across spreadsheets and disconnected documents.
A role-based production system with real-time dashboards, backups, and VPS deployment.
The workflow constraint
The client relied on scattered spreadsheets and manual workflows for job tracking, quotations, and inventory. They needed a unified system with real-time dashboards, access control, and automated workflows.
What changed
Decisions and trade-offs
MongoDB over SQL for this use case
ERP data (job orders, quotations, products) has variable schemas across clients and flexible document structures.
Decision: Chose MongoDB with Mongoose ODM for flexible schemas and fast iteration on changing business requirements.
Trade-off: Lost relational integrity guarantees, mitigated with application-level validation and Mongoose schema enforcement.
Socket.IO for real-time updates
Job order status changes need to reflect immediately across multiple users viewing the dashboard.
Decision: Added Socket.IO for real-time event broadcasting when job orders, quotations, or inventory items are modified.
Trade-off: Added WebSocket server complexity, but eliminated manual refresh patterns and improved team coordination.
Single VPS with Docker Compose over cloud-managed services
Client has a fixed budget and wants predictable costs without pay-per-use cloud pricing.
Decision: Dockerized everything (frontend, backend, database) on a single VPS with automated backup scripts and Cloudflare for SSL/CDN.
Trade-off: Manual infrastructure management vs managed cloud, but predictable $20-40/mo cost with full control.
Constraints, architecture, and proof
Angular 21 SPA served via Nginx (port 80) reverse-proxying to Node.js/Express API (port 5555), MongoDB with auth enabled. Docker Compose orchestrates all three services with persistent volumes for uploads and database. Cloudflare handles SSL termination, CDN, and DDoS protection.
Deployment, security, and maintenance
Helmet.js for HTTP security headers, bcrypt password hashing, JWT authentication with refresh tokens, express-rate-limit on all endpoints (strict on auth routes), CORS whitelist, input validation via express-validator, Winston structured logging, MongoDB authentication enabled.