Account: ERP-AI-Chatbot
Enter 6-digit code from Google Authenticator
Refresh:

IRIS Ecosystem

v1.0 · 2026-07-30

**IRIS** — *Intec Responsive Information System* — is INTEC Engineering's internal software family. It is a manufacturing ERP (`intec-erp-v2`) that owns the database and all business logic, paired with a natural-language chatbot backend (`intec-erp-chatbot`, internally called "IRIS") that reads the same database and answers questions in English or Bahasa Malaysia using a hybrid regex + local LLM (Ollama `qwen3:30b`) intent engine. Three near-identical client apps — web, Android mobile, and Windows desktop — talk to the chatbot over HTTP so shop-floor and office workers can query work orders, inventory, invoices, BOMs, production, and more conversationally. The ERP is the senior project and the sole schema owner; the chatbot and its clients depend on it, never the other way around.

Audience: a developer who just joined the team and needs to understand the whole family in 10 minutes. This page synthesizes the per-project .cursor/guide/ docs; for any fact beyond what is here, trust those guides — they are the authoritative source this overview synthesizes.

Architecture at a glance

Client Applications (HTTP)
Chatbot Web
React 19 · :3001
Chatbot Mobile
Expo / RN (APK)
Chatbot Desktop
Tauri + React 18
POST /api/v1/chatbot/* · client: web | mobile | desktop
Backends
IRIS Chatbot API · intec-erp-chatbot :8001
Laravel 8 / PHP 8 · hybrid regex + Ollama intent engine
 
Ollama LLM
:11434 · qwen3:30b
read business data via symlinked Eloquent models · shared MySQL, NOT HTTP · writes only chatbot_query_logs
Shared Data Layer & ERP
MySQL · intec_erp
single shared schema
ERP API + Web · intec-erp-v2 :8000
Laravel 5.8 · owns schema · full read/write · 282 models

Key invariants: the ERP is the sole schema owner (never migrate from the chatbot); the chatbot never duplicates ERP business logic — it reuses the same Eloquent models via the symlink; the chatbot inherits ERP's model boot logic, global scopes, and observers; the ERP does not call the chatbot — if the chatbot is down, the ERP keeps running.

Projects

intec-erp-v2
ERP / System of record
The ERP system of record. Owns the MySQL schema, all writes, all business logic, all migrations. 282 Eloquent models.
Tech
PHP 7.1+, Laravel 5.8, Vue 2, Blade, MySQL, Cartalyst Sentinel, InfyOm generator
Port
8000
Path
intec-erp-v2/.cursor/guide/
Deep-dive docs (26)
.cursor/guide/BOM_SYSTEM_DOCUMENTATION.md
.cursor/guide/CALENDAR_CACHE_CHAIN_REACTION_GUIDE.md
.cursor/guide/CALENDAR_DETAIL_CACHES_DOCUMENTATION.md
.cursor/guide/CHATBOT_EXTRACTION_STATUS.md
.cursor/guide/DEPLOYMENT_2026-04-21.md
.cursor/guide/DOMAIN_MODEL_GUIDE.md
.cursor/guide/EINVOICE_EXCHANGE_RATE_GUIDE.md
.cursor/guide/EINVOICE_SYSTEM_DOCUMENTATION.md
.cursor/guide/ERP_ARCHITECTURE_OVERVIEW.md
.cursor/guide/GLOBAL_UI_DESIGN_SYSTEM.md
.cursor/guide/INVOICE_CANCELLATION_VERIFICATION_GUIDE.md
.cursor/guide/IRIS_ECOSYSTEM_CONTEXT.md
.cursor/guide/MODULE_AUDIT_LOG_GUIDE.md
.cursor/guide/PERMISSION_SYSTEM_GUIDE.md
.cursor/guide/PROGRESS_UPDATE_BY_ACTUAL_FG_GUIDE.md
.cursor/guide/README.md
.cursor/guide/RECEIVED_EINVOICE_WORKFLOW.md
.cursor/guide/SENT_EINVOICE_WORKFLOW.md
.cursor/guide/TERMINAL_API_GUIDE.md
.cursor/guide/TOOL_DEVELOPMENT_GUIDE.md
.cursor/guide/WORK_HISTORY_GUIDE.md
.cursor/guide/WORK_ORDER_EDIT_PROGRESS_DOCUMENTATION.md
.cursor/guide/WORK_ORDER_MAINTENANCE_USER_GUIDE.md
.cursor/guide/WORK_ORDER_SYSTEM_DOCUMENTATION.md
.cursor/guide/WO_INDEX_PERFORMANCE_GUIDE.md
.cursor/guide/WO_POSITION_BUG_INVESTIGATION.md
intec-erp-chatbot
IRIS API / this project
The "IRIS" chatbot API. Reads the same MySQL DB via symlinked models (not HTTP). Hybrid regex + Ollama intent engine, ~162 intents, 14 data handlers + 14 formatters.
Tech
PHP 8, Laravel 8.75, Sanctum, Ollama (qwen3:30b)
Port
8001
Path
intec-erp-chatbot/.cursor/guide/
Deep-dive docs (9)
.cursor/guide/API_REFERENCE_GUIDE.md
.cursor/guide/CHATBOT_SYSTEM_DOCUMENTATION.md
.cursor/guide/CLIENT_INTEGRATION_GUIDE.md
.cursor/guide/ERP_INTEGRATION_GUIDE.md
.cursor/guide/INTENT_AUDIT.md
.cursor/guide/INTENT_AUTOMATION_GUIDE.md
.cursor/guide/INTENT_SYSTEM_GUIDE.md
.cursor/guide/README.md
.cursor/guide/_diagrams_reference.md
erp-ai-chatbot-web
Client / web
React 19 CRA web chat client. Renders markdown, mermaid, charts, image galleries.
Tech
React 19, react-scripts 5.0.1, axios, react-markdown, mermaid, recharts
Port
3001
Path
erp-ai-chatbot-web/.cursor/guide/
Deep-dive docs (6)
.cursor/guide/API_CLIENT_GUIDE.md
.cursor/guide/IRIS_ECOSYSTEM_CONTEXT.md
.cursor/guide/MESSAGE_RENDERING_GUIDE.md
.cursor/guide/README.md
.cursor/guide/UAC_AND_AUTH_GUIDE.md
.cursor/guide/WEB_CLIENT_SYSTEM_DOCUMENTATION.md
erp-ai-chatbot-mobile
Client / mobile
Expo 54 / React Native 0.81 Android client. Most mature client. Force-update + APK sideload.
Tech
Expo ~54, React Native 0.81.5, React 19.1, axios, AsyncStorage
Port
APK (chatbot public/downloads/)
Path
erp-ai-chatbot-mobile/.cursor/guide/
Deep-dive docs (6)
.cursor/guide/API_CLIENT_GUIDE.md
.cursor/guide/BUILD_DEPLOYMENT_GUIDE.md
.cursor/guide/IRIS_ECOSYSTEM_CONTEXT.md
.cursor/guide/MOBILE_CLIENT_SYSTEM_DOCUMENTATION.md
.cursor/guide/README.md
.cursor/guide/UAC_AND_INTENTS_GUIDE.md
erp-ai-chatbot-desktop
Client / desktop (broken build)
Tauri 1.5 + React 18 Windows client. Currently NOT buildable (build regression).
Tech
Tauri 1.5, Rust (reqwest), React 18, react-scripts 5.0.1
Port
Tauri window
Path
erp-ai-chatbot-desktop/.cursor/guide/
Deep-dive docs (6)
.cursor/guide/API_CLIENT_GUIDE.md
.cursor/guide/BUILD_REGRESSION_AND_RECOVERY_GUIDE.md
.cursor/guide/DESKTOP_CLIENT_SYSTEM_DOCUMENTATION.md
.cursor/guide/IRIS_ECOSYSTEM_CONTEXT.md
.cursor/guide/README.md
.cursor/guide/WINDOWS_CROSS_COMPILE_GUIDE.md

Integration contract

FromToMechanismDetail
Web / Mobile / Desktop Chatbot API HTTP POST/GET All three clients call POST /api/v1/chatbot/chat (and /conversation, /config, /health, /version/check, /improve/*) at http://chatbot.inteceng.com.my:8001 (local dev http://localhost:8001). Each client sends client: 'web' | 'mobile' | 'desktop' in the body for query-log filtering.
Chatbot API ERP Shared MySQL + symlinked models (NOT HTTP) intec-erp-chatbot/app/Models is a symlink to intec-erp-v2/app/Models. Both projects point .env at the same intec_erp database. The chatbot is read-only for business data and writes only to chatbot_query_logs. Never run migrations from the chatbot.
Chatbot API Ollama HTTP (local) OllamaService calls http://localhost:11434 for intent detection fallback and general answers. Model qwen3:30b.
ERP Mobile APK HTTP download + QR MobileTerminalReleaseController renders a QR code encoding the APK download URL; operators scan it to install/upgrade. The APK also lives in the chatbot public/downloads/ and is enforced by VersionController.
All clients ERP /api/login Login flow Clients POST credentials to {chatbot-host}/api/login (host root, with /api/v1/chatbot stripped). The chatbot's AuthController validates against the shared users table and returns a Sanctum bearer token. Gap: no client currently sends the token on subsequent chat calls, and chatbot routes don't enforce auth.
Client identity Query log client field in chat body One of web, mobile, desktop. Written to ChatbotQueryLog so logs can be filtered per client. Treat as required for production clients.
UAC context Chatbot uac object in chat body (optional) { user_id, staff_id, department, role }. Used by the self-improvement prompt and LLM classification; not currently enforced as a hard authorization layer on handlers.
APK distribution Chatbot public/downloads/ Filename convention Filename convention erp-ai-chatbot-v{VERSION}.apk. VersionController::LATEST_APK names the current APK; MIN_VERSIONS enforces the floor. Bump both together on release.
CORS for Tauri config/cors.php (chatbot) Allowed origins The web origin (http://localhost:3001 + production) and the Tauri origin (tauri://localhost or http://tauri.localhost) must be in allowed_origins, with allowed_paths covering /api/*. Without the Tauri origin, desktop chat requests are silently blocked by WebView CORS. (The Rust http_get/http_post bridge bypasses CORS in Tauri mode, but the browser fallback path still needs it.)
Collaborative-query + polling Chatbot /improve/* POST + poll POST /improve/collaborative-query returns a task_id when building is needed; clients poll GET /improve/status/{taskId} until COMPLETE. Currently blocked: improve.php references ChatbotImproveController, which does not exist — the REST surface 500s. The self-improvement loop itself works (triggered directly from ChatbotService::processQuery()), but clients cannot poll a taskId.

Which project do I edit?

If you want to change...Edit projectFile(s) to touch
Add or change a chatbot intent intec-erp-chatbot config/chatbot_intents.php (LLM catalog), config/intent_patterns.php (regex), app/Services/ChatbotServices/Core/IntentDetectionService.php (isErpDataQuery()), then the matching DataHandlers/* + Formatters/*. See INTENT_SYSTEM_GUIDE.md.
Change ERP business logic / a model intec-erp-v2 app/Models/, app/Repositories/, app/Services/. Prefer the repository or a service over the controller. The chatbot sees model changes instantly via the symlink.
Change ERP schema (migration) intec-erp-v2 database/migrations/ + app/Models/. Run php artisan migrate here only.
Add a column to chatbot_query_logs intec-erp-v2 Migration here (ERP owns the schema); the chatbot writes through the symlinked ChatbotQueryLog model.
Change the chatbot API endpoints intec-erp-chatbot routes/api/chatbot/*.php (canonical; do not edit the dead routes/api/chatbotAPI.php) + app/Http/Controllers/Api/Chatbot/.
Change the LLM / Ollama integration intec-erp-chatbot app/Services/OllamaService.php, app/Services/LlmIntentDetectionService.php, config/chatbot.php (ollama, intent_detection).
Change the chat UI (web) erp-ai-chatbot-web src/components/Chatbot.js, ChatMessage.js, ChatInput.js, Sidebar.js.
Change the chat UI (mobile) erp-ai-chatbot-mobile src/screens/ChatScreen.js, src/components/ChatMessage.js.
Change the chat UI (desktop) erp-ai-chatbot-desktop src/components/* (survives) — but fix the build first (see below).
Fix the desktop build erp-ai-chatbot-desktop Follow BUILD_REGRESSION_AND_RECOVERY_GUIDE.md: restore src-tauri/{Cargo.toml,build.rs,src/main.rs,tauri.conf.json} + ForceUpdate.js/.css + updateService.js + package.json from c0f2e6b, then apply Phase 4 fixes (http_delete, /version/check path, PLATFORM=desktop, backend windows min version).
Add a mobile feature erp-ai-chatbot-mobile src/screens/, src/components/, then bump version in package.json + app.json + src/config/version.js, build APK, copy to intec-erp-chatbot/public/downloads/, bump VersionController::LATEST_APK. See BUILD_DEPLOYMENT_GUIDE.md.
Change auth (login/token) All clients + chatbot Clients: src/services/chatbotService.js (add Authorization: Bearer interceptor). Chatbot: enforce auth on /api/v1/chatbot/* and derive uac from the session. See CLIENT_INTEGRATION_GUIDE.md §8.
Change shop-floor terminals intec-erp-v2 routes/api/terminals/* + app/Http/Controllers/Api/ terminal controllers. See TERMINAL_API_GUIDE.md.
Change e-invoice / MyInvois intec-erp-v2 app/Services/ e-invoice services + Klsheng\Myinvois. See EINVOICE_SYSTEM_DOCUMENTATION.md.
Change CORS (for Tauri or web) intec-erp-chatbot config/cors.php (allowed_origins, allowed_paths).
Change the mobile minimum version / force-update intec-erp-chatbot app/Http/Controllers/Api/Chatbot/VersionController.php (MIN_VERSIONS, LATEST_APK).

Known issues & next steps (prioritized)

PriorityIssueOne-line detailRead for full detail
P1 Desktop build restoration erp-ai-chatbot-desktop is not buildable from source (commit 4f81934 deleted the Tauri infra). Restore from c0f2e6b + apply 3 latent-bug fixes + port collaborative-query flow. erp-ai-chatbot-desktop/.cursor/guide/BUILD_REGRESSION_AND_RECOVERY_GUIDE.md
P2 Cross-client parity All three clients fail to send the auth token; web has no version check; desktop has no force update; UAC key mismatch on web. intec-erp-chatbot/.cursor/guide/CLIENT_INTEGRATION_GUIDE.md §8; erp-ai-chatbot-web/.cursor/guide/WEB_CLIENT_SYSTEM_DOCUMENTATION.md
P3 Chatbot backend cleanup Orphaned progress_query intent; duplicate keys in chatbot_intents.php (9) and intent_patterns.php (2); dead chatbotAPI.php router; missing ChatbotImproveController; new_feature_* stubs out of sync; DeliveryOrder model drift risk. intec-erp-chatbot/.cursor/guide/CHATBOT_SYSTEM_DOCUMENTATION.md §8; INTENT_SYSTEM_GUIDE.md §5; ERP_INTEGRATION_GUIDE.md §5
P4 DeliveryOrder decision Confirm whether DeliveryOrder exists in intec-erp-v2/app/Models and whether the chatbot delivery domain should keep depending on it (ERP models DOs as Invoice + DeliveryEvidence by design). intec-erp-v2/.cursor/guide/DOMAIN_MODEL_GUIDE.md §9; intec-erp-chatbot/.cursor/guide/ERP_INTEGRATION_GUIDE.md §5.2
P5 Docs & cleanup ~50 root-level test_*.php scripts in ERP; stale CODEBASE_STUDY.md; TEMPORARY test_bom_wo.php route; .bak files; align chatbot README's 'Laravel 10.x' claim with composer.json (^8.75). intec-erp-v2/.cursor/guide/CHATBOT_EXTRACTION_STATUS.md §5; intec-erp-chatbot/.cursor/guide/ERP_INTEGRATION_GUIDE.md §6

Cross-cutting note: the auth-token-not-sent gap (P2) is the single most impactful security item — any future change that enforces auth on /api/v1/chatbot/* will break all three clients at once. Fix the clients first (send the token), then enforce on the backend.

Glossary

IRIS
Intec Responsive Information System — the umbrella name for INTEC's internal software family (the ERP + chatbot + clients). Also the in-chat persona name.
UAC
User Access Control — the { user_id, staff_id, department, role } context clients send with chat requests; used to scope/personalize answers and feed the self-improvement prompt. Not currently a hard authorization layer.
Intent
A label classifying what the user wants (e.g. work_order_status, invoice_overdue). Defined in three places kept consistent by hand: config/chatbot_intents.php (162 LLM intents), config/intent_patterns.php (109 regex groups), IntentDetectionService::isErpDataQuery() (runtime allow-list).
Data handler
A class implementing DataHandlerInterface that fetches ERP data for a set of intents and returns a payload array tagged with a type key. 14 handlers, one per business domain.
Formatter
A class implementing FormatterInterface that claims a handler payload by type and renders it to markdown. 14 formatters, paired 1:1 with handlers.
BOM
Bill of Materials — the product master. An n-level tree: Bom -> BomChild (sub-assemblies, self-referential) -> BomInventory (raw-material leaves). Walked by BomExplosionService.
WO
Work Order — the manufacturing order (work_orders), linked to a SalesOrderItem via so_item_id and to a Bom via bom_id. Status 20 = completed.
SO
Sales Order — the customer-facing order (sales_orders), carrying many SalesOrderItem lines.
PO
Purchase Order — a PO to a supplier (purchase_orders), carrying PurchaseOrderItem lines and GoodsReceiptsNote receipts.
DO
Delivery Order — not a separate model. A DO is an Invoice carrying DeliveryEvidence rows, scanned by the logistic terminal by invoice number. Deliberate design decision.
MyInvois
Malaysia's e-invoicing platform (LHDN). Invoice rows are submitted via Klsheng\Myinvois; einvoice_status/einvoice_uuid track submission.
TOTP
Time-based One-Time Password — used as the admin gate for first-run setup and settings on all three clients. Verified client-side against a hardcoded secret (TOTP secret is hardcoded in source; see each client's UAC_AND_AUTH_GUIDE.md).
Ollama
Local LLM inference server (:11434) running qwen3:30b. Used for intent detection fallback and general-knowledge answers.
Self-improvement loop
When IRIS cannot answer, SelfImprovementService records a task, analyzes the failure with the LLM, builds a prompt, and runs a Cursor agent / Claude CLI in the background to draft a new new_feature_<timestamp> intent + handler + formatter + REST route.
Symlinked models
intec-erp-chatbot/app/Models is a symbolic link to intec-erp-v2/app/Models, so the chatbot uses the exact same Eloquent models as the ERP with no duplication. Model changes in ERP propagate instantly; the chatbot must not edit models directly.