feat: Phase 1 – Plattform-Grundgerüst (Docker, NestJS, React, Auth)

This commit is contained in:
MPM Dev
2026-10-06 14:22:11 +02:00
commit a7e1c421f2
85 changed files with 17701 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import { z } from 'zod';
/**
* Zentrale, typsichere Konfiguration der Management-Plattform.
* Alle Werte stammen aus Umgebungsvariablen und werden beim Start
* einmalig validiert (fail-fast bei fehlerhafter Konfiguration).
*/
export type NodeEnvironment = 'development' | 'test' | 'production';
export interface DatabaseConfig {
readonly url: string;
}
export interface SecurityConfig {
readonly sessionTtlMinutes: number;
readonly cookieSecure: boolean;
readonly behindProxy: boolean;
readonly loginMaxAttempts: number;
readonly loginLockoutMinutes: number;
readonly loginRateLimitAttempts: number;
readonly loginRateLimitWindowMinutes: number;
}
export interface AdminSeedConfig {
readonly username: string;
readonly email: string;
readonly password: string;
}
export interface AppConfig {
readonly nodeEnv: NodeEnvironment;
readonly port: number;
readonly database: DatabaseConfig;
readonly security: SecurityConfig;
readonly adminSeed: AdminSeedConfig;
}
const booleanFromString = z
.enum(['true', 'false'])
.default('false')
.transform((value) => value === 'true');
const environmentSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']).default('production'),
PORT: z.coerce.number().int().positive().default(3000),
DATABASE_URL: z.string().min(1, 'DATABASE_URL ist erforderlich'),
SESSION_TTL_MINUTES: z.coerce.number().int().positive().default(120),
COOKIE_SECURE: booleanFromString,
BEHIND_PROXY: booleanFromString,
LOGIN_MAX_ATTEMPTS: z.coerce.number().int().positive().default(5),
LOGIN_LOCKOUT_MINUTES: z.coerce.number().int().positive().default(15),
LOGIN_RATE_LIMIT_ATTEMPTS: z.coerce.number().int().positive().default(10),
LOGIN_RATE_LIMIT_WINDOW_MINUTES: z.coerce.number().int().positive().default(5),
ADMIN_USERNAME: z.string().trim().min(3).max(100),
ADMIN_EMAIL: z.string().trim().email(),
ADMIN_PASSWORD: z.string().min(10, 'ADMIN_PASSWORD muss mindestens 10 Zeichen lang sein').max(200),
});
/** Lädt und validiert die Konfiguration aus den Umgebungsvariablen. */
export function loadConfiguration(): AppConfig {
const environment = environmentSchema.parse(process.env);
return {
nodeEnv: environment.NODE_ENV,
port: environment.PORT,
database: { url: environment.DATABASE_URL },
security: {
sessionTtlMinutes: environment.SESSION_TTL_MINUTES,
cookieSecure: environment.COOKIE_SECURE,
behindProxy: environment.BEHIND_PROXY,
loginMaxAttempts: environment.LOGIN_MAX_ATTEMPTS,
loginLockoutMinutes: environment.LOGIN_LOCKOUT_MINUTES,
loginRateLimitAttempts: environment.LOGIN_RATE_LIMIT_ATTEMPTS,
loginRateLimitWindowMinutes: environment.LOGIN_RATE_LIMIT_WINDOW_MINUTES,
},
adminSeed: {
username: environment.ADMIN_USERNAME,
email: environment.ADMIN_EMAIL,
password: environment.ADMIN_PASSWORD,
},
};
}