Zeitplan in der Oberflaeche einstellbar

Takt und Schalter der beiden Abgleiche standen in der Umgebung und liessen
sich nur mit einem Neustart aendern. Jetzt stehen sie unter Verwaltung ->
Zeitplan, je Lauf einzeln: ob er automatisch laeuft, in welchem Abstand, beim
Kaeufe-Abgleich zusaetzlich der seltenere Takt fuer ruhende Konten und ab
wann ein Konto als ruhend gilt, beim Forumslauf die Stunde, vor der nicht
gelaufen wird.

Die Abstaende stehen in Minuten - damit laesst sich alles ausdruecken -, und
daneben steht, was das in Stunden bedeutet, damit niemand im Kopf rechnet.
Unter einer Viertelstunde geht nicht: beide Abgleiche greifen auf Server zu,
die der Community gehoeren.

Aenderungen greifen sofort, ohne Neustart. Die Vorgaben sind die bisherigen
Werte, sie stehen in der Migration.

SCHEDULE_ENABLED und FORUM_SCAN_HOUR entfallen damit.
This commit is contained in:
2026-09-21 13:25:56 +02:00
parent db37d3388a
commit 6094e4eaef
14 changed files with 658 additions and 168 deletions
+26 -7
View File
@@ -267,14 +267,33 @@ export async function adminRoutes(app: FastifyInstance): Promise<void> {
// --- Audit-Log ---
/** Stand der wiederkehrenden Abgleiche. */
/** Einstellungen und Stand der wiederkehrenden Abgleiche. */
app.get('/api/admin/schedule', async () => {
const { listRuns } = await import('../services/schedule.js');
return {
enabled: env.SCHEDULE_ENABLED,
forumHour: env.FORUM_SCAN_HOUR,
runs: await listRuns(),
};
const { listRuns, listSettings } = await import('../services/schedule.js');
const [settings, runs] = await Promise.all([listSettings(), listRuns()]);
return { settings, runs };
});
app.patch('/api/admin/schedule/:name', async (request) => {
const { updateSetting, LAEUFE } = await import('../services/schedule.js');
const params = parseWith(
z.object({ name: z.enum(['gextension', 'forum']) }),
request.params,
);
const body = parseWith(
z.object({
enabled: z.boolean().optional(),
intervalMinutes: z.number().int().optional(),
idleIntervalMinutes: z.number().int().nullable().optional(),
idleAfterDays: z.number().int().nullable().optional(),
onlyAfterHour: z.number().int().nullable().optional(),
}),
request.body,
);
if (!LAEUFE.includes(params.name)) throw notFound('Lauf');
return updateSetting(params.name, body, contextOf(request));
});
app.get('/api/admin/audit', async (request) => {