System Flow & Architecture
The complete developer guide to this Factory ERP: layers, modules, data model, business flows, state machines, algorithms and rules — everything a developer needs to understand, run and extend the system.
Contents
1 · System Overview & Design Principles
Factory ERP runs a complete small-factory operation — procurement, lot-based inventory, daily production, quality control, sales with invoicing, HR with payroll, analytics and an AI analyst — around one shared dataset. Six principles shape every part of the implementation:
One central store
All business data lives in a single in-memory store. Screens never keep their own copies of records — they read from the store and ask it to perform actions. There is exactly one source of truth, so every screen always agrees with every other screen.
Lots are the stock truth
Physical stock is stored as lots (batches). A product’s stock number is only a cached sum of its lots and is recomputed after every change: product.stock = Σ lot.qty. Costs, expiries and sources live on the lot, never averaged away.
Losses are first-class records
Nothing disappears silently. Supplier shortages, production shortfalls, quality rejections and write-offs are stored as money-valued loss records with date, product, quantity, unit cost, reference and note — so "profit after losses" is always computable.
Every stock change is a ledger entry
Receipts, deliveries, production output, manual adjustments and write-offs all append a signed movement (IN / OUT / ADJUST) with the running balance after it. The ledger can replay the full history of any product.
Derive, don’t store
Totals, payment statuses, alerts, statistics and KPIs are computed at read time by pure helper functions. The only stored snapshots are deliberate historical facts: receivedQty per order line, the COGS frozen on a sales order at delivery, and the cached stock sum.
Guarded transitions
Documents move through explicit status machines. Transitions validate preconditions (enough stock, correct current status, no double posting) and either succeed completely — including all side records — or change nothing.
2 · Architecture at a Glance
The system is a layered, single-page application. Data flows down as user intents and back up as derived view-data. The only server component is the AI gateway; everything else runs around the central store.
Screens Layer (Presentation)
Sixteen screens (tables, forms, popups, dashboards, print views). Screens are stateless views: they render derived data from the store and translate clicks into store actions. They never mutate records directly.
Central Store (Application State)
Owns the entire dataset in memory. Every change is one guarded, immutable state transition that also writes its side records (movements, losses, audit entries) and persists the result. On load it normalizes older saved data into the current shape.
Domain Logic (Pure Helpers)
Stateless functions: data in, value out, no side effects. This is where every business formula lives exactly once, so screens, reports and the AI snapshot can never disagree on a number.
Data Layer (Dataset & Persistence)
The dataset is one structured object of record collections (products, lots, orders, …). A first visit starts from a deep copy of the built-in demo factory dataset; afterwards the visitor’s own workspace is saved automatically after every change and restored on return.
Server AI Gateway (the only server component)
A small server endpoint that keeps the AI access key on the server. It receives a question plus a grounded snapshot of the data, automatically routes to the fastest responding AI engine (with silent failover), and streams the answer back token by token. Engine details never reach the screens.
What happens on every user action
1 · User acts
Clicks a button / submits a form
2 · Screen validates
Required fields, ranges, confirmations
3 · Store action
One guarded state transition
4 · Side records
Movements · losses · audit written together
5 · Persist
Workspace saved automatically
6 · Re-derive
All screens recompute & re-render
3 · Module Map — Every Feature
Sixteen functional modules share the central store. Each card lists what the module does and the features it owns.
Dashboard
The operational home screen.
- Headline KPI cards: revenue, gross profit, profit after losses, inventory value, receivables vs payables, payroll
- Alert banners for low stock, out-of-stock and expiry risks
- Business summaries and shortcuts into every module
Products & Category Tree
The product master catalogue.
- Rich product record: SKU, barcode, type (Raw Material / Finished Product), unit, cost & sale price, reorder level, max stock, main supplier, status and descriptive fields
- Unlimited-depth category tree with a visual manager; every product hangs on one tree node and filters match whole subtrees
- Search by name / SKU / barcode, tree + type + status filters, spreadsheet export
- Details popup: edit, print barcode labels, jump to stock & lots, delete (guarded)
Stock Management (Lots)
Where physical inventory lives.
- Per-product popup listing every lot: batch code, quantity, initial quantity, unit cost, expiry, received date, source and supplier
- Stock In creates a new lot; Stock Out consumes lots in FEFO order or from a chosen lot; write-off removes quantity and books a loss
- Lot editing with quantity clamped between 0 and its initial quantity; every change writes a ledger movement
- Live valuation (Σ qty × lot cost), weighted average cost, expiry classification: Expired / Expiring soon (≤ 30 days) / OK
Daily Production
Target vs actual output per day.
- Record per product & day: target quantity, produced quantity, unit cost, supervisor, reason for any gap
- Produced quantity becomes a production lot in stock automatically
- Shortfall (target − produced) is booked as a Production Shortage loss valued at unit cost
- Deleting a record reverses its lot, movement and loss; efficiency per product / supervisor feeds Reports
Quality Control
Lot-level inspection and defect management.
- Inspection queue: every new lot (supplier receipt, production batch, manual stock-in) starts as Pending until inspected
- Sampling inspections with a structured defect breakdown; failed units are written off the lot as a Quality Rejection loss at lot cost
- The 90% rule: below a 90% pass rate the lot is quarantined and FEFO delivery skips it until a re-inspection releases it
- Pass rates by supplier and product, defect Pareto, monthly inspection counts, and a fully reversible inspection register
Suppliers
Vendor master data and performance.
- Contact, address, payment terms, status and rating
- Computed statistics: order count, received value, fulfilment % (received ÷ ordered), shortage losses caused, outstanding payables
- Account statement popup with orders and payments; deletion blocked while referenced
Purchase Orders
Procure-to-stock documents.
- Lifecycle: Draft → Pending → Approved → Partially Received / Received (or Cancelled)
- Multi-line items (product, quantity, unit cost) with per-line receivedQty tracking
- Partial receiving: each receipt creates one lot per line; short-closing converts the missing quantity into a Supplier Shortage loss
- Payments against the received value; outstanding payable is always derived
Sales & Invoices
Order-to-cash documents.
- Lifecycle: Draft → Confirmed → Delivered (or Cancelled); salesperson assignment
- Delivery is stock-checked and atomic: lots are consumed FEFO and the real COGS is frozen on the order
- Printable invoice with 14% VAT; payments against the grand total; outstanding receivable is derived
Customers
Customer master data and balances.
- Contact details and customer type (Corporate / Retail / Government)
- Computed statistics: order count, delivered revenue, outstanding receivables, last order date
- Account statement popup; deletion blocked while referenced
Barcode Labels
Product identification labels.
- Every product carries a 12-digit code; the 13th EAN-13 check digit is computed with the standard algorithm
- Label sheet designer (copies, fields); one preview is rendered and the chosen number of copies is sent to print
Human Resources
People, attendance and payroll.
- Employee master: code (EMP-…), department, job title, salary, allowances, hire date, status
- Monthly attendance per employee: absent days, late count, overtime hours
- Payroll computed from attendance (see formulas); leave requests with Pending → Approved / Rejected decisions
Insights & Reports
Organized analytics.
- Five tabs — Overview, Sales, Procurement, Inventory, Losses & Production — each with its own KPI row, chart and detail table
- Key ratios: gross margin, margin after losses, losses as % of revenue, inventory turnover, net receivables position, payroll as % of revenue
- Period switch (this month / quarter / year / all) re-derives every figure; AI report generator with print / save / download
AI Assistant
A grounded analyst over live data.
- Chat answered only from a structured snapshot of the current dataset — figures are never invented
- Suggested questions, seven report templates (executive, inventory, sales, procurement, losses, HR, restocking), saved report library
- Replies stream in; the server gateway automatically uses the fastest responding engine and switches silently if one is slow to start
History & Audit
Full traceability.
- Stock movement ledger with type, reference and running balance per product
- Product & category audit trail: who-changed-what field diffs for creates, updates and deletes (kept to the most recent 800 entries)
System Flow (this page)
Living documentation.
- Architecture, data model, flows, state machines and formulas — generated from the same concepts the code implements, with live record counts below
Visitor Analytics
Who visited the system, from where, on what device, and what they did.
- A page-view beacon fires on every route change; the browser sends only the path and basic client hints (screen, language, timezone) plus the time spent on each page
- A server endpoint enriches each event with the IP address, country/region/city and parsed device, OS and browser — values the page script cannot fake — and ignores crawlers
- Every audited store action (create, update, delete, status change, goods receipt, delivery, production, inspection, data reset) is mirrored as an analytics action; AI chat and report usage are logged server-side
- Events persist in an external key-value store when configured (in-memory fallback otherwise); there is deliberately NO analytics screen inside the app — a private message alerts the owner the first time a new visitor arrives, and an hourly digest (sent only when there was activity) is delivered privately to the site owner messaging app, and the hosting dashboard provides owner-only traffic analytics
4 · Core Business Flows
The seven flows below are the heart of the system. Every arrow is a real implemented transition in the central store.
4.1 Procure-to-Stock (Suppliers → Purchase Orders → Lots)
Supplier
Master data, terms, rating
Purchase Order
Draft → Pending → Approved
Receive Goods
Full or partial, per line
Stock Lots
One lot per received line
Payable
Received value − paid
- An approved order can be received any number of times. For each line the receiver enters how many units arrived now (between 0 and the remaining quantity) and optionally an expiry date.
- Each received line creates a stock lot (batch code from the PO number, cost = line unit cost, source = Purchase Order) and an IN movement with the new running balance.
- Line receivedQty accumulates; the order becomes Received when every line is complete, otherwise Partially Received.
- If the buyer closes the order short, every missing unit is booked as a Supplier Shortage loss (missing qty × unit cost) — the loss that later reduces profit and scores the supplier.
- Payments are recorded against the received value (not the ordered value), so payables always match goods actually in the warehouse.
4.2 Order-to-Cash (Customers → Sales Orders → Invoice)
Customer
Master data & balance
Sales Order
Draft → Confirmed
Deliver
FEFO consumption, real COGS
Invoice
Subtotal + 14% VAT, printable
Receivable
Grand total − paid
- Delivery first checks every line against the product’s total lot quantity. If anything is short, the delivery is refused with the short lines listed — nothing is posted.
- Otherwise lots are consumed in FEFO order (earliest expiry first, then oldest receipt), decrementing lot quantities and writing OUT movements.
- The exact cost of the consumed units is summed and frozen on the order as its COGS — later purchase-price changes never rewrite history.
- The order becomes Delivered with a delivery date; its printable invoice shows lines, subtotal, 14% VAT and grand total; payments reduce the receivable (grand total − paid).
4.3 Daily Production (Target → Output Lot → Shortfall Loss)
Daily Target
Planned units per product
Actual Output
Produced units + supervisor
Production Lot
Output enters stock
Shortfall Loss
(target − produced) × unit cost
- A record captures date, product, target quantity (optional), produced quantity, unit cost, supervisor and — when there is a gap — the reason.
- Produced units become a production lot with an IN movement, immediately sellable.
- Any missing units against the target are booked as a Production Shortage loss carrying the reason, so Reports can rank loss causes and supervisor efficiency.
- Deleting the record reverses its lot quantity, its movement and its loss in one step.
4.4 Manual Stock Operations
- Stock In — creates a new lot (batch, cost, expiry, source such as a direct supplier receipt). When an expected quantity is given and less arrives, the difference is booked as a Supplier Shortage loss.
- Stock Out — consumes lots FEFO (or one specific lot chosen in the popup) and writes an OUT movement with a reason note.
- Write-off — removes damaged/expired quantity from a chosen lot and books a loss valued at that lot’s cost.
- Lot edit — corrects batch, cost, expiry or quantity (clamped to the lot’s initial quantity); quantity deltas post ADJUST movements.
- Every path ends with the same step: recompute the product’s cached stock from its lots.
4.5 HR: Attendance → Payroll, and Leave Decisions
Employees
Salary, allowances, department
Monthly Attendance
Absent days · lates · overtime
Payroll
Net = base + allowances + overtime − deductions
Leave Requests
Pending → Approved / Rejected
- Attendance is one record per employee per month; payroll for any month is derived on demand by the payroll formula (section 7) — no month-end “closing” step exists.
- Leave requests start as Pending (and badge the HR tab), then are approved or rejected; the decision is stored on the request.
- Headcount, department totals and payroll-as-%-of-revenue all derive from the same records in Reports.
4.6 AI Analyst: Snapshot → Gateway → Streamed Answer
Question / Report Type
From chat or report studio
Data Snapshot
Compact aggregates of live data
Server Gateway
Key server-side; picks fastest engine
Streamed Answer
Rendered live; print / save / download
- The screen builds a bounded snapshot: headline figures, per-module aggregates and capped top-N lists (top products, risks, restock needs) — enough to answer precisely without shipping the whole database.
- The snapshot is embedded in the instructions with strict grounding rules: use only these numbers, format money as EGP, admit when detail is missing, never discuss the technology behind the assistant.
- The gateway tries its engines in speed order: an engine that does not start answering within a short deadline (~10 seconds) is abandoned for the next one, silently; a final patient attempt guarantees an answer whenever any engine is alive.
- Tokens stream back and render progressively. Reports can be printed (PDF via the browser), downloaded as text, or saved into the report library.
4.7 Quality Gate: Inspect → Accept / Reject → Quarantine
New Lot
Receipt / production / stock-in → Pending
Inspection
Sample checked, defects broken down by type
Failed Units
Written off as Quality Rejection loss
Decision
Passed / Partially Passed released · Failed quarantined
- An inspector samples units from one lot and records how many were checked, how many failed, and a defect breakdown (type × quantity) that must add up to the failed count.
- Failed units are removed from the lot in the same transition: an OUT movement and a Quality Rejection loss valued at the lot's cost — so QC waste reduces profit-after-losses like every other loss.
- The lot's quality status follows the result: Passed (no defects), Partially Passed (pass rate at least 90%), or Quarantine (below 90%). Delivery and manual stock-out consume only non-quarantined lots, and the delivery guard reports how much is held.
- Re-inspecting a quarantined lot can release it; deleting an inspection reverses it completely (units back to the lot, loss and movement removed, previous status restored). Supplier and product pass rates across all inspections feed Suppliers, Reports and the AI analyst.
5 · Data Model (Entities & Relationships)
Eighteen record types. Order lines are embedded arrays inside their orders; everything else is a top-level collection keyed by string ids (prefixed, e.g. product, PO, SO, employee codes are human-readable). Money is stored as plain EGP numbers; dates as yyyy-mm-dd strings.
Supplier
PurchaseOrder
Product
StockLot
SalesOrder
Customer
| Entity | Purpose | Key Fields | Relationships |
|---|---|---|---|
| Category | Node of the product classification tree | id, name, parentId (null = root) | Parent → children (unlimited depth); 1 → many Products |
| Product | Catalogue item (raw material or finished product) | id, name, sku, barcode (12-digit base), type, categoryId, unit, costPrice, salePrice, stock (cached), reorderLevel, maxStock, supplierId (main), status | Belongs to Category & main Supplier; has many Lots, Movements, order lines |
| StockLot | One physical batch of a product | id, productId, batchCode, qty, initialQty, costPrice, expiryDate?, receivedDate, source, sourceRef, supplierId?, qualityStatus | Belongs to Product; created by PO receipt, production or manual stock-in |
| StockMovement | Ledger entry for every stock change | id, date, productId, type (IN / OUT / ADJUST), qty (signed), ref, note, balanceAfter | Belongs to Product; ref points to PO / SO / batch / adjustment |
| Supplier | Vendor master record | id, name, contactPerson, email, phone, address, paymentTerms, status, rating | Has many Purchase Orders; main supplier of many Products |
| PurchaseOrder | Buying document with lines | id, number (PO-…), supplierId, status, orderDate, expectedDate, receivedDate?, createdBy, notes, closedShort, paidAmount, items[] | Belongs to Supplier; items reference Products |
| PurchaseOrderItem | Embedded PO line | productId, qty, receivedQty, unitCost | Received quantity drives partial-receipt status and lot creation |
| Customer | Customer master record | id, name, contactPerson, email, phone, address, type | Has many Sales Orders |
| SalesOrder | Selling document with lines | id, number (SO-…), customerId, status, orderDate, deliveryDate?, salesperson, paidAmount, cogs (frozen at delivery), items[] | Belongs to Customer; items reference Products |
| SalesOrderItem | Embedded SO line | productId, qty, unitPrice | Delivery consumes the product’s lots FEFO |
| ProductionRecord | One day’s output of one product | id, date, productId, batchCode, targetQty, producedQty, unitCost, expiryDate?, supervisor, reason, notes | Creates one StockLot (+ a Loss when produced < target) |
| LossRecord | Money-valued loss of any kind | id, date, type, productId, qty, unitCost, value, ref, note | Belongs to Product; ref points to the PO / batch / lot that caused it |
| QualityInspection | Sample check of one stock lot with defect breakdown | id, number (QC-…), date, productId, lotId, batchCode, supplierId?, type, inspector, inspectedQty, passedQty, failedQty, passRate, result, prevQualityStatus, defects[], notes | Belongs to a StockLot; failed units create a LossRecord + OUT movement |
| Employee | Staff master record | id, code (EMP-…), name, department, jobTitle, email, phone, salary, allowances, hireDate, status | Has many AttendanceRecords and LeaveRequests; salespeople & supervisors are referenced by name |
| AttendanceRecord | One employee-month of attendance | employeeId, month (yyyy-mm), absentDays, lateCount, overtimeHours | Combined with salary by the payroll formula |
| LeaveRequest | Leave application to approve | employeeId, leave type, from, to, days, reason, status (Pending / Approved / Rejected) | Belongs to Employee; pending count badges the HR tab |
| AuditEntry | Field-level change log | timestamp, entity label, action (Created / Updated / Deleted), record id, details (human-readable diff) | Written automatically by create / update / delete on products & categories |
| AIReport | Saved generated report | id, title, type, content (formatted text), createdAt | Produced by the AI Assistant / Reports generator on demand |
6 · State Machines
Statuses are stored as plain strings on the records. Only the transitions drawn below are possible; each is guarded in the store (or by button availability plus a store-level check).
Purchase Order
Draft
Editable
Pending
Awaiting approval
Approved
Can be received
Partially Received
Some lines still open
Received
All lines complete / closed
Cancelled
No postings allowed
Sales Order
Draft
Editable
Confirmed
Ready to deliver
Delivered
Stock consumed, COGS frozen
Cancelled
No postings allowed
Leave Request
Pending
Awaiting decision
Approved
Rejected
Stock Lot Lifecycle (implicit — no status field)
Created
qty = initialQty
Active
0 < qty ≤ initialQty — available to FEFO
Depleted
qty = 0 — kept for traceability
Lot Quality Status
Pending
New lot — not inspected yet
Passed
Released for delivery
Partially Passed
Released; defects written off
Quarantine
Failed — delivery skips this lot
A quarantined lot returns to Passed / Partially Passed only through a new inspection. Deleting an inspection restores the status the lot had before it.
Payment status is never stored either: it is derived from paidAmount vs the amount due (SO: grand total incl. VAT; PO: received value) as Unpaid / Partial / Paid.
7 · Key Algorithms & Formulas
Every number in the system comes from one of these definitions, implemented once in the domain-logic layer.
| Concept | Definition |
|---|---|
| Product stock | Σ over its lots of lot.qty — cached on the product and recomputed after every mutation. |
| Inventory valuation (per product) | Σ lot.qty × lot.costPrice. Weighted average cost = valuation ÷ stock quantity. |
| FEFO consumption order | Sort lots by expiryDate ascending (lots without expiry last), then by receivedDate ascending; consume from the front. |
| Expiry classification | Expired when expiryDate is before today; Expiring Soon when within 30 days; OK afterwards; No Expiry when empty. |
| Order totals | Line value = qty × unit price/cost; sales grand total = subtotal × 1.14 (14% VAT) as printed on the invoice. |
| Received value (PO) | Σ receivedQty × unitCost — the payable basis; outstanding payable = received value − paidAmount. |
| Real COGS (per delivery) | Σ consumed lot quantity × that lot’s costPrice, computed during FEFO consumption and frozen on the sales order. |
| Profit chain | Gross profit = delivered revenue − real COGS. Profit after losses = gross profit − Σ loss.value. Margins are the same figures ÷ revenue. |
| Payment status (derived) | paidAmount = 0 → Unpaid; 0 < paidAmount < due → Partial; paidAmount ≥ due → Paid. (SO due = grand total incl. VAT; PO due = received value.) |
| Payroll (per employee-month) | daily = salary ÷ 30; hourly = daily ÷ 8; overtime pay = overtimeHours × hourly × 1.5; deductions = absentDays × daily + lateCount × hourly; net = salary + allowances + overtime pay − deductions. |
| Restock suggestion | For active products with stock ≤ reorderLevel: target = max(maxStock, 3 × reorderLevel); suggested order = target − stock; estimated cost uses weighted average lot cost; list sorted by urgency (stock ÷ reorderLevel). |
| Supplier fulfilment % | Σ receivedQty ÷ Σ ordered qty across the supplier’s non-cancelled orders; shortage losses are summed from the loss register by reference. |
| EAN-13 check digit | From the stored 12-digit base: multiply digits alternately by 1 and 3 from the right, sum, check = (10 − (sum mod 10)) mod 10. |
| Quality pass rate & quarantine rule | (inspectedQty − failedQty) ÷ inspectedQty. Result: 0 failed → Passed; at least 90% → Passed with Defects; below 90% → Failed and the lot is quarantined. Failed units are valued at lot cost as a Quality Rejection loss; supplier/product pass rates aggregate all inspections. |
8 · Business Rules & Invariants
Rules the store enforces regardless of which screen triggers the change — a developer adding a feature must preserve all of them.
Stock can never be oversold
Delivery validates every line against available lot quantity first; if any line is short, nothing is posted and the shortages are listed. The check-and-consume step is one atomic transition.
No double posting
A purchase order only receives against its remaining quantities and a delivered sales order cannot be delivered again; status guards make re-posting impossible.
Referential integrity
Products, suppliers and customers referenced by orders, lots or movements cannot be deleted. Deleting a production record reverses its lot, movement and loss instead of orphaning them.
Stock equals the sum of lots
The cached product stock is recomputed from lots after every single mutation — receipts, deliveries, adjustments, write-offs, lot edits and production reversals all pass through the same recomputation.
Lot quantity bounds
Manual lot editing clamps quantity to [0, initialQty], so history can be corrected but never inflated beyond what physically arrived; the delta is written as an ADJUST movement.
Quality gate on delivery
FEFO consumption skips quarantined lots everywhere (sales delivery and manual stock-out), so failed stock can never reach a customer unnoticed — and the delivery guard reports exactly how much is held in quarantine.
Losses are always valued & referenced
Every loss record carries quantity × unit cost = value and a reference to its cause (order, batch or lot), making loss analysis by type, product and cause exact.
Sequential document numbers
Purchase orders (PO-1001…), sales orders (SO-2001…), employee codes (EMP-001…) and product barcodes are generated from the current maximum, so numbers are unique and human-readable.
Automatic alerting thresholds
stock ≤ reorderLevel flags Low Stock; stock = 0 flags Out of Stock; lots expiring within 30 days or already expired raise expiry alerts on the dashboard, sidebar badge and reports.
Payments never overstate balances
Outstanding amounts are derived (due − paidAmount) at read time, so recording or editing a payment instantly corrects every balance, statement and KPI.
Auditability by construction
Stock changes flow into the movement ledger with running balances; product and category edits flow into the audit log as field-level diffs. No change path bypasses either log.
9 · Screens Inventory
Each screen, its address, its job, and the store actions it is allowed to call. Read-only screens only derive and display.
| Screen | Path | Purpose | Store Actions |
|---|---|---|---|
| Dashboard | / | KPIs, alerts, summaries | — (read-only) |
| Products | /products | Product master + category tree manager | upsert, remove |
| Stock Management | /inventory | Lots per product, stock in/out, write-offs | adjustStock, updateLot, writeOffLot |
| Daily Production | /production | Target vs actual production | addProduction, deleteProduction |
| Quality Control | /quality | Lot inspections, quarantine, defect analytics | recordInspection, deleteInspection |
| History & Audit | /history | Movement ledger + audit diffs | — (read-only) |
| Suppliers | /suppliers | Vendor master, stats, statements | upsert, remove |
| Purchase Orders | /purchase-orders | PO lifecycle, receiving, payments | upsert, setStatus, receivePO |
| Sales & Invoices | /sales | SO lifecycle, delivery, payments | upsert, setStatus, deliverSO |
| Customers | /customers | Customer master, stats, statements | upsert, remove |
| Invoice / PO Print | /invoices/… | Printable invoice (VAT) & PO document | — (read-only) |
| Barcode Labels | /labels/… | EAN-13 label sheets | — (read-only) |
| Human Resources | /hr | Employees, attendance, payroll, leaves | upsert, remove, setStatus |
| Insights & Reports | /reports | Tabular analytics + AI reports | upsert (saved reports) |
| AI Assistant | /ai | Chat + report studio + library | upsert (saved reports) |
| System Flow | /flow | This documentation | — (read-only) |
10 · How a Developer Extends This System
Three recipes cover almost any change. The golden rule: new behaviour goes in the store (transition) or the domain helpers (calculation) — screens only display and dispatch.
Add a new record type
- Define its shape and add sample records to the seed dataset.
- Give the load-time normalizer a default (collection: saved.collection || []) so older saved workspaces upgrade safely.
- Reuse upsert / remove / setStatus for plain CRUD, or add one dedicated guarded transition for anything with side effects.
- Build the screen (table + form + details popup), then register it in the sidebar navigation.
Add a new KPI or statistic
- Write it as a pure helper next to the existing formulas (input: dataset or records; output: number/object).
- Display it with the standard KPI card (big coloured title, value, sub-note) — pick the tone by meaning: green money-in, red losses/danger, amber waiting/risk, and so on.
- If the AI should know it, add it to the bounded snapshot builder so chat and reports share the same figure.
Add an order-like workflow
- Give the document a status field and draw its state machine first (section 6 style).
- Implement each transition as one store action that validates the current status, applies the change, and writes all side records (movements/losses/audit) in the same transition.
- Expose only the buttons valid for the current status; colour them distinctly, keep the rest inside the details popup.
Conventions used everywhere
- Immutable updates: actions build the next dataset instead of mutating records in place.
- One user intent = one transition = one persistence write + one notification.
- Ids come from a single generator with readable prefixes; document numbers from “next after current maximum”.
- Money is formatted through one formatter (EGP 12,500); dates are yyyy-mm-dd strings end to end.
- Buttons are colour-coded by meaning and adjacent buttons never share a colour; destructive actions live in details popups, not table rows.
- No decorative icons in the interface — colour and typography carry the meaning.
11 · Assumptions, Limitations & the Production Path
Current assumptions (demo mode)
- Single workspace per visitor/browser: data persists on the device and is not shared between users or devices.
- No login or roles — every visitor can do everything in their own workspace; “Reset demo data” restores the seed dataset.
- Single currency (EGP) and a fixed 14% VAT on sales invoices.
- The AI assistant needs its server-side access key configured; without it the assistant reports itself offline and the rest of the ERP is unaffected.
- Visitor Analytics events live outside the workspace dataset (a separate key-value store when configured; server memory otherwise), so analytics observe every visitor rather than a single browser.
Path to a production deployment
- Keep the screens and domain helpers exactly as they are — the store boundary is the seam.
- Re-implement the store actions behind authenticated server endpoints backed by a shared database (same transitions, same side records, same guards).
- Add users & roles at the endpoint layer (e.g. warehouse vs finance), plus server-side validation mirroring the store guards.
- Move document-number generation into database sequences to stay unique under concurrency.
Live Dataset Right Now
Record counts in your current workspace — proof that this page documents the very dataset you are looking at: