HTTP-Endpunkte und Anwendungsaufbau
Eingaben werden mit zod validiert, jede aendernde Aktion schreibt ins Audit-Log. Beim ersten Start entsteht ein Administrator samt Startwerten fuer die Produkterkennung; solange ein Erstpasswort gilt, bleiben schreibende Wege bis auf den Passwortwechsel gesperrt. Nicht-API-Pfade fallen auf die SPA zurueck, damit Deep-Links funktionieren.
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { ProductTarget } from '@prisma/client';
|
||||
import { prisma } from './db.js';
|
||||
import { env } from './env.js';
|
||||
import { hashPassword } from './auth/password.js';
|
||||
|
||||
// Startpunkte fuer die Produkterkennung beim Import. Jederzeit im Admin-Bereich
|
||||
// anpassbar, sobald die echten Produktnamen bekannt sind.
|
||||
const DEFAULT_MAPPINGS = [
|
||||
{ matchPattern: 'cc-paket', target: ProductTarget.CC_PACKAGE, priority: 10 },
|
||||
{ matchPattern: 'cc paket', target: ProductTarget.CC_PACKAGE, priority: 11 },
|
||||
{ matchPattern: 'custom character', target: ProductTarget.CC_PACKAGE, priority: 12 },
|
||||
{ matchPattern: 'redesign', target: ProductTarget.REDESIGN_PACKAGE, priority: 20 },
|
||||
];
|
||||
|
||||
export interface BootstrapResult {
|
||||
createdAdmin: { username: string; password: string } | null;
|
||||
createdMappings: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Legt beim allerersten Start einen Administrator an. Ohne gesetztes
|
||||
* Bootstrap-Passwort wird eines erzeugt und einmalig ins Log geschrieben.
|
||||
*/
|
||||
export async function bootstrap(log: {
|
||||
info: (msg: string) => void;
|
||||
warn: (msg: string) => void;
|
||||
}): Promise<BootstrapResult> {
|
||||
const result: BootstrapResult = { createdAdmin: null, createdMappings: 0 };
|
||||
|
||||
const userCount = await prisma.user.count();
|
||||
if (userCount === 0) {
|
||||
const password = env.BOOTSTRAP_ADMIN_PASSWORD ?? randomBytes(12).toString('base64url');
|
||||
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
username: env.BOOTSTRAP_ADMIN_USER,
|
||||
passwordHash: await hashPassword(password),
|
||||
role: 'ADMIN',
|
||||
mustChangePassword: true,
|
||||
},
|
||||
});
|
||||
|
||||
result.createdAdmin = { username: env.BOOTSTRAP_ADMIN_USER, password };
|
||||
|
||||
log.warn('─'.repeat(60));
|
||||
log.warn(`Administrator angelegt: ${env.BOOTSTRAP_ADMIN_USER}`);
|
||||
if (!env.BOOTSTRAP_ADMIN_PASSWORD) {
|
||||
log.warn(`Einmal-Passwort: ${password}`);
|
||||
}
|
||||
log.warn('Das Passwort muss bei der ersten Anmeldung geaendert werden.');
|
||||
log.warn('─'.repeat(60));
|
||||
}
|
||||
|
||||
const mappingCount = await prisma.productMapping.count();
|
||||
if (mappingCount === 0) {
|
||||
const created = await prisma.productMapping.createMany({ data: DEFAULT_MAPPINGS });
|
||||
result.createdMappings = created.count;
|
||||
log.info(`${created.count} Produkt-Mappings als Startwerte angelegt`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user