721 lines
22 KiB
Markdown
721 lines
22 KiB
Markdown
# ERP Backend — Module & Data Flow Diagram
|
|
|
|
> **Stack:** Express · PostgreSQL · Prisma · JWT + RBAC
|
|
> **Base API:** `/api/v1`
|
|
> **Phase 1 modules:** Auth, Users, Roles, Masters (14), Vendors, Purchase Orders, GRN, Assets (+ AMC / Insurance / Service / Alerts / Depreciation), Settings
|
|
|
|
Reference: [BACKEND_TASKS.md](../BACKEND_TASKS.md) · [BACKEND_SETUP.md](../BACKEND_SETUP.md)
|
|
|
|
---
|
|
|
|
## 1. High-level system architecture
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
subgraph Client["Frontend / API Client"]
|
|
FE[React App / Postman]
|
|
end
|
|
|
|
subgraph Gateway["Express App (src/app.js)"]
|
|
HELMET[Helmet + CORS + HPP]
|
|
RATE[Rate Limiter /api]
|
|
REQID[Request ID]
|
|
ROUTES["/api/v1 Routes"]
|
|
SWAGGER[Swagger /api-docs]
|
|
ERR[Error Middleware]
|
|
end
|
|
|
|
subgraph Middleware["Per-route chain"]
|
|
AUTH[authenticate JWT]
|
|
RBAC[authorize module + action]
|
|
VAL[validate Joi schema]
|
|
CTRL[Controller]
|
|
end
|
|
|
|
subgraph Services["Business Layer"]
|
|
SVC["*.service.js"]
|
|
REPO["*.repository.js PO/GRN/Assets"]
|
|
end
|
|
|
|
subgraph Data["PostgreSQL"]
|
|
PRISMA[(Prisma ORM)]
|
|
VIEWS[(SQL Views v_asset_*)]
|
|
AUDIT[(audit_logs)]
|
|
end
|
|
|
|
FE --> HELMET --> RATE --> REQID --> ROUTES
|
|
ROUTES --> AUTH --> RBAC --> VAL --> CTRL --> SVC
|
|
SVC --> PRISMA
|
|
SVC --> REPO --> PRISMA
|
|
SVC --> AUDIT
|
|
SVC --> VIEWS
|
|
CTRL --> ERR
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Every API module map
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
subgraph System
|
|
HEALTH[/health /healthz]
|
|
DOCS[/api-docs]
|
|
end
|
|
|
|
subgraph Security
|
|
AUTH_MOD["/auth login|refresh|logout|me"]
|
|
USERS["/users CRUD + export"]
|
|
ROLES["/roles CRUD + permissions matrix"]
|
|
end
|
|
|
|
subgraph Masters["/masters/* (item categories shared with assets)"]
|
|
M1[uom]
|
|
M2[item-categories / subcategories / items]
|
|
M3[brands / gst-rates]
|
|
M4[payment-terms / delivery-terms]
|
|
M5[departments / designations]
|
|
M6[locations / plants / warehouses]
|
|
M7[document-series]
|
|
end
|
|
|
|
subgraph Procurement
|
|
VEND["/vendors + addresses|contacts|bank|items"]
|
|
PO["/purchase-orders workflow + PDF"]
|
|
GRN["/grn receipt + cancel + PDF"]
|
|
end
|
|
|
|
subgraph Assets["/assets"]
|
|
A_CORE[CRUD + transfer]
|
|
A_AMC[AMC contracts + renew]
|
|
A_SVC[service visits + status]
|
|
A_INS[insurance + renew]
|
|
A_DEPR[depreciation preview]
|
|
A_ALERT[expiry + service alerts]
|
|
end
|
|
|
|
subgraph Config
|
|
SET["/settings company + email SMTP"]
|
|
end
|
|
|
|
System --> Security --> Masters --> Procurement --> Assets --> Config
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Standard request data flow (all protected routes)
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant FE as Frontend
|
|
participant API as Express Route
|
|
participant AUTH as authenticate
|
|
participant RBAC as authorize
|
|
participant VAL as validate
|
|
participant SVC as Service
|
|
participant DB as PostgreSQL
|
|
participant AUD as audit_logs
|
|
|
|
FE->>API: HTTP + Bearer JWT
|
|
API->>AUTH: Verify token, load user + roles
|
|
AUTH->>RBAC: Check module permission (view/create/edit/delete/approve/export)
|
|
RBAC->>VAL: Joi validate body/query
|
|
VAL->>SVC: Business logic
|
|
SVC->>DB: Prisma read/write (deleted_at: null)
|
|
SVC->>AUD: auditLog on mutations
|
|
SVC-->>FE: ApiResponse { success, message, data, meta }
|
|
```
|
|
|
|
**RBAC modules:** `USERS`, `ROLES`, `MASTERS`, `VENDOR`, `PURCHASE_ORDER`, `GRN`, `ASSET`, `SETTINGS`, `AUDIT_LOGS`
|
|
|
|
### Audit logs (read-only)
|
|
|
|
| Endpoint | Purpose |
|
|
|---|---|
|
|
| `GET /audit-logs/filters` | Dropdown values: tables, actions, performers |
|
|
| `GET /audit-logs` | Filtered list — **returns empty until a filter is set** |
|
|
| `GET /audit-logs/:id` | Full row with `old_value` / `new_value` |
|
|
| `GET /audit-logs/export` | CSV of filtered rows |
|
|
|
|
Typical FE flow: load filters → user picks table + record (or date range) → list → click row for detail drawer.
|
|
|
|
---
|
|
|
|
## 4. Auth & session flow
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> Login: POST /auth/login
|
|
Login --> Active: Valid credentials
|
|
Login --> Locked: MAX_LOGIN_ATTEMPTS exceeded
|
|
Login --> RateLimited: Too many failed logins (IP)
|
|
Active --> TokenIssued: accessToken 15m + refreshToken
|
|
TokenIssued --> APIAccess: Bearer on /api/v1/*
|
|
APIAccess --> Refresh: access expired
|
|
Refresh --> TokenIssued: POST /auth/refresh (rotate hash in DB)
|
|
APIAccess --> Logout: POST /auth/logout (revoke refresh)
|
|
Locked --> Login: After LOCKOUT_DURATION_MINUTES
|
|
```
|
|
|
|
| Layer | Storage | Reset |
|
|
|---|---|---|
|
|
| Global API rate limit | In-memory per IP | Restart server or wait 15 min |
|
|
| Login rate limit | In-memory per IP | Restart or wait 15 min |
|
|
| Account lockout | `users.locked_until` | Wait 30 min or DB reset |
|
|
|
|
---
|
|
|
|
## 5. Master data dependency graph
|
|
|
|
Masters must exist **before** transactional modules use them.
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
DS[document_series] --> VCODE[vendor_code / po_number / grn_number / asset_code]
|
|
LOC[locations plants + warehouses] --> PO
|
|
LOC --> GRN
|
|
LOC --> ASSET
|
|
|
|
DEPT[departments] --> USERS
|
|
DEPT --> ASSET
|
|
DES[designations] --> USERS
|
|
|
|
UOM[uom] --> ITEMS
|
|
IC[item_categories] --> ISUB[item_subcategories] --> ITEMS
|
|
GST[gst_rates] --> ITEMS
|
|
BRANDS[brands] --> ITEMS
|
|
BRANDS --> PO
|
|
|
|
PT[payment_terms] --> VEND
|
|
PT --> PO
|
|
DT[delivery_terms] --> PO
|
|
|
|
ICAT[item_categories] --> ISUB[item_subcategories]
|
|
ISUB --> ITEMS[items]
|
|
ICAT --> ASSET
|
|
ICAT --> GRN_AUTO[GRN auto-asset creation]
|
|
ISUB --> ASSET
|
|
ISUB --> GRN_AUTO
|
|
|
|
ITEMS --> PO_ITEMS
|
|
ITEMS --> GRN_ITEMS
|
|
VEND --> PO
|
|
VEND --> GRN
|
|
VEND --> AMC
|
|
VEND --> SVC_VISIT
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Procurement → Asset end-to-end flow (core business chain)
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
START([Setup Masters + Vendor]) --> PO_CREATE
|
|
|
|
PO_CREATE["POST /purchase-orders<br/>status: DRAFT"] --> PO_EDIT["PUT /purchase-orders/:id<br/>add line items"]
|
|
PO_EDIT --> PO_SUBMIT["POST .../submit<br/>→ PENDING_APPROVAL"]
|
|
PO_SUBMIT --> PO_APPROVE{"Approve?"}
|
|
PO_APPROVE -->|Yes| PO_APPROVED["status: APPROVED"]
|
|
PO_APPROVE -->|No| PO_REJECTED["status: REJECTED → edit & resubmit"]
|
|
PO_REJECTED --> PO_EDIT
|
|
|
|
PO_APPROVED --> GRN_CREATE["POST /grn<br/>receive against PO lines"]
|
|
|
|
subgraph GRN_TXN["GRN Transaction (repository)"]
|
|
G1[Create grn POSTED]
|
|
G2[Create grn_items per line]
|
|
G3[Increment PO item received_qty]
|
|
G4{is_asset_item?}
|
|
G5[Auto-create assets 1 per accepted qty]
|
|
G6[Recalculate PO status]
|
|
G1 --> G2 --> G3 --> G4
|
|
G4 -->|Yes| G5 --> G6
|
|
G4 -->|No| G6
|
|
end
|
|
|
|
GRN_CREATE --> GRN_TXN
|
|
G6 --> PO_STATUS{Receipt status}
|
|
PO_STATUS -->|partial| PARTIAL[PARTIALLY_RECEIVED]
|
|
PO_STATUS -->|full| FULL[FULLY_RECEIVED]
|
|
|
|
G5 --> MANUAL_ASSET["POST /assets manual create also allowed"]
|
|
PARTIAL --> GRN_CREATE
|
|
FULL --> ASSET_OPS[Asset lifecycle ops]
|
|
|
|
GRN_CANCEL["POST /grn/:id/cancel"] --> REV1[Decrement received_qty]
|
|
REV1 --> REV2[Soft-delete linked assets]
|
|
REV2 --> REV3[GRN status CANCELLED]
|
|
```
|
|
|
|
### PO status lifecycle
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> DRAFT
|
|
DRAFT --> PENDING_APPROVAL: submit
|
|
REJECTED --> PENDING_APPROVAL: resubmit
|
|
PENDING_APPROVAL --> APPROVED: approve
|
|
PENDING_APPROVAL --> REJECTED: reject
|
|
APPROVED --> PARTIALLY_RECEIVED: GRN partial
|
|
APPROVED --> FULLY_RECEIVED: GRN full
|
|
PARTIALLY_RECEIVED --> FULLY_RECEIVED: more GRN
|
|
APPROVED --> CLOSED: amend closes old PO
|
|
DRAFT --> CANCELLED: cancel
|
|
APPROVED --> CANCELLED: cancel if no receipts
|
|
```
|
|
|
|
### GRN goods receiving concept flow
|
|
|
|
End-to-end warehouse receipt: PO-backed GRN posting, optional supporting documents, PO qty update, and asset auto-creation.
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
subgraph Physical["Physical receipt at warehouse"]
|
|
P1[Vendor delivery arrives]
|
|
P2[Verify PO / invoice / LR / vehicle]
|
|
P3[Inspect qty quality batch]
|
|
end
|
|
|
|
subgraph System["System — GRN posting"]
|
|
S1["GET open PO<br/>status APPROVED / PARTIALLY_RECEIVED"]
|
|
S2["POST /grn<br/>header + line items"]
|
|
S3["GRN txn: grn POSTED"]
|
|
S4["grn_items per accepted/rejected qty"]
|
|
S5["PO received_qty += accepted_qty"]
|
|
S6{Item is_asset_item?}
|
|
S7["Auto-create assets<br/>1 per accepted unit"]
|
|
S8["Recalculate PO status"]
|
|
end
|
|
|
|
subgraph Docs["Supporting documents (after or alongside GRN)"]
|
|
D1["POST /grn/:grnId/attachments<br/>multipart file"]
|
|
D2["grn_attachments row"]
|
|
D3["File stored under uploads/grn/{grnId}/"]
|
|
D4["GET .../download — authenticated"]
|
|
end
|
|
|
|
P1 --> P2 --> P3 --> S1 --> S2 --> S3 --> S4 --> S5 --> S6
|
|
S6 -->|Yes| S7 --> S8
|
|
S6 -->|No| S8
|
|
S3 --> D1 --> D2 --> D3
|
|
D3 --> D4
|
|
|
|
S8 --> OUT1{More qty pending?}
|
|
OUT1 -->|Yes| PARTIAL[PO PARTIALLY_RECEIVED]
|
|
OUT1 -->|No| FULL[PO FULLY_RECEIVED]
|
|
|
|
CANCEL["POST /grn/:id/cancel"] --> REV1[Reverse PO received_qty]
|
|
REV1 --> REV2[Soft-delete linked assets]
|
|
REV2 --> REV3[GRN CANCELLED — attachments remain on record]
|
|
```
|
|
|
|
| Step | Actor | API / table | Notes |
|
|
|------|-------|-------------|-------|
|
|
| 1 | Store / procurement | `POST /grn` | Requires APPROVED PO with pending qty |
|
|
| 2 | System | `grn`, `grn_items` | `accepted_qty + rejected_qty = current_qty` per line |
|
|
| 3 | System | `purchase_order_items.received_qty` | Incremented in same transaction |
|
|
| 4 | System | `assets` | Created when `items.is_asset_item = true` |
|
|
| 5 | Store user | `POST /grn/:grnId/attachments` | Invoice PDF, LR copy, photos (PDF/JPEG/PNG/WebP) |
|
|
| 6 | Any authorized user | `GET .../attachments/:id/download` | RBAC-protected download — not public `/uploads` |
|
|
| 7 | GRN detail | `GET /grn/:id` | Includes `attachments[]` metadata |
|
|
|
|
**Typical attachment types:** vendor tax invoice, LR/eway bill, packing list, QC rejection photos, delivery challan.
|
|
|
|
### GRN auto-asset creation (when `items.is_asset_item = true`)
|
|
|
|
| Field on Asset | Source |
|
|
|---|---|
|
|
| `asset_code` | `document_series` via `ASSET_{category.code}` |
|
|
| `asset_name` | Item name (+ `#N` if qty > 1) |
|
|
| `item_category_id` / `item_subcategory_id` | From item master (optional GRN line override) |
|
|
| `plant_id` | From PO |
|
|
| `warehouse_id`, `vendor_id`, `po_id`, `grn_id`, `grn_item_id` | From GRN |
|
|
| `purchase_date` | `grn.grn_date` |
|
|
| `purchase_cost` | `grn_items.rate` |
|
|
| `useful_life_years`, `depreciation_method` | From `item_categories` defaults |
|
|
| `condition` | `NEW` |
|
|
| `status` | `IN_USE` |
|
|
|
|
---
|
|
|
|
## 7. Asset module — full lifecycle
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
subgraph Create["Asset Creation Paths"]
|
|
P1[Manual POST /assets]
|
|
P2[Auto from GRN receipt]
|
|
end
|
|
|
|
subgraph Validate["normalizeAssetPayload validations"]
|
|
V1[item_category + subcategory match]
|
|
V2[plant / dept / warehouse / user refs]
|
|
V3[vendor / PO / GRN / grn_item refs]
|
|
V4[disposal_date required if DISPOSED/SCRAPPED]
|
|
V5[depreciation_rate required if method=OTHER]
|
|
V6[resolve rate from category defaults]
|
|
end
|
|
|
|
Create --> Validate --> SAVE[(assets table)]
|
|
SAVE --> CODE[asset_code from document_series]
|
|
|
|
SAVE --> READ["GET /assets/:id<br/>includes depreciation summary"]
|
|
|
|
SAVE --> TRANSFER["POST /assets/:id/transfer"]
|
|
TRANSFER --> TH[(asset_transfers)]
|
|
TRANSFER --> UPDATE_LOC[Update plant/dept/user/warehouse on asset]
|
|
|
|
SAVE --> UPDATE["PUT /assets/:id"]
|
|
SAVE --> DELETE["DELETE /assets/:id soft delete"]
|
|
|
|
UPDATE --> DISPOSE{status DISPOSED/SCRAPPED?}
|
|
DISPOSE -->|Yes| NEED_DATE[disposal_date required]
|
|
```
|
|
|
|
### Asset status & condition enums
|
|
|
|
| Field | Values |
|
|
|---|---|
|
|
| `status` | `IN_USE`, `IDLE`, `UNDER_MAINTENANCE`, `DISPOSED`, `SCRAPPED` |
|
|
| `condition` | `NEW`, `GOOD`, `FAIR`, `POOR` |
|
|
|
|
---
|
|
|
|
## 8. AMC contracts flow + renewal concept
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[(assets)] --> AMC_LIST["GET /assets/:id/amc"]
|
|
A --> AMC_CREATE["POST /assets/:id/amc"]
|
|
|
|
AMC_CREATE --> CHECK1{is_active=true?}
|
|
CHECK1 -->|Yes| DEACT[Deactivate other active AMC for same asset]
|
|
CHECK1 --> AMC_ROW[(asset_amc_contracts)]
|
|
DEACT --> AMC_ROW
|
|
|
|
AMC_ROW --> FIELDS["vendor_id, contract_type, start/end dates,<br/>renewal_date, annual_cost, visits_per_year, etc."]
|
|
|
|
AMC_ROW --> AMC_UPDATE["PUT /assets/:id/amc/:contractId"]
|
|
AMC_ROW --> AMC_RENEW["PATCH .../renew"]
|
|
|
|
subgraph RENEW_FLOW["Renewal Flow (AMC)"]
|
|
R1[Load existing contract]
|
|
R2[Set old contract is_active=false]
|
|
R3[Create NEW contract row with new dates]
|
|
R4[New contract is_active=true]
|
|
R5[auditLog action=RENEW]
|
|
R1 --> R2 --> R3 --> R4 --> R5
|
|
end
|
|
|
|
AMC_RENEW --> RENEW_FLOW
|
|
|
|
AMC_ROW --> SVC_LINK["Service visits can link amc_contract_id"]
|
|
```
|
|
|
|
**Key rule:** Only **one active AMC** per asset (`deactivateOtherActive`).
|
|
|
|
**Renewal ≠ update dates on same row** — renewal creates a **new contract record** and deactivates the old one (history preserved).
|
|
|
|
---
|
|
|
|
## 9. Insurance policies flow + renewal concept
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[(assets)] --> INS_LIST["GET /assets/:id/insurance"]
|
|
A --> INS_CREATE["POST /assets/:id/insurance"]
|
|
|
|
INS_CREATE --> CHECK{is_active=true?}
|
|
CHECK -->|Yes| DEACT[Deactivate other active policies]
|
|
CHECK --> POL[(asset_insurance_policies)]
|
|
DEACT --> POL
|
|
|
|
POL --> FIELDS["policy_no, insurer, sum_insured,<br/>annual_premium, start/end dates,<br/>renewal_date, is_auto_renewal, premium_paid"]
|
|
|
|
POL --> INS_UPDATE["PUT /assets/:id/insurance/:policyId"]
|
|
POL --> INS_RENEW["PATCH .../renew"]
|
|
|
|
subgraph RENEW_INS["Renewal Flow (Insurance)"]
|
|
I1[Deactivate old policy]
|
|
I2[Create new policy with new dates]
|
|
I3[premium_paid defaults false on renew]
|
|
I4[auditLog action=RENEW]
|
|
I1 --> I2 --> I3 --> I4
|
|
end
|
|
|
|
INS_RENEW --> RENEW_INS
|
|
```
|
|
|
|
Same pattern as AMC: **one active policy**, renewal = **new row + deactivate old**.
|
|
|
|
---
|
|
|
|
## 10. Service visits flow
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[(assets)] --> SV_LIST["GET /assets/:id/service-visits"]
|
|
A --> SV_CREATE["POST /assets/:id/service-visits"]
|
|
|
|
SV_CREATE --> VAL_SV["Validate amc_contract_id belongs to asset<br/>optional vendor_id ref"]
|
|
VAL_SV --> SV_ROW[(asset_service_visits)]
|
|
|
|
SV_ROW --> FIELDS["visit_type, visit_date, complaint details,<br/>engineer, work_done, parts_replaced,<br/>next_service_date, downtime_hours,<br/>service_cost, is_under_amc,<br/>asset_condition_after"]
|
|
|
|
SV_ROW --> SV_UPDATE["PUT .../service-visits/:visitId"]
|
|
SV_ROW --> SV_STATUS["PATCH .../status<br/>SCHEDULED|IN_PROGRESS|COMPLETED|etc."]
|
|
|
|
SV_ROW --> ALERT_VIEW["Feeds v_asset_next_service view"]
|
|
```
|
|
|
|
### Visit types
|
|
|
|
`PREVENTIVE`, `BREAKDOWN`, `INSPECTION`, `INSTALLATION`, `CALIBRATION`, `OTHER`
|
|
|
|
### Link to AMC
|
|
|
|
- `amc_contract_id` optional but validated against the asset
|
|
- `is_under_amc` flag for cost tracking
|
|
- `next_service_date` drives **service alerts**
|
|
|
|
---
|
|
|
|
## 11. Depreciation flow
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
subgraph Inputs
|
|
CAT[item_categories defaults]
|
|
FORM[User form fields]
|
|
end
|
|
|
|
CAT --> |default_useful_life_years<br/>default_depreciation_method| CREATE
|
|
FORM --> CREATE["POST /assets or PUT /assets/:id"]
|
|
FORM --> PREVIEW["POST /assets/depreciation/calculate"]
|
|
|
|
subgraph Methods["depreciation_method"]
|
|
SLM[SLM Straight Line]
|
|
WDV[WDV Written Down Value]
|
|
OTHER[OTHER manual rate required]
|
|
end
|
|
|
|
PREVIEW --> CALC[calculateDepreciation]
|
|
CREATE --> STORE[(assets: method, rate, cost, salvage, life, purchase_date)]
|
|
STORE --> READ["GET /assets/:id"]
|
|
READ --> CALC
|
|
|
|
CALC --> OUT["annual_depreciation<br/>accumulated_depreciation<br/>book_value<br/>years_elapsed<br/>resolved depreciation_rate"]
|
|
|
|
SLM --> CALC
|
|
WDV --> CALC
|
|
OTHER --> CALC
|
|
```
|
|
|
|
| Method | Rate auto-calc? | Formula concept |
|
|
|---|---|---|
|
|
| **SLM** | Yes (if rate omitted) | Equal yearly depreciation on original cost |
|
|
| **WDV** | Yes (if rate omitted) | Depreciation on reducing book value year-by-year |
|
|
| **OTHER** | No — user must send `depreciation_rate` | Custom % on cost |
|
|
|
|
**FE usage:**
|
|
|
|
- **Live preview** → `POST /assets/depreciation/calculate` (no save)
|
|
- **Saved asset view** → `GET /assets/:id` → `data.depreciation` object
|
|
- **Method dropdown** → `GET /assets/depreciation-methods`
|
|
|
|
---
|
|
|
|
## 12. Alerts flow (cross-asset dashboards)
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
subgraph Sources
|
|
AMC[(asset_amc_contracts end_date)]
|
|
INS[(asset_insurance_policies policy_end_date)]
|
|
WAR[(assets warranty_expiry_date)]
|
|
SVC[(asset_service_visits next_service_date)]
|
|
end
|
|
|
|
AMC --> V1[v_asset_expiry_alerts]
|
|
INS --> V1
|
|
WAR --> V1
|
|
SVC --> V2[v_asset_next_service]
|
|
|
|
V1 --> API1["GET /assets/alerts/expiry<br/>?days=30&type=AMC|INSURANCE|WARRANTY"]
|
|
V2 --> API2["GET /assets/alerts/service<br/>?status=OVERDUE|DUE_THIS_WEEK|..."]
|
|
|
|
V1 --> LEVELS["EXPIRED / CRITICAL / WARNING / INFO"]
|
|
V2 --> SSTAT["OVERDUE / DUE_THIS_WEEK / DUE_THIS_MONTH / UPCOMING"]
|
|
```
|
|
|
|
**Requires DB views:** run `scripts/patch-assets-amc-insurance.sql` + `scripts/patch-assets-views.sql`
|
|
|
|
---
|
|
|
|
## 13. Vendor module data flow
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
V[(vendors)] --> ADDR[vendor_addresses]
|
|
V --> CONT[vendor_contacts]
|
|
V --> BANK[vendor_bank_details AES encrypted]
|
|
V --> MAP[vendor_item_mapping]
|
|
|
|
V --> PO[purchase_orders]
|
|
V --> GRN[grn]
|
|
V --> AMC[asset_amc_contracts]
|
|
V --> SVC[asset_service_visits]
|
|
|
|
MAP --> ITEMS[items preferred vendor rates]
|
|
```
|
|
|
|
---
|
|
|
|
## 14. Users & roles permission flow
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
U[(users)] --> UR[user_roles]
|
|
UR --> R[(roles)]
|
|
R --> RP[role_permissions]
|
|
RP --> P[(permissions)]
|
|
P --> M[(modules)]
|
|
|
|
U --> PO_APPROVE[PO approve/reject]
|
|
U --> ASSET_OPS[Asset CRUD/transfer]
|
|
U --> AUDIT[performed_by in audit_logs]
|
|
|
|
LOGIN["GET /auth/me"] --> PERM[Returns user + flat permissions list for FE menu/RBAC]
|
|
```
|
|
|
|
---
|
|
|
|
## 15. Settings module
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
CO[(company singleton)] --> PDF[PO/GRN/Asset PDF headers]
|
|
EM[(email_settings SMTP encrypted)] --> MAIL[Future email notifications]
|
|
LOGO["POST /settings/company/logo"] --> UPLOADS[(uploads/)]
|
|
```
|
|
|
|
---
|
|
|
|
## 16. Cross-cutting concerns (every module)
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
M[Every mutation] --> AUDIT[auditLog table_name, record_id, action, old/new JSON]
|
|
M --> SOFT[Soft delete deleted_at = now]
|
|
M --> USER[created_by / updated_by from req.user.id]
|
|
M --> REQ[request_id from middleware]
|
|
|
|
DOC[Document numbers] --> SERIES[document_series atomic increment]
|
|
SERIES --> VC[vendor_code]
|
|
SERIES --> PO_NUM[po_number]
|
|
SERIES --> GRN_NUM[grn_number]
|
|
SERIES --> ASSET_CODE[asset_code per category prefix]
|
|
|
|
PII[mobile, bank accounts] --> ENC[AES-256-GCM + HMAC blind index]
|
|
```
|
|
|
|
---
|
|
|
|
## 17. Complete entity relationship (simplified)
|
|
|
|
```mermaid
|
|
erDiagram
|
|
vendors ||--o{ purchase_orders : supplies
|
|
vendors ||--o{ grn : delivers
|
|
vendors ||--o{ asset_amc_contracts : maintains
|
|
vendors ||--o{ asset_service_visits : services
|
|
|
|
purchase_orders ||--o{ purchase_order_items : contains
|
|
purchase_orders ||--o{ grn : received_via
|
|
purchase_orders ||--o{ assets : sourced_from
|
|
|
|
grn ||--o{ grn_items : lines
|
|
grn ||--o{ grn_attachments : documents
|
|
grn_items ||--o{ assets : auto_created
|
|
|
|
items ||--o{ purchase_order_items : ordered
|
|
items ||--o{ grn_items : received
|
|
|
|
item_categories ||--o{ item_subcategories : has
|
|
item_categories ||--o{ items : classifies
|
|
item_categories ||--o{ assets : classifies
|
|
item_subcategories ||--o{ items : sub_classifies
|
|
item_subcategories ||--o{ assets : sub_classifies
|
|
|
|
assets ||--o{ asset_amc_contracts : has
|
|
assets ||--o{ asset_insurance_policies : insured_by
|
|
assets ||--o{ asset_service_visits : serviced
|
|
assets ||--o{ asset_transfers : moved
|
|
assets ||--o{ asset_attachments : files
|
|
|
|
asset_amc_contracts ||--o{ asset_service_visits : covers
|
|
|
|
locations ||--o{ assets : plant_warehouse
|
|
departments ||--o{ assets : assigned_dept
|
|
users ||--o{ assets : assigned_user
|
|
|
|
users ||--o{ user_roles : has
|
|
roles ||--o{ role_permissions : grants
|
|
permissions }o--|| modules : belongs_to
|
|
```
|
|
|
|
---
|
|
|
|
## 18. Asset sub-module API quick reference
|
|
|
|
| Area | Endpoints | Notes |
|
|
|---|---|---|
|
|
| Core | `GET/POST /assets`, `GET/PUT/DELETE /assets/:id` | Includes computed `depreciation` on read |
|
|
| Transfer | `POST /assets/:id/transfer`, `GET .../transfer-history` | Blocked if DISPOSED/SCRAPPED |
|
|
| AMC | `GET/POST /assets/:id/amc`, `GET/PUT .../:contractId`, `PATCH .../renew` | One active contract |
|
|
| Service | `GET/POST /assets/:id/service-visits`, `PUT`, `PATCH .../status` | Links optional AMC |
|
|
| Insurance | `GET/POST /assets/:id/insurance`, `GET/PUT`, `PATCH .../renew` | One active policy |
|
|
| Depreciation | `GET /depreciation-methods`, `POST /depreciation/calculate` | Preview only |
|
|
| Alerts | `GET /alerts/expiry`, `GET /alerts/service` | SQL views |
|
|
|
|
---
|
|
|
|
## 19. Typical FE screen → API mapping
|
|
|
|
| Screen | APIs used |
|
|
|---|---|
|
|
| Login | `POST /auth/login`, `GET /auth/me` |
|
|
| Master setup | `/masters/*` CRUD |
|
|
| Vendor management | `/vendors/*` |
|
|
| Create PO | Masters dropdowns + `POST /purchase-orders` |
|
|
| Approve PO | `POST /purchase-orders/:id/approve` |
|
|
| GRN receipt | `POST /grn` (auto assets for asset items) |
|
|
| GRN attachments | `POST /grn/:grnId/attachments`, `GET .../download` |
|
|
| Asset list/detail | `GET /assets`, `GET /assets/:id` |
|
|
| Asset create/edit form | Masters + `POST /depreciation/calculate` (preview) + `POST/PUT /assets` |
|
|
| AMC tab | `/assets/:id/amc/*` + renew |
|
|
| Insurance tab | `/assets/:id/insurance/*` + renew |
|
|
| Service log | `/assets/:id/service-visits/*` |
|
|
| Dashboard alerts | `/assets/alerts/expiry`, `/assets/alerts/service` |
|
|
| Transfer asset | `POST /assets/:id/transfer` |
|
|
|
|
---
|
|
|
|
## 20. Renewal concept summary (for FE)
|
|
|
|
| Entity | What "Renew" does | Old record | New record |
|
|
|---|---|---|---|
|
|
| **AMC** | `PATCH /assets/:id/amc/:contractId/renew` | `is_active = false` | New row, `is_active = true`, new dates |
|
|
| **Insurance** | `PATCH /assets/:id/insurance/:policyId/renew` | `is_active = false` | New row, `is_active = true`, new policy period |
|
|
|
|
Both preserve **full history** — never overwrite the old contract/policy row.
|
|
|
|
---
|
|
|
|
## Viewing diagrams
|
|
|
|
- **GitHub** — renders Mermaid natively in markdown
|
|
- **VS Code** — install a Mermaid preview extension
|
|
- **Online** — paste into [mermaid.live](https://mermaid.live)
|