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 vLLM (`iris-v3` / Qwen2.5-14B-Instruct-AWQ) 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
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.
Latest Updates
17 entries · 2026-07-30 → 2026-08-03
Consolidated retrospective across the four IRIS chatbot-family repos (intec-erp-chatbot, erp-ai-chatbot-web, erp-ai-chatbot-mobile, erp-ai-chatbot-desktop). Newest first.
Projects
- Tech
- PHP 7.1+, Laravel 5.8, Vue 2, Blade, MySQL, Cartalyst Sentinel, InfyOm generator
- Port
- 8000
- Path
- intec-erp-v2/.cursor/guide/
- Tech
- PHP 8, Laravel 8.75, Sanctum, vLLM chat replicas + Unlimited-OCR on GPU 3
- Port
- 8001
- Path
- intec-erp-chatbot/.cursor/guide/
- Tech
- React 19, react-scripts 5.0.1, axios, react-markdown, mermaid, recharts
- Port
- 3001
- Path
- erp-ai-chatbot-web/.cursor/guide/
- 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/
- Tech
- Electron, electron-updater, React 19, react-scripts 5.0.1
- Port
- Electron window
- Path
- erp-ai-chatbot-desktop/.cursor/guide/
Integration contract
| From | To | Mechanism | Detail |
|---|---|---|---|
| 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 https://chatbot.inteceng.com.my (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 | vLLM | HTTP (local) | OllamaService (vLLM backend) calls http://127.0.0.1:8002 OpenAI /v1. Four GPU replicas behind nginx least_conn. Model Qwen2.5-14B-Instruct-AWQ (aliases iris-v3, gemma4:12b). |
| 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. Clients now send Authorization: Bearer on every chat request; the chatbot's ResolveChatUser middleware resolves the Sanctum session and the chat pipeline enforces per-user UAC (a legacy user_id body fallback is retained during the cutover, so old clients keep working). |
| 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 | Chatbot | Server-side, per-user, enforced | Resolved from the Sanctum Bearer token by the ResolveChatUser middleware; per-user allowed intent categories are stored in uac_user_settings (ERP users synced into erp_users via the erp-users:sync command). The chat pipeline (ChatbotService) enforces UAC — disallowed intent categories fall through to the no-data / uac_blocked path. The old client-sent uac body field is removed. |
| APK distribution | Chatbot public/downloads/ | Filename convention | Filename convention erp-ai-chatbot-v{VERSION}.apk. VersionController latest = min for android and desktop/windows. Bump LATEST_* and rebuild both clients on release. |
| CORS for web | config/cors.php (chatbot) | Allowed origins | The web origin (http://localhost:3001 + production) must be in allowed_origins, with allowed_paths covering /api/*. The desktop client no longer needs a CORS entry: its Electron IPC bridge routes HTTP through the main process (Node fetch), bypassing renderer CORS entirely (Tauri is gone). |
| 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: routes/api/chatbot/improve.php references App\Http\Controllers\Api\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 project | File(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 / vLLM integration | intec-erp-chatbot | app/Services/OllamaService.php, scripts/vllm-serve.sh, scripts/iris-vllm@.service, config/chatbot.php (llm.vllm). |
| 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). Desktop src/ is a forked copy of web src/ — mirror visual edits, keep the Electron IPC logic in src/services/httpClient.js + electron/. |
| Fix / rebuild the desktop build | erp-ai-chatbot-desktop | The Tauri shell is gone; the desktop is now Electron + React (electron/main.js, electron/preload.js, package.json). Rebuild with `npm run build && npm run dist:win` (electron-builder + Wine — see WINDOWS_CROSS_COMPILE_GUIDE.md; re-apply the 3 wine32-free patches after every npm install). |
| 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 send Authorization: Bearer on every chat request (src/services/chatbotService.js). Chatbot: ResolveChatUser middleware resolves the Sanctum session and ChatbotService enforces per-user UAC. See CLIENT_INTEGRATION_GUIDE.md §8. |
| Manage ERP users / UAC | intec-erp-chatbot | UsersUacController + resources/views/admin/users-uac.blade.php (list/search/filter, per-user UAC editor, bulk-assign, manual "Sync ERP users"). erp-users:sync snapshots the ERP users table into erp_users. |
| 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 web) | intec-erp-chatbot | config/cors.php (allowed_origins, allowed_paths). Desktop needs no CORS entry — Electron IPC bypasses renderer CORS. |
| 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)
| Priority | Issue | One-line detail | Read for full detail |
|---|---|---|---|
| P1 | Collaborative-query REST 500s | routes/api/chatbot/improve.php references App\Http\Controllers\Api\ChatbotImproveController, which does not exist — POST /improve/collaborative-query and the /improve/status polling surface 500. The self-improvement loop itself works (triggered directly from ChatbotService::processQuery()), but clients cannot poll a taskId. | intec-erp-chatbot/.cursor/guide/CHATBOT_SYSTEM_DOCUMENTATION.md §8 |
| P2 | Web SPA not independently deployed | erp-ai-chatbot-web has no version-check / force-update gate (mobile and desktop do), and there is no documented deployment of the web SPA build — web users only get the new build on next page load. Add a web version-check gate and a deploy pipeline. | erp-ai-chatbot-web/.cursor/guide/WEB_CLIENT_SYSTEM_DOCUMENTATION.md |
| P3 | Remaining intent drift (61) | intent:audit reports 61 remaining: 58 handler-supported intents with no regex pattern (needs regex, left on the LLM path) + new_erp_feature_request (intentional self-improvement trigger, counted twice). The duplicate-key, new_feature_* sync, and progress_query orphan drift is RESOLVED by the intent automation (registry + intent:generate + intent:audit). | intec-erp-chatbot/.cursor/guide/INTENT_AUDIT.md §8–§9 |
| 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 | Inventory-image follow-up + docs cleanup | Inventory images are not yet surfaced in chat (InventoryController reads images from local disk with different part-number sanitization than the BOM URL mechanism — needs reconciling). Plus: ~50 root-level test_*.php scripts in ERP; stale CODEBASE_STUDY.md; .bak files; align chatbot README's "Laravel 10.x" claim with composer.json (^8.75). | intec-erp-chatbot/.cursor/guide/ERP_INTEGRATION_GUIDE.md §6; intec-erp-v2/.cursor/guide/CHATBOT_EXTRACTION_STATUS.md §5 |
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.