From 0007ef58d93b78cbdbdc50079f906cd2421ba711 Mon Sep 17 00:00:00 2001 From: Schalli Date: Fri, 19 Jun 2026 12:38:40 +0200 Subject: [PATCH] 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 --- .../03-01-SUMMARY.md | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 .planning/phases/03-module-system-domaincheck/03-01-SUMMARY.md diff --git a/.planning/phases/03-module-system-domaincheck/03-01-SUMMARY.md b/.planning/phases/03-module-system-domaincheck/03-01-SUMMARY.md new file mode 100644 index 0000000..1741b43 --- /dev/null +++ b/.planning/phases/03-module-system-domaincheck/03-01-SUMMARY.md @@ -0,0 +1,117 @@ +--- +phase: 03-module-system-domaincheck +plan: 01 +subsystem: module-registry +tags: [module-sdk, prisma, nestjs, multi-tenant, guard] +dependency_graph: + requires: [prisma-service, tenant-middleware, jwt-auth-guard, roles-guard] + provides: [module-sdk-types, module-registry-service, module-guard, module-registry-controller] + affects: [app-module] +tech_stack: + added: ["@tessera/module-sdk"] + patterns: [upsert-activation, tenant-scoped-guard, decorator-composition] +key_files: + created: + - 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 + modified: + - apps/api/prisma/schema.prisma + - apps/api/src/app.module.ts + - pnpm-lock.yaml +decisions: + - "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" +metrics: + duration: 7 min + completed: 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.