System Design & Architecture
How Namisite mERP is put together: the layers, the data it keeps, how stock moves when a job is produced or goods arrive, how people sign in, and how the app is deployed and scaled.
Laravel 13
PHP 8.3 MVC
MySQL 8
Single database
9 modules
One shared codebase
6 roles
Gate-based access
Contents
Overview
mERP is a cloud manufacturing ERP for Indian MSME plants. One Laravel application serves two faces from the same codebase and database:
Public site
merp.namisite.com
Landing page, one page per module, this guide, privacy, and the "Book a demo" form that saves a lead and emails the sales inbox.
Admin panel
merp.namisite.com/admin
Invitation-only workspace for plant staff: dashboard, production, BOMs, inventory, procurement, quality, leads, staff and settings.
Design goals
- Runs on ordinary cPanel hosting: no Node build, no Redis, no extra servers.
- Stock is always explained: every change writes a ledger row with a running balance.
- No passwords: email one-time codes for every sign-in.
- Business rules live in small services, not in screens, so they are tested once.
- Admins change company, email and production settings in the app, not in files.
- Mobile friendly from the start, so supervisors can work from the shop floor.
Architecture at a glance
A classic layered monolith. Each layer only talks to the one below it, which keeps the code easy to follow and change.
Clients
Web server
Laravel 13 application
Routing & middleware
web.php, auth, active, throttle, CSRF
Controllers
Landing, Auth (OTP), 10 admin controllers
Services & gates
ProductionService, PurchaseService, 8 abilities
Eloquent models
13 models, one per table
business data, sessions, cache, jobs
set in Admin → Settings
storage/ for logs and cache files
Technology stack
| Layer | Choice | Why |
|---|---|---|
| Language | PHP 8.3 | Available on every Indian shared and VPS host. |
| Framework | Laravel 13 | Routing, ORM, queues, mail, validation and tests in one package. |
| Database | MySQL 8 / MariaDB 10.6+ | Transactions and row locks for stock; cPanel standard. |
| UI | Blade, Tailwind CSS 4 (CDN), Alpine.js 3 | Server-rendered pages, no npm build step on the server. |
| Fonts | Poppins + Inter | Namisite brand typography. |
| Sign-in | Email one-time code (6 digits) | No passwords to forget, leak or reset. |
| Background work | Database queue + Laravel scheduler | Works with a single cron entry; no Redis needed. |
| Sessions & cache | Database driver | Shared across PHP workers without extra services. |
| Browser print (Print / Save as PDF) | Clean A4 purchase orders without a PDF library. | |
| Tests | PHPUnit 12 | Covers stock posting, shortages, receipts, roles and the demo form. |
Request lifecycle
What happens when a production supervisor presses Book output on a work order:
Step 1
Browser
POST /admin/work-orders/{id}/output with CSRF token
Step 2
Middleware
Session, CSRF, auth, active-user check
Step 3
Controller
Validates input, checks the manage-production gate
Step 4
Service
ProductionService posts stock in one DB transaction
Step 5
Response
Redirect back with a status message
If anything fails inside the transaction (for example, not enough material), nothing is saved and the user sees a clear message such as "Not enough material: RM-CRCA-1.2 (short 14 kg)".
Modules & code map
Each module is a controller, its models and a folder of views. Shared logic sits in services.
Production
Plan → release (material check) → start → book good and rejected output → complete.
Code · WorkOrderController · ProductionService
Tables · work_orders
Bills of materials
Components with scrap %, versions, cost per unit, requirement calculator.
Code · BomController
Tables · boms, bom_lines
Inventory
Item master, reorder levels, bin locations, adjustments and the stock ledger.
Code · ItemController
Tables · items, stock_movements
Procurement
Draft → sent → partial or full goods receipt. GST %, printable PO, "PO for low stock".
Code · PurchaseOrderController · SupplierController · PurchaseService
Tables · purchase_orders, purchase_order_lines, suppliers
Quality
Incoming (against PO), in-process and final (against work order) checks: pass, fail or hold.
Code · QualityInspectionController
Tables · quality_inspections
Dashboard
Open and overdue jobs, output this month, low stock, stock value, QC pass rate, new leads.
Code · DashboardController
Tables · reads all modules
Leads
Demo form on the public site; status, notes and CSV export in admin.
Code · LandingController · DemoRequestController
Tables · demo_requests
Access
Invite staff, set role, deactivate; email-code sign-in.
Code · OtpLoginController · UserController
Tables · users, login_otps
Settings
Company details, alert inbox, SMTP (encrypted), negative-stock switch, test email.
Code · SettingsController
Tables · settings
Core business flows
Stock only changes through Item::moveStock(). It locks the item row, updates the balance and writes a ledger row in one transaction, so two people booking at the same moment can never get the count wrong.
Production output
ProductionService::recordOutput- 1
Check. Work order must be released or in progress.
- 2
Explode BOM. Required = (good + rejected) × qty per unit × (1 + scrap %).
- 3
Shortage check. Block with a clear list, unless "allow negative stock" is on.
- 4
Issue. Each component: stock − required, ledger type "issue".
- 5
Receive. Finished item: stock + good units, ledger type "production".
- 6
Status. In progress, or completed once produced ≥ planned.
Goods receipt
PurchaseService::receive- 1
Check. PO must be sent or partly received.
- 2
Validate. Each line: cannot receive more than is pending.
- 3
Receive. Item stock + qty, ledger type "receipt" with PO number.
- 4
Update line. received_qty goes up.
- 5
Status. Partial while anything is pending, then received.
- 6
Inspect. Optional incoming quality inspection against the PO.
Document lifecycles
Security & sign-in
Email one-time code
- 1Staff enters their work email at /admin/login. Only emails added on Staff & Roles get a code; others see the same neutral message.
- 2A 6-digit code is generated, stored as a bcrypt hash in login_otps, and emailed. It is valid for 10 minutes and works once.
- 3Wrong codes are counted: 5 tries per code, 5 codes per email per hour, plus request throttling per IP.
- 4On success the session ID is regenerated and the user lands on the dashboard.
- 5Every admin request re-checks that the user is still active, so a deactivated person is signed out at once.
Built-in protections
- Served over HTTPS; session cookies are HTTP-only.
- CSRF token on every form.
- All input validated in controllers; Eloquent prevents SQL injection.
- Blade escapes output by default (XSS).
- Admin pages sent with noindex so search engines skip them.
- SMTP password stored encrypted with the app key.
- Rate limits on login and on the public demo form.
- Each stock change records who made it.
Roles & permissions
Everyone signed in can view every screen. The role decides what they can change. Rules are Laravel gates defined in one place, AppServiceProvider::ABILITIES, and checked in controllers and views.
| Can change | Admin | Plant manager | Production | Stores & purchase | Quality | Viewer |
|---|---|---|---|---|---|---|
| Work orders: create, release, book output | ||||||
| Bills of materials | ||||||
| Items, stock adjustments | ||||||
| Suppliers, purchase orders, goods receipt | ||||||
| Quality inspections | ||||||
| Demo requests (leads) | ||||||
| Staff & roles | ||||||
| Company, email and production settings |
Design decisions & roadmap
| Decision | Chosen | Trade-off |
|---|---|---|
| Monolith or microservices | One Laravel monolith | Simple to host and change; split later only if a module needs its own scale. |
| Stock model | Running balance on item + full ledger | Fast stock lookups and a full audit trail. Multi-warehouse is a future step. |
| Front end | Server-rendered Blade + Alpine | No build tools; less suited to offline use, which a future mobile app can cover. |
| Tenancy | One install per customer | Strong data separation; each plant gets its own database. |
| Sign-in | Email OTP only | No passwords; depends on reliable email, so SMTP is tested from Settings. |
Planned next
Glossary
- BOM
- Bill of materials: the components and quantities needed to make one finished item.
- Scrap %
- Extra material allowed for wastage when a BOM is exploded.
- Work order
- A shop-floor job to make a planned quantity of one item.
- GRN / receipt
- Goods received against a purchase order, added to stock.
- Stock ledger
- Every stock movement with its running balance.
- Reorder level
- Stock level at which an item shows as low and appears in "PO for low stock".
- HSN code
- Indian tax classification code for goods, used on POs.
- OTP
- One-time password: the 6-digit sign-in code sent by email.
Want a walkthrough with your IT team?
We'll go through the architecture, hosting and data migration for your plant.
Book a free 30-min demo