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.

Backend Module TemplateText
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 registration

Frontend Module Template

Frontend Module TemplateText
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 components

Module 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.

ModuleTypeBackendFrontendDescription
IdentityCore✅✅Authentication, users, roles, tenants
AdminFeature—✅Admin panel with dashboard
DashboardSub-module✅ (via Identity)✅KPIs, charts, activity feed
User ManagementSub-module✅ (via Identity)✅User CRUD operations
Role ManagementSub-module✅ (via Identity)✅Role + permission assignment
Tenant ManagementSub-module✅ (via Identity)✅Multi-tenant administration
DocsFeature—✅Documentation portal
HomeFeature—✅Landing page
InventoryFutureNot presentNot presentFuture module; not available in backend today
CRM / HRMS / FinanceFutureNot presentNot presentDo not claim as current modules until backend code exists

Cross-Module Communication Patterns

  1. 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>
  2. 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!
  3. 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
    });