3a1bfd943e
- ProxmoxServer/ProxmoxServerStatus mit RLS (tenant_isolation_policy +
system_read_policy auf ProxmoxServer fuer den kommenden Planer)
- proxmox-auth.ts (Token-Kopfzeilen PVE/PBS), proxmox-client.service.ts
(proxmoxGet, ausschliesslich lesend, Dispatcher je Aufruf aus
tlsRejectUnauthorized, nie global)
- proxmox.service.ts: Server anlegen (Geheimnis verschluesselt,
select ohne Geheimnisfelder), Serverliste, PVE-Abfrage mit
nachsichtiger Grundauswertung (Knoten/Gaeste)
- Controller/Modul/Seed nach Domaincheck-Vorbild, Kategorie
"infrastructure", @UseModule('proxmox') + @Roles auf Schreibwegen
- Modulseite (duenne Liste) + proxmox-api.ts + Registrierung in
MODULE_REGISTRY
- Zugriffsklassifikation nachgezogen (rls-access-inventory.spec.ts gruen)
Tore: api 1247/1247 (>=1240), web 693/693, type-check 4/4, lint 5/5,
Biome apps/web 53 Warnungen (unveraendert).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
91 lines
2.4 KiB
TypeScript
91 lines
2.4 KiB
TypeScript
/**
|
|
* Module Loader — Lazy-loading registry for Tessera modules.
|
|
*
|
|
* Maps module slugs to dynamically imported components.
|
|
* Only modules listed in MODULE_REGISTRY will have their code loaded;
|
|
* inactive/unregistered modules never trigger an import (MOD-04).
|
|
*
|
|
* Security: Only whitelisted slugs are resolved — arbitrary slugs
|
|
* from URL params return null (T-03-09).
|
|
*/
|
|
|
|
import dynamic from 'next/dynamic';
|
|
import type { ComponentType } from 'react';
|
|
|
|
/**
|
|
* Registry entry for a module's lazy-loaded components.
|
|
*/
|
|
interface ModuleRegistryEntry {
|
|
/** Main module page component (loaded on demand) */
|
|
component: ComponentType;
|
|
/** Optional card component for category grid view */
|
|
cardComponent?: ComponentType;
|
|
}
|
|
|
|
/**
|
|
* Module registry mapping slugs to lazy-loaded components.
|
|
*
|
|
* To register a new module, add its slug and dynamic imports here.
|
|
* Components are only fetched when React renders them (code-splitting).
|
|
*/
|
|
export const MODULE_REGISTRY: Record<string, ModuleRegistryEntry> = {
|
|
domaincheck: {
|
|
component: dynamic(
|
|
() => import('@/app/(portal)/modules/domaincheck/page'),
|
|
{ ssr: false },
|
|
),
|
|
},
|
|
'dkv-fleet': {
|
|
component: dynamic(
|
|
() => import('@/app/(portal)/modules/dkv-fleet/page'),
|
|
{ ssr: false },
|
|
),
|
|
},
|
|
'cert-manager': {
|
|
component: dynamic(
|
|
() => import('@/app/(portal)/modules/cert-manager/page'),
|
|
{ ssr: false },
|
|
),
|
|
},
|
|
'tender-radar': {
|
|
component: dynamic(
|
|
() => import('@/app/(portal)/modules/tender-radar/page'),
|
|
{ ssr: false },
|
|
),
|
|
},
|
|
proxmox: {
|
|
component: dynamic(
|
|
() => import('@/app/(portal)/modules/proxmox/page'),
|
|
{ ssr: false },
|
|
),
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Load the main component for a module by slug.
|
|
*
|
|
* @param slug - Module slug (e.g., 'domaincheck')
|
|
* @returns The dynamic component, or null if the slug is not registered
|
|
*/
|
|
export function loadModuleComponent(
|
|
slug: string,
|
|
): ComponentType | null {
|
|
const entry = MODULE_REGISTRY[slug];
|
|
return entry?.component ?? null;
|
|
}
|
|
|
|
/**
|
|
* Load the card component for a module by slug.
|
|
*
|
|
* Falls back to null if no card component is registered.
|
|
*
|
|
* @param slug - Module slug (e.g., 'domaincheck')
|
|
* @returns The card component, or null if not available
|
|
*/
|
|
export function loadModuleCard(
|
|
slug: string,
|
|
): ComponentType | null {
|
|
const entry = MODULE_REGISTRY[slug];
|
|
return entry?.cardComponent ?? null;
|
|
}
|