Files
schalli 0007ef58d9 docs(03-01): complete Module SDK + Registry plan summary
- Module SDK package with versioned interface contract
- Database-driven module registry with per-tenant activation
- ModuleGuard for tenant-scoped module access control
2026-06-19 12:38:40 +02:00

5.4 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
03-module-system-domaincheck 01 module-registry
module-sdk
prisma
nestjs
multi-tenant
guard
requires provides affects
prisma-service
tenant-middleware
jwt-auth-guard
roles-guard
module-sdk-types
module-registry-service
module-guard
module-registry-controller
app-module
added patterns
@tessera/module-sdk
upsert-activation
tenant-scoped-guard
decorator-composition
created modified
packages/module-sdk/package.json
packages/module-sdk/tsconfig.json
packages/module-sdk/src/types.ts
packages/module-sdk/src/index.ts
apps/api/prisma/migrations/20260619103242_add_module_registry/migration.sql
apps/api/src/module-registry/dto/activate-module.dto.ts
apps/api/src/module-registry/module-registry.service.ts
apps/api/src/module-registry/module-registry.controller.ts
apps/api/src/module-registry/module.guard.ts
apps/api/src/module-registry/module-registry.module.ts
apps/api/prisma/schema.prisma
apps/api/src/app.module.ts
pnpm-lock.yaml
Framework-agnostic ComponentType in SDK instead of React dependency to keep package backend-compatible
Soft-delete activation records (isActive=false) rather than row deletion for audit trail
ModuleGuard uses slug-based lookup via @UseModule() decorator for downstream modules
duration completed
7 min 2026-06-19T10:37:24Z

Phase 03 Plan 01: Module SDK + Registry Service Summary

Module SDK package with versioned interface contract and database-driven module registry with per-tenant activation/deactivation via REST API and ModuleGuard for access control.

What Was Built

Task 1: Module SDK Package + Prisma Schema (8c24c1e)

@tessera/module-sdk package (packages/module-sdk/):

  • TesseraModule interface: full module definition with id, name, version, slug, category, i18n descriptions, icon, routes, lazy-loaded components
  • ModuleRoute interface: HTTP method, path, handler for module API routes
  • ModuleManifest type: backend-only metadata (omits component/cardComponent)
  • ModuleCategory type: string literal union for module grouping
  • ComponentType: framework-agnostic component type for lazy-loaded UIs

Prisma schema extensions:

  • Module model: id (UUID), slug (unique), name, version, category, description (JSON), icon, isSystem flag, timestamps
  • TenantModuleActivation model: tenant-module join with isActive soft-delete, unique constraint on [tenantId, moduleId], index on tenantId
  • Migration 20260619103242_add_module_registry applied successfully

Task 2: ModuleRegistry NestJS Module (fa15d35)

ModuleRegistryService — full CRUD + tenant activation:

  • findAll(): list all registered modules
  • findBySlug(slug): lookup by slug
  • findActiveForTenant(tenantId): active modules for a tenant
  • activateForTenant(tenantId, moduleId): upsert activation record
  • deactivateForTenant(tenantId, moduleId): soft-delete (isActive=false)
  • isModuleActive(tenantId, moduleSlug): boolean check for guard
  • seedModule(manifest): upsert module by slug for startup seeding

ModuleRegistryController — REST endpoints:

  • GET /modules — list all modules (any authenticated user)
  • GET /modules/active — active modules for current tenant
  • POST /modules/:moduleId/activate — ADMIN/SUPER_ADMIN only
  • POST /modules/:moduleId/deactivate — ADMIN/SUPER_ADMIN only

ModuleGuard + @UseModule() decorator:

  • CanActivate guard checking tenant module activation via slug
  • Composed decorator: @UseModule('domaincheck') applies metadata + guard
  • TenantId sourced from JWT/middleware (not user input) per T-03-04

ActivateModuleDto with @IsUUID() validation per T-03-02.

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] React.ComponentType reference in SDK types

  • Found during: Task 1
  • Issue: types.ts referenced React.ComponentType but the SDK package has no React dependency, causing TypeScript errors
  • Fix: Defined a framework-agnostic ComponentType within the SDK instead of depending on React types
  • Files modified: packages/module-sdk/src/types.ts

2. [Rule 1 - Bug] DTO definite assignment in strict mode

  • Found during: Task 2
  • Issue: ActivateModuleDto.moduleId property lacked definite assignment assertion, causing TS2564 with strict mode
  • Fix: Added ! definite assignment assertion (moduleId!: string) consistent with class-validator pattern
  • Files modified: apps/api/src/module-registry/dto/activate-module.dto.ts

Threat Mitigations Applied

Threat ID Mitigation Implementation
T-03-01 @Roles(ADMIN, SUPER_ADMIN) on activate/deactivate module-registry.controller.ts
T-03-02 @IsUUID validator + Prisma parameterized queries activate-module.dto.ts, module-registry.service.ts
T-03-03 Module catalog accessible to all authenticated users GET /modules has no role restriction
T-03-04 tenantId from request (JWT/middleware), not user input module.guard.ts uses req.tenantId

Verification Results

  • API build: PASS
  • Prisma migration status: up to date (3 migrations)
  • SDK type-check: PASS
  • Required exports present: TesseraModule, ModuleRoute, ModuleManifest, ModuleCategory
  • No stubs or placeholders found

Self-Check: PASSED

All 10 created files verified on disk. Both task commits (8c24c1e, fa15d35) verified in git log.