0007ef58d9
- Module SDK package with versioned interface contract - Database-driven module registry with per-tenant activation - ModuleGuard for tenant-scoped module access control
5.4 KiB
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 |
|
|
|
|
|
|
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/):
TesseraModuleinterface: full module definition with id, name, version, slug, category, i18n descriptions, icon, routes, lazy-loaded componentsModuleRouteinterface: HTTP method, path, handler for module API routesModuleManifesttype: backend-only metadata (omits component/cardComponent)ModuleCategorytype: string literal union for module groupingComponentType: framework-agnostic component type for lazy-loaded UIs
Prisma schema extensions:
Modulemodel: id (UUID), slug (unique), name, version, category, description (JSON), icon, isSystem flag, timestampsTenantModuleActivationmodel: tenant-module join with isActive soft-delete, unique constraint on [tenantId, moduleId], index on tenantId- Migration
20260619103242_add_module_registryapplied successfully
Task 2: ModuleRegistry NestJS Module (fa15d35)
ModuleRegistryService — full CRUD + tenant activation:
findAll(): list all registered modulesfindBySlug(slug): lookup by slugfindActiveForTenant(tenantId): active modules for a tenantactivateForTenant(tenantId, moduleId): upsert activation recorddeactivateForTenant(tenantId, moduleId): soft-delete (isActive=false)isModuleActive(tenantId, moduleSlug): boolean check for guardseedModule(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 tenantPOST /modules/:moduleId/activate— ADMIN/SUPER_ADMIN onlyPOST /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.tsreferencedReact.ComponentTypebut the SDK package has no React dependency, causing TypeScript errors - Fix: Defined a framework-agnostic
ComponentTypewithin 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.moduleIdproperty 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.