Module System
Module isolation rules, backend/frontend templates, module registry, and cross-module communication.
SCRIPE uses a modular-monolith backend today. Modules are separated in code and can be loaded by server role, but true independent microservices require distributed messaging that is not implemented yet.
Module Isolation Rules
Allowed Imports
- @core/* — Shared infrastructure (Result, API client, UI)
- @modules/{self}/* — Own module files only
- External npm packages (React, TanStack Query, etc.)
Forbidden Imports
- @modules/{other}/* — NEVER import from other modules
- ../../../modules/{other}/ — Relative paths to other modules
- Embedding another module's entity or component
Backend Module Template
Every backend module follows DDD (Domain-Driven Design) with three projects: Domain, Application, and Infrastructure. The Domain is pure C# with no external dependencies.
src/Modules/{ModuleName}/
├── {Module}.Domain/
│ ├── Entities/ # Domain entities (DDD)
│ ├── Interfaces/ # Repository contracts
│ ├── Specifications/ # Query specifications
│ ├── Events/ # Domain events
│ └── Enums/ # Module-specific enums
│
├── {Module}.Application/
│ ├── Commands/ # CQRS write operations
│ │ ├── Create{Entity}/
│ │ │ ├── Create{Entity}Command.cs
│ │ │ ├── Create{Entity}CommandValidator.cs
│ │ │ └── Create{Entity}CommandHandler.cs
│ │ └── Update{Entity}/
│ ├── Queries/ # CQRS read operations
│ │ ├── Get{Entity}ById/
│ │ └── List{Entities}/
│ ├── DTOs/ # Data transfer objects
│ ├── Mappings/ # Explicit DTO mapping rules
│ └── DependencyInjection.cs # Assembly marker
│
└── {Module}.Infrastructure/
├── Persistence/
│ ├── {Module}DbContext.cs
│ ├── Configurations/ # EF entity configs
│ ├── Repositories/ # Interface implementations
│ └── Migrations/ # EF migrations
├── Services/ # External service adapters
└── DependencyInjection.cs # Service registrationFrontend Module Template
src/modules/{module-name}/
├── di.ts # Module DI Container
├── index.ts # Public API (Views, entities)
└── src/
├── domain/
│ ├── entities/ # Zod schemas + domain logic
│ └── interfaces/ # Repository contracts
├── data/
│ ├── models/ # API DTOs (raw shapes)
│ ├── mappers/ # DTO ↔ Entity transforms
│ └── repositories/ # API implementations
└── presentation/
├── viewmodels/ # React hooks (all logic)
├── views/ # Pure UI (<60 lines)
└── components/ # Section UI componentsModule Registry
The current backend modules verified in code are Identity, Entitlements, Compliance, Plugins, and Marketplace, plus host controller labels such as Auth, System, Communication, Media, and Customization. CRM, HRMS, Inventory, Finance, Documents, Workflow, and Service Management are future modules, not current backend modules.
| Module | Type | Backend | Frontend | Description |
|---|---|---|---|---|
| Identity | Core | ✅ | ✅ | Authentication, users, roles, tenants |
| Admin | Feature | — | ✅ | Admin panel with dashboard |
| Dashboard | Sub-module | ✅ (via Identity) | ✅ | KPIs, charts, activity feed |
| User Management | Sub-module | ✅ (via Identity) | ✅ | User CRUD operations |
| Role Management | Sub-module | ✅ (via Identity) | ✅ | Role + permission assignment |
| Tenant Management | Sub-module | ✅ (via Identity) | ✅ | Multi-tenant administration |
| Docs | Feature | — | ✅ | Documentation portal |
| Home | Feature | — | ✅ | Landing page |
| Inventory | Future | Not present | Not present | Future module; not available in backend today |
| CRM / HRMS / Finance | Future | Not present | Not present | Do not claim as current modules until backend code exists |
Cross-Module Communication Patterns
Pattern 1: URL Navigation
Navigate to another module's page via standard URL links. No imports needed.TypeScript// In HR module — link to Vendor details via URL import Link from 'next/link'; <Link href={`/vendor/${employee.assignedVendorId}`}> View Assigned Vendor </Link>Pattern 2: Shared IDs Only
Store only the foreign module's entity ID. Never embed the whole entity.TypeScript// ✅ Store ONLY the vendor ID, not the whole entity const EmployeeSchema = z.object({ id: z.string().uuid(), name: z.string(), assignedVendorId: z.string().uuid().optional(), // Just the ID }); // ❌ DON'T embed the entire Vendor entity // vendor: VendorSchema ← This creates coupling!Pattern 3: Core Event Bus
Domain events currently dispatch in-process. RabbitMQ is a placeholder fallback, so do not use this as proof of true distributed microservices.TypeScript// Core Event Bus (future pattern) eventBus.emit("employee:created", { id: "123", name: "John" }); // Subscribing in another module eventBus.on("employee:created", (data) => { // React to employee creation without importing HR module });