113 lines
4.0 KiB
Markdown
113 lines
4.0 KiB
Markdown
# 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. |