fbd7d44e88
- Document module loader registry, category pages, and expanded module views - Record threat mitigations T-03-09, T-03-10, T-03-11 - Self-check passed: all files and commits verified
111 lines
5.6 KiB
Markdown
111 lines
5.6 KiB
Markdown
---
|
|
phase: 03-module-system-domaincheck
|
|
plan: 03
|
|
subsystem: module-ui-loader
|
|
tags: [lazy-loading, dynamic-imports, next-dynamic, category-page, module-cards]
|
|
dependency_graph:
|
|
requires:
|
|
- module-registry-service
|
|
- domaincheck-frontend-page
|
|
provides:
|
|
- module-loader-registry
|
|
- category-page
|
|
- expanded-module-view
|
|
- api-client-utils
|
|
affects: [sidebar-module-links, module-marketplace]
|
|
tech_stack:
|
|
added: []
|
|
patterns: [next-dynamic-ssr-false, slug-whitelist-registry, category-grid-layout]
|
|
key_files:
|
|
created:
|
|
- apps/web/src/lib/module-loader.ts
|
|
- apps/web/src/lib/api.ts
|
|
- apps/web/src/app/(portal)/modules/[category]/page.tsx
|
|
- apps/web/src/app/(portal)/modules/[category]/components/ModuleCard.tsx
|
|
- apps/web/src/app/(portal)/modules/[category]/[moduleSlug]/page.tsx
|
|
modified:
|
|
- apps/web/src/messages/de.json
|
|
- apps/web/src/messages/en.json
|
|
key_decisions:
|
|
- "MODULE_REGISTRY whitelist pattern: only slugs explicitly listed can trigger dynamic imports (T-03-09)"
|
|
- "Client components for all pages to support next/dynamic with ssr:false and client-side API fetching"
|
|
- "Inline SVG icons to avoid external icon library dependency while keeping ModuleCard self-contained"
|
|
patterns_established:
|
|
- "Module registry pattern: slug -> { component, cardComponent? } mapping for lazy loading"
|
|
- "Category page pattern: [category] dynamic route with API fetch + filter + grid render"
|
|
- "Expanded module view pattern: [moduleSlug] route with whitelist check + dynamic component render"
|
|
requirements_completed: [MOD-04]
|
|
duration: 6min
|
|
completed: 2026-06-19
|
|
---
|
|
|
|
# Phase 03 Plan 03: Module UI Lazy Loading + Category Pages Summary
|
|
|
|
**Lazy-loaded module UI rendering via next/dynamic with slug-whitelist registry, category grid pages, and expanded module views**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** 6 min
|
|
- **Started:** 2026-06-19T11:32:50Z
|
|
- **Completed:** 2026-06-19T11:38:50Z
|
|
- **Tasks:** 2/2
|
|
- **Files created:** 5
|
|
- **Files modified:** 2
|
|
|
|
## Accomplishments
|
|
|
|
- MODULE_REGISTRY in module-loader.ts maps module slugs to dynamically imported components via next/dynamic with ssr:false, ensuring inactive modules are never bundled (MOD-04)
|
|
- Category page at /modules/[category] fetches active modules from API, filters by category, and renders a responsive card grid (D-04)
|
|
- ModuleCard component displays icon, name, localized description, and link to expanded view with hover effects (D-05a)
|
|
- Expanded module view at /modules/[category]/[moduleSlug] loads the module component on demand via whitelist lookup (D-05b)
|
|
- API client utilities (getActiveModules, getModuleBySlug) provide typed fetch wrappers for module endpoints
|
|
- i18n keys added for "modules" namespace in both German and English
|
|
|
|
## Task Commits
|
|
|
|
Each task was committed atomically:
|
|
|
|
1. **Task 1: Module Loader Utility + Category Page with Lazy Cards** - `a191628` (feat)
|
|
2. **Task 2: Expanded Module View with Dynamic Routing** - `de63b10` (feat)
|
|
|
|
## Files Created/Modified
|
|
|
|
- `apps/web/src/lib/module-loader.ts` - MODULE_REGISTRY with loadModuleComponent and loadModuleCard exports
|
|
- `apps/web/src/lib/api.ts` - getActiveModules and getModuleBySlug API client functions
|
|
- `apps/web/src/app/(portal)/modules/[category]/page.tsx` - Category page with module grid and empty state
|
|
- `apps/web/src/app/(portal)/modules/[category]/components/ModuleCard.tsx` - Module card with icon, description, and link
|
|
- `apps/web/src/app/(portal)/modules/[category]/[moduleSlug]/page.tsx` - Expanded module view with lazy loading and not-found state
|
|
- `apps/web/src/messages/de.json` - Added modules namespace (categoryTitle, openModule, noModules, notFound, etc.)
|
|
- `apps/web/src/messages/en.json` - Added modules namespace (categoryTitle, openModule, noModules, notFound, etc.)
|
|
|
|
## Decisions Made
|
|
|
|
- **Slug whitelist pattern:** MODULE_REGISTRY acts as an allowlist — only explicitly registered slugs can trigger dynamic imports. Arbitrary URL slugs get a not-found state, never an import attempt (T-03-09).
|
|
- **Client components throughout:** All three pages use 'use client' to support next/dynamic with ssr:false and client-side fetch with credentials:include for auth cookie forwarding.
|
|
- **Inline SVG icons:** ModuleCard uses inline SVGs rather than an icon library to avoid adding a dependency for a small number of icons. Icons are mapped by the module's icon property (e.g., 'Globe' for domaincheck).
|
|
- **Category filtering:** The category page fetches all active modules and filters client-side by category. This keeps the API simple (single /modules/active endpoint) while supporting category-based views.
|
|
|
|
## Threat Mitigations Applied
|
|
|
|
| Threat ID | Mitigation | Implementation |
|
|
|-----------|------------|----------------|
|
|
| T-03-09 | Slug whitelist via MODULE_REGISTRY | module-loader.ts: only registered slugs resolve to components; [moduleSlug]/page.tsx checks `slug in MODULE_REGISTRY` before loading |
|
|
| T-03-10 | API filters by tenant active modules | [category]/page.tsx: fetches from /modules/active which is tenant-scoped server-side |
|
|
| T-03-11 | Accepted | Module names/descriptions are non-sensitive catalog data |
|
|
|
|
## Deviations from Plan
|
|
|
|
None - plan executed exactly as written.
|
|
|
|
## Verification Results
|
|
|
|
- `pnpm --filter web build`: PASS
|
|
- Route `/modules/[category]` generated: confirmed in build output (2.01 kB)
|
|
- Route `/modules/[category]/[moduleSlug]` generated: confirmed in build output (1.95 kB)
|
|
- Domaincheck module code at `/modules/domaincheck` (1.47 kB) is separate from category page, confirming code-splitting works
|
|
- No stubs or placeholders found in created files
|
|
|
|
## Self-Check: PASSED
|
|
|
|
All 5 created files verified on disk. Both task commits (a191628, de63b10) verified in git log.
|