@ff-admin/core-server (1.0.0)
Installation
@ff-admin:registry=npm install @ff-admin/core-server@1.0.0"@ff-admin/core-server": "1.0.0"About this package
ff-admin-core-server
Core-Funktionalität für ff-admin Server-Anwendungen als wiederverwendbares npm-Package.
📋 Inhaltsverzeichnis
- Übersicht
- Was übernimmt das Package?
- Installation
- Konfiguration
- Verwendung
- Erweiterung
- API-Dokumentation
Übersicht
@ff-admin/core-server bietet eine vollständige Basis-Infrastruktur für FF-Admin Server-Anwendungen mit Fokus auf Benutzerverwaltung, Authentifizierung, Autorisierung und WebSocket-Kommunikation. Das Package ermöglicht die Verwendung und Entwicklung von Funktionen als Basis für mehrere Anwendungen und eine konsistente API-Struktur sicherzustellen.
Was übernimmt das Package?
🔐 Authentifizierung & Autorisierung
- JWT-basierte Authentifizierung - Sichere Token-basierte Authentifizierung
- Passkey-Unterstützung - Moderne WebAuthn/Passkey-Integration
- Session-Management - Verwaltung von Benutzersitzungen
- Refresh-Tokens - Automatische Token-Erneuerung
- Reset-Funktionalität - Zugangs-Reset
- WebAPI-Tokens - Authentifizierung für externe API-Zugriffe
👥 Benutzerverwaltung
- User Entity - Vollständiges Benutzermodell mit TypeORM
- Rollen & Berechtigungen - Flexibles rollenbasiertes Berechtigungssystem
- Account-Management - Einheitlicher Zugriff auf Account-Funktionen
- Benachrichtigungen - Benachrichtigungssystem für Benutzer
- Device-Verwaltung - Tracking und Verwaltung von Geräten/Sessions
🛠️ Admin-Funktionalität
- Einladungssystem - Verwaltung von Einladungen für neue Benutzer
- Rollenverwaltung - CRUD-Operationen für Rollen
- Berechtigungssystem - Granulare Berechtigungen auf User- und Rollenebene
- WebAPI-Verwaltung - Verwaltung von API-Keys und Berechtigungen
- Moduleinstellungen - Konfigurierbare Module und Einstellungen
- Einstellungsverwaltung - Application- und Module-Settings
🌐 REST API Routes
Das Package stellt folgende fertige API-Endpunkte bereit:
/api/public- Öffentliche Endpunkte (Setup-Check, etc.)/api/setup- Initiale Setup-Konfiguration/api/reset- Passwort-Reset-Funktionalität/api/invite- Einladungsverwaltung/api/auth- Authentifizierung (Login, Logout, etc.)/api/webapi- WebAPI-Token-Verwaltung/api/admin- Admin-Funktionen (Benutzer, Rollen, etc.)/api/account- Account-Management für eingeloggte Benutzer/api/server- Server-Verwaltung und Informationen
🔌 WebSocket-Unterstützung
- Socket.IO Integration - Vollständige WebSocket-Unterstützung
- Namespace-System - Erweiterbare Socket-Namespaces
- Socket-Authentifizierung - JWT-basierte WebSocket-Authentifizierung
- Admin UI - Socket.IO Admin Panel für Development
🧰 Helper-Funktionen
- JWTHelper - Token-Generierung und -Validierung
- PasskeyHelper - WebAuthn-Operationen
- PermissionHelper - Berechtigungsprüfungen und Middlewares
- MailHelper - E-Mail-Versand
- BackupHelper - Automatische Datenbank-Backups
- NotificationHelper - Benachrichtigungsverwaltung
- SettingsHelper - Einstellungsverwaltung
- DateHelper - Datums- und Zeitoperationen
- FileSystemHelper - Dateisystem-Operationen
- StringHelper - String-Manipulationen
- und weitere...
🛡️ Middlewares
- Authentication - JWT- und WebAPI-Authentifizierung
- Access Control - Permissions- und Role-basierter Zugriff
- Rate Limiting - Schutz vor Brute-Force-Angriffen
- Error Handling - Zentralisierte Fehlerbehandlung
- File Upload - Multer-basierter File-Upload
- Device Detection - Automatische Geräteerkennung
- PWA Detection - Progressive Web App Erkennung
📦 TypeORM Integration
- Entities - Vordefinierte Datenbank-Entities für alle Basis-Funktionen
- CQRS Pattern - Commands und CommandHandlers für Datenbankoperationen
- Factories - Factory-Pattern für Entitäten
- Services - Geschäftslogik-Services
- ViewModels - Optimierte Datenstrukturen für API-Responses
⏰ Cron Jobs
- Tägliche Wartung - Automatische Bereinigung abgelaufener Tokens/Sessions
- Backup-Automation - Automatische Backups zu konfigurierten Zeitpunkten
- Erweiterbare Hooks - Eigene Cron-Jobs über
registerDailyCronHookhinzufügen
🔧 Exception Handling
- CustomRequestException - Basisklasse für API-Exceptions
- BadRequestException - 400 Fehler
- UnauthorizedRequestException - 401 Fehler
- ForbiddenRequestException - 403 Fehler
- InternalException - 500 Fehler
- DatabaseActionException - Datenbank-spezifische Fehler
Installation
npm install @ff-admin/core-server
Peer Dependencies
Das Package benötigt folgende Peer Dependencies:
express>= 5.0.0typeorm>= 0.3.0reflect-metadata
Konfiguration
1. DataSource konfigurieren
Das Package benötigt eine TypeORM DataSource. Diese muss in der Anwendung konfiguriert und an das Package übergeben werden:
import { DataSource } from "typeorm";
import { DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME, DB_SCHEMA, configureDataSource, baseTables } from "@ff-admin/core-server";
const AppDataSource = new DataSource({
type: "postgres",
host: DB_HOST,
port: DB_PORT,
username: DB_USER,
password: DB_PASSWORD,
database: DB_NAME,
schema: DB_SCHEMA,
entities: [...baseTables, ...applicationTables],
migrations: [...applicationMigrations],
synchronize: false,
});
// DataSource dem Package übergeben
configureDataSource(AppDataSource);
await AppDataSource.initialize();
Wichtig: Die Datenbank-Connection und Migrationen werden von der Anwendung verwaltet, nicht vom Package!
2. Umgebungsvariablen
Das Package erwartet folgende Umgebungsvariablen und veröffentlicht diese auch. Das Package prüft zudem den Inhalt der ENV-Variablen und setzt default Werte, sollte eine ENV nicht verwendet werden.
DB_PORT = 5432
DB_HOST = database_host
DB_NAME = database_name
DB_USERNAME = database_username
DB_PASSWORD = database_password
APPLICATION_SECRET = mysecret
USE_SECURITY_STRICT_LIMIT = (true|false) # default ist true
SECURITY_STRICT_LIMIT_WINDOW = [0-9]*(y|d|h|m|s) # default ist 15m
SECURITY_STRICT_LIMIT_REQUEST_COUNT = strict_request_count # default ist 15
USE_SECURITY_LIMIT = (true|false) # default ist true
SECURITY_LIMIT_WINDOW = [0-9]*(y|d|h|m|s) # default ist 1m
SECURITY_LIMIT_REQUEST_COUNT = request_count # default ist 500
TRUST_PROXY = <boolean|number|ip|ip1,ip2,...> # wenn leer, wird dieser Wert nicht angewendet.
3. Package Config Vals
Setzen der anwendungsspezifischen Konfigurationswerte:
import { PackageConfigVals } from "@ff-admin/core-server";
PackageConfigVals.serverRSSFeedLink = "https://git.your-server.com/server/rss-feed";
PackageConfigVals.clientRSSFeedLink = "https://git.your-server.com/client/rss-feed";
4. Konfiguration bzw. Erweiterung der PackageTypen
Das Package stellt Basis-Typen bereit, welche in der Anwendung erweitert werden können. Eine Ausführliche Information gibt es weiter unten: [Erweiterungen](## Erweiterung)
Verwendung
Express App Setup
import express, { Express } from "express";
import cors from "cors";
import helmet from "helmet";
import morgan from "morgan";
import {
// Routes
auth,
invite,
reset,
setup,
publicAvailable,
account,
admin,
applicationRouter,
webapi,
server,
// Middlewares
authenticate,
authenticateAPI,
preventWebapiAccess,
allowSetup,
detectPWA,
extractDeviceInfo,
httpApiAvailable,
errorHandler,
strictLimiter,
generalLimiter,
excludePaths,
// Helpers
PermissionHelper,
} from "@ff-admin/core-server";
export const setupApp = (app: Express) => {
// Express-Konfiguration
if (process.env.TRUST_PROXY) {
app.set("trust proxy", process.env.TRUST_PROXY);
}
app.set("query parser", "extended");
// Security & Logging
app.use(cors());
app.options("*", cors());
app.use(helmet());
app.use(morgan("combined"));
// Body Parser
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// API Verfügbarkeit
app.use(httpApiAvailable);
// Device Detection
app.use(detectPWA);
app.use(extractDeviceInfo);
// Public Routes
app.use("/api/public", publicAvailable);
// Hinzufügen der anwendungsspezifischen Public Routes
// app.use("/api/public", yourPublicRoutes);
// Setup, Reset, Invite (mit Rate Limiting)
app.use("/api/setup", strictLimiter, preventWebapiAccess, allowSetup, setup);
app.use("/api/reset", strictLimiter, preventWebapiAccess, reset);
app.use("/api/invite", strictLimiter, preventWebapiAccess, invite);
// Authentication
app.use("/api/auth", strictLimiter, preventWebapiAccess, auth);
// WebAPI Routes
app.use("/api/webapi", authenticateAPI, webapi);
// Authentifizierung für alle folgenden Routes
app.use(authenticate);
// General Rate Limiting (mit Ausnahmen)
app.use(excludePaths(generalLimiter, ["/synchronize"]));
// Admin Routes
app.use("/api/admin", admin);
app.use("/api/admin", /* Anwendungs- Admin-Routes */);
// Application routes
app.use("/api/application", applicationRouter);
// Account Routes
app.use("/api/account", preventWebapiAccess, account);
// Server Routes (nur für Admins)
app.use("/api/server", preventWebapiAccess, PermissionHelper.isAdminMiddleware(), server);
// Error Handler (muss am Ende sein!)
app.use(errorHandler);
};
WebSocket Setup
import { createServer } from "http";
import { SocketServer } from "@ff-admin/core-server";
const httpServer = createServer(app);
// Socket.IO initialisieren
SocketServer.init(httpServer);
// Eigene Socket-Namespace-Hooks registrieren (optional)
SocketServer.registerSocketNamespaceHook((io) => {
io.of("/my-namespace")
.on("connection", (socket) => {
console.log("socket connection: ", socket.id);
socketBase(this.io, socket);
});
});
// App-Namespace-Hooks registrieren (optional)
SocketServer.registerAppNamespaceHook((io, socket) => {
socket.on("myCustomEvent", (data) => {
// Handle custom events
});
});
httpServer.listen(3000);
Eigene Routes erstellen
import { Router } from "express";
import { PermissionHelper, authenticate } from "@ff-admin/core-server";
const router = Router();
// Route mit Authentifizierung
router.get("/my-endpoint", authenticate, async (req, res) => {
// req.userId, req.username, req.permissions sind verfügbar
res.json({ message: "Hello " + req.username });
});
// Route mit Berechtigungsprüfung
router.post(
"/admin-endpoint",
authenticate,
PermissionHelper.check("admin.write"),
async (req, res) => {
// Nur für Benutzer mit admin.write Berechtigung
res.json({ success: true });
}
);
export default router;
Commands verwenden
Das Package verwendet ein CQRS-Pattern. Das Package stellt CommandHandlers für Datenbankoperationen bereit:
import { UserCommandHandler, CreateUserCommand, UpdateUserCommand } from "@ff-admin/core-server";
// Benutzer erstellen
const createCommand: CreateUserCommand = {
username: "john.doe",
email: "john@example.com",
firstname: "John",
lastname: "Doe",
password: "securePassword123",
};
const newUser = await UserCommandHandler.create(createCommand);
// Benutzer aktualisieren
const updateCommand: UpdateUserCommand = {
id: newUser.id,
firstname: "Jane",
};
await UserCommandHandler.update(updateCommand);
Helpers verwenden
import {
JWTHelper,
PermissionHelper,
MailHelper,
NotificationHelper,
} from "@ff-admin/core-server";
// JWT erstellen
const token = JWTHelper.sign({ userId: "123", username: "john" });
// JWT validieren
const payload = JWTHelper.verify(token);
// Berechtigungen prüfen
const hasPermission = PermissionHelper.check("admin.users.write");
// E-Mail senden
await MailHelper.send({
to: "user@example.com",
subject: "Welcome",
html: "<h1>Welcome to our platform</h1>",
});
// Benachrichtigung erstellen
await NotificationHelper.create({
userId: "123",
title: "New Message",
message: "You have a new message",
});
Cron Jobs erweitern
import { registerDailyCronHook } from "@ff-admin/core-server";
// Eigene tägliche Wartungsaufgabe registrieren
registerDailyCronHook(async () => {
console.log("Running custom daily maintenance task");
// Ihre Logik hier
await cleanupOldData();
});
Erweiterung
TypeScript Type Declarations erweitern
Das Package bietet mehrere Interfaces, die in der Anwendung erweitern werden können, um anwendungsspezifische Funktionalität hinzuzufügen.
SocketNamespaceMap
Erweitern der Socket.IO Namespaces:
declare module "@ff-admin/core-server" {
interface SocketNamespaceMap {
myCustomNamespace: "/custom";
anotherNamespace: "/another";
}
}
import { configureSocketNamespace, SocketNamespace } from "@ff-admin/core-server";
// Namespaces konfigurieren
configureSocketNamespace({
myCustomNamespace: "/custom",
anotherNamespace: "/another",
});
// Verwendung
console.log(SocketNamespace.myCustomNamespace); // "/custom"
const namespace: SocketNamespace = SocketNamespace.app; // Type-safe
PermissionSectionMap & PermissionModuleMap
Erweitern des Berechtigungssystem um eigene Sections und Module:
declare module "@ff-admin/core-server" {
interface PermissionSectionMap {
// Eigene Berechtiungs-Section hinzufügen
mySection: void;
}
interface PermissionModuleMap {
// Eigene Berechtigungs-Module hinzufügen
myModule: void;
anotherModule: void;
}
}
// Verwendung im Code
import { PermissionHelper } from "@ff-admin/core-server";
// Nachfolgende Funktionen werden benötigt, um die Werte neben den Typen verfügbar zu machen.
extendPermissionSections(/** ... */)
extendPermissionModules(/** ... */)
configureSectionsAndModules(/** ... */)
ModuleSettingTopicMap & ModuleSettingValueMapping
Erweitern der Modul-Einstellungen um eigene Topics und Settings:
declare module "@ff-admin/core-server" {
interface ModuleSettingTopicMap {
myModule: void;
}
interface ModuleSettingValueMapping {
"myModule.setting1": string;
"myModule.setting2": number;
"myModule.enabled": boolean;
}
}
import {
configurModuleSettingsType,
ModuleSettingsSchema
} from "@ff-admin/core-server";
// Schema für die neuen Settings definieren
configurModuleSettingsType({
"myModule.setting1": {
type: "string",
default: "default value"
},
"myModule.setting2": {
type: "number",
default: 42
},
"myModule.enabled": {
type: "boolean",
default: false
},
});
// Verwendung
import { SettingsHelper } from "@ff-admin/core-server";
const setting = await SettingsHelper.getModuleSetting("myModule.setting1");
await SettingsHelper.setModuleSetting("myModule.enabled", true);
SettingTopicMap & SettingValueMapping
Erweitern der Application-Einstellungen um eigene Topics und Settings:
declare module "@ff-admin/core-server" {
interface SettingTopicMap {
myApp: void;
}
interface SettingValueMapping {
"myApp.apiKey": string;
"myApp.timeout": number;
"myApp.baseUrl": string;
}
}
import {
configurSettingsType,
SettingsSchema
} from "@ff-admin/core-server";
// Schema für die neuen Settings definieren
configurSettingsType({
"myApp.apiKey": {
type: "string",
optional: true
},
"myApp.timeout": {
type: "number",
default: 5000
},
"myApp.baseUrl": {
type: "url",
default: "https://api.example.com"
},
});
// Verwendung
import { SettingsHelper } from "@ff-admin/core-server";
const apiKey = await SettingsHelper.getSetting("myApp.apiKey");
await SettingsHelper.setSetting("myApp.timeout", 10000);
Eigene Entities
Erweitern der Package-Entities oder erstellen eigener:
import { Entity, Column, ManyToOne } from "typeorm";
import { User } from "@ff-admin/core-server";
@Entity()
export class CustomUserData {
@Column()
someCustomField: string;
@ManyToOne(() => User)
user: User;
}
Eigene Datenbanktabellen können direkt in der Anwendung angelegt werden. Soll eine bestehende Entität des packages erweitert werden, so kann eine eigene Entity von der Entität des Packages erben. Jedoch müssen dann auch alle Abhängigkeiten zu dieser Ursprungsentität ersetzt und in der Anwendung neue implementiert werden.
Routen überschreiben
Die vom Package bereitgestellten Routen können in der Anwendung jederzeit überschrieben werden. Express verwendet Pattern-Matching für Routes, wobei die zuerst definierte Route Vorrang hat.
import express from "express";
import {
auth, // Package-Route
authenticate
} from "@ff-admin/core-server";
const app = express();
// Eigene Login-Route, die die Package-Route überschreibt
app.post("/api/auth/login", async (req, res) => {
// Ihre angepasste Implementierung
console.log("Custom login logic");
// ...
res.json({ success: true });
});
// Package-Route wird hinzugefügt, aber /api/auth/login ist bereits definiert
// Daher wird die obige Route für /login verwendet
app.use("/api/auth", auth);
// Alternativ: Nur bestimmte Endpunkte vom Package nutzen
app.post("/api/auth/login", customLoginHandler); // Überschrieben
app.use("/api/auth", auth); // Andere Endpunkte vom Package
Wichtig: Definieren Sie Ihre benutzerdefinierten Routen vor den Package-Routen, um sicherzustellen, dass Ihre Implementierung verwendet wird.
Beispiel - Teilweises Überschreiben:
// Setup-Endpunkt mit zusätzlicher Validierung überschreiben
app.post("/api/setup/initial",
customValidationMiddleware,
customSetupHandler
);
// Restliche Setup-Routen vom Package verwenden
app.use("/api/setup", strictLimiter, preventWebapiAccess, allowSetup, setup);
API-Dokumentation
Express Request Extensions
Das Package erweitert das Express Request-Objekt um folgende Properties:
interface Request {
userId: string; // ID des authentifizierten Benutzers
username: string; // Username des Benutzers
firstname: string; // Vorname
lastname: string; // Nachname
isOwner: boolean; // Ist der Benutzer Owner?
permissions: PermissionObject; // Berechtigungsobjekt
isPWA: boolean; // Zugriff über PWA?
isWebApiRequest: boolean; // Zugriff über WebAPI?
deviceFingerprint: string; // Geräte-Fingerprint
deviceName: string; // Gerätename
}
Wichtige Exports
Das Package exportiert folgende Hauptkomponenten:
- Commands - CQRS Commands und CommandHandlers
- Controllers - Controller für API-Endpunkte
- Entities - TypeORM Entities
- Enums - API-Status, Login-Routinen, Socket-Namespaces
- Exceptions - Custom Exception-Klassen
- Factories - Factory-Pattern Implementierungen
- Helpers - Utility-Funktionen
- Middlewares - Express-Middlewares
- Routes - Fertige API-Routes
- Services - Business-Logic Services
- Types - TypeScript Type Definitions
- ViewModels - API Response Models
- WebSocket - Socket.IO Konfiguration
Lizenz
AGPL-3.0-only
Author
JK Effects
Repository
https://code.jk-effects.cloud/FF-Admin/ff-admin-core-server.git
Dependencies
Dependencies
| ID | Version |
|---|---|
| @simplewebauthn/server | ^13.2.2 |
| cors | ^2.8.6 |
| crypto | ^1.0.1 |
| dotenv | ^17.2.4 |
| express | ^5.2.1 |
| express-rate-limit | ^8.2.1 |
| express-validator | ^7.3.1 |
| helmet | ^8.1.0 |
| ip-address | ^10.1.0 |
| jsonwebtoken | ^9.0.3 |
| lodash.clonedeep | ^4.5.0 |
| lodash.uniqby | ^4.7.0 |
| moment | ^2.30.1 |
| morgan | ^1.10.1 |
| ms | ^2.1.3 |
| multer | ^2.0.2 |
| node-schedule | ^2.1.1 |
| nodemailer | ^8.0.0 |
| qrcode | ^1.5.4 |
| reflect-metadata | ^0.2.2 |
| rss-parser | ^3.13.0 |
| sharp | ^0.34.5 |
| sharp-ico | ^0.1.5 |
| socket.io | ^4.8.3 |
| speakeasy | ^2.0.0 |
| typeorm | ^0.3.28 |
| ua-parser-js | ^2.0.9 |
| uuid | ^13.0.0 |
| validator | ^13.15.26 |
Development dependencies
| ID | Version |
|---|---|
| @socket.io/admin-ui | ^0.5.1 |
| @types/cors | ^2.8.19 |
| @types/express | ^5.0.6 |
| @types/ip | ^1.1.3 |
| @types/jsonwebtoken | ^9.0.10 |
| @types/lodash.clonedeep | ^4.5.9 |
| @types/lodash.uniqby | ^4.7.9 |
| @types/morgan | ^1.9.10 |
| @types/ms | ^2.1.0 |
| @types/multer | ^2.0.0 |
| @types/node | ^25.2.1 |
| @types/node-schedule | ^2.1.8 |
| @types/nodemailer | ^7.0.9 |
| @types/qrcode | ~1.5.6 |
| @types/speakeasy | ^2.0.10 |
| @types/uuid | ^11.0.0 |
| @types/validator | ^13.15.10 |
| ts-node | 10.9.2 |
| tsc-alias | ^1.8.16 |
| typescript | ^5.9.3 |
