# platform-module-sdk Offizielles SDK für MPM-Module (Phase 8). Es verdrahtet den verbindlichen Modul-API-Vertrag und stellt Authentifizierung, Konfiguration, Logging und einen Plattform-API-Client bereit. ## Installation (Vendor-Pattern) Module sind selbstständige ZIP-Pakete. Das SDK wird als **eine Datei** (`index.js`) in das Modul-Paket kopiert (z. B. `backend/platform-module-sdk.js`) und per `require` geladen. Dadurch bleiben Module ohne npm-Registry lauffähig. ```text mein-modul/ ├── module.json ├── backend/ │ ├── server.js # Einstiegspunkt (Manifest: entrypoint) │ └── platform-module-sdk.js # vendored SDK (Kopie von index.js) └── README.md ``` ## Schnellstart ```js 'use strict'; const path = require('node:path'); const { createModuleServer, loadManifest, createLogger, } = require('./platform-module-sdk'); const manifest = loadManifest(path.join(__dirname, '..', 'module.json')); const logger = createLogger({ moduleId: manifest.id }); const port = Number(process.env.PORT ?? manifest.port); const server = createModuleServer({ manifest, logger, permissions: ['meinmodul.read'], routes: (request, response, context) => { // context.identity → { userId, username, displayName, role } // context.path → URL-Pfad if (request.method === 'GET' && context.path === '/aufgaben') { response.writeHead(200, { 'Content-Type': 'application/json' }); response.end(JSON.stringify({ aufgaben: [] })); return; } response.writeHead(404, { 'Content-Type': 'application/json' }); response.end(JSON.stringify({ statusCode: 404, message: 'Nicht gefunden' })); }, }); server.listen(port, '127.0.0.1', () => { logger.info(`Modul gestartet`, { port }); }); ``` Der Server verdrahtet automatisch den Vertrag: | Endpunkt | Verhalten | |---|---| | `GET /health` | 200 `{ moduleId, version, status: "healthy" }` | | `GET /api/manifest` | 200 Manifest + Status | | `GET /api/me` | 200 Identität vom Gateway (401 ohne Identität) | | fachliche Routen | `options.routes(...)`; ohne Identität 401 (`identityRequired`) | ## API ### `extractIdentity(headers)` > This helper only parses untrusted header values. Do not use it as an authorization check. `createModuleServer` verifies the request-bound, per-module signature before exposing the identity to `/api/me` or route handlers. In production it requires the key injected as `MPM_MODULE_IDENTITY_KEY`. Liest die Benutzer-Identität aus den Gateway-Headern (`x-user-id`, `x-user-username`, `x-user-display-name`, `x-user-role`). Case-insensitive; `null`, wenn der Request nicht über den Gateway kam. ### `loadManifest(manifestPath)` Lädt und validiert `module.json` (Pflichtfelder, Runtime `node`, apiVersion `v1`). ### `loadModuleConfig(env?)` Laufzeit-Konfiguration: `port` (ENV `PORT`), `nodeEnv`, `platformBaseUrl` (ENV `PLATFORM_INTERNAL_URL`, Default `http://127.0.0.1:3000`), `serviceToken`. ### `createLogger({ moduleId, level })` Strukturierte JSON-Logs (`debug/info/warn/error`). Sensible Schlüssel (Passwort, Token, Secret, Cookie, …) werden automatisch geschwärzt. ### `createPlatformClient({ baseUrl, serviceToken, timeoutMs }))` HTTP-Client für interne Aufrufe zur Plattform (`get/post/patch/delete`). Wirft bei Nicht-2xx einen Fehler mit Statuscode. ### `createModuleServer(options)` Siehe Schnellstart. Optionen: `manifest`, `routes`, `permissions`, `logger`, `identityRequired` (Default `true` – sicherer Default). ## Tests Die SDK-Tests laufen im Backend-Test-Suite (`apps/platform-backend/test/platform-module-sdk.spec.ts`): ```bash cd apps/platform-backend && npm test ``` ## Sicherheitsregeln für Modul-Autoren - Nur auf `127.0.0.1` lauschen (der Gateway ist der einzige Zugang). - Identität ausschließlich über `extractIdentity` beziehen – niemals aus URL, Body oder eigenen Headern vertrauen. - Keine Plattform-Secrets erwarten: Der Prozess-Manager übergibt nur `PATH`, `NODE_ENV` und `PORT`. - Logs niemals Passwörter/Tokens/personenbezogene Daten schreiben lassen.