Architecture Overview
Philosophy
Section titled “Philosophy”“ERP must adapt to the business — not the other way around.”
iZ ERP is inspired by WordPress’s plugin/theme architecture, applied to business operations. The core is intentionally minimal — everything else is a module you enable, disable, or build yourself.
4-Tier Architecture
Section titled “4-Tier Architecture”┌──────────────────────────────────────────────────────────────┐│ COMMUNITY EXTENSIONS (Tier 3) ││ automation · document-hub · sync-connectors · billing │├──────────────────────────────────────────────────────────────┤│ PLATFORM MODULES (Tier 2) ││ global-search · import · api-keys · webhooks · settings │├──────────────────────────────────────────────────────────────┤│ CRM CORE (Tier 1) ││ contacts · deals · companies · activities · custom-fields │├──────────────────────────────────────────────────────────────┤│ CORE ENGINE (Tier 0 — IMMUTABLE) ││ schema · event-bus · rbac · auth · db · migrations │└──────────────────────────────────────────────────────────────┘| Tier | Loaded | Can be disabled |
|---|---|---|
| 0 — Core Engine | Always | ❌ Never |
| 1 — CRM Core | Always | ❌ No |
| 2 — Platform Modules | Configurable | ✅ Yes |
| 3 — Community Extensions | Opt-in | ✅ Yes |
Golden Rules
Section titled “Golden Rules”These rules are non-negotiable. All code in izhubs — including extensions — must follow them.
| Rule | What it means |
|---|---|
| No direct DB access | Only core/engine/*.ts may call db.query(). Routes import from engine. |
| ApiResponse always | All routes use ApiResponse.success/error. Never NextResponse.json() directly. |
| Zod on DB output | Every DB row passes through Schema.parse() before returning. |
| Soft-delete only | Never DELETE FROM. Use UPDATE SET deleted_at = NOW(). |
| withPermission() guard | Every API route wrapped with withPermission('resource:action', handler). |
| No component > 150 lines | Split if exceeded. |
| Sequential migrations | New migration = new file 00X_description.sql. Never edit committed migrations. |
| EventBus for cross-module | Modules never import each other. Communication = eventBus.emit() only. |
Event System
Section titled “Event System”iZ ERP uses an internal EventBus (inspired by WordPress do_action):
// Emitting an event (inside engine)await eventBus.emit('deal.stage_changed', { deal, fromStage, toStage });
// Listening to an event (in a module or extension)eventBus.on('deal.stage_changed', async ({ deal }) => { // send notification, trigger automation, etc.});Built-in events:
| Event | Emitted when |
|---|---|
deal.created | New deal created |
deal.stage_changed | Deal moved to a different stage |
deal.won | Deal stage set to won |
deal.lost | Deal stage set to lost |
contact.created | New contact created |
contact.updated | Contact fields updated |
File Structure
Section titled “File Structure”izhubs-erp/├── .agent/ ← AI context (memory, tracks, skills)├── core/│ ├── schema/ ← Zod schemas — source of truth│ └── engine/ ← DB access layer (only place db.query() is allowed)├── modules/ ← crm, automation, contracts...├── extensions/sdk/ ← ExtensionBase.ts for building add-ons├── app/ ← Next.js frontend + API routes├── database/migrations/ ← Sequential SQL migration files└── tests/contracts/ ← Schema + API contract tests