feat(admin): add system logs viewer, tabbed data management, fix AT20 sync

This commit is contained in:
Matthias Hochmeister
2026-04-18 18:31:22 +02:00
parent 0a6377a64f
commit 0a5402a9e5
7 changed files with 526 additions and 205 deletions

View File

@@ -289,6 +289,41 @@ export async function syncToDatabase(
}
}
/**
* Scans the ausbildung table for AT20 courses with erfolgscode = 'mit Erfolg'
* and upserts atemschutz_traeger records accordingly.
* Must run AFTER syncToDatabase() has committed — i.e. on the same pool, outside the transaction.
*/
export async function syncAT20ToAtemschutz(pool: Pool): Promise<void> {
// First, log a sample of what's actually stored so we can verify the filter strings match.
const sample = await pool.query<{ kurs_kurzbezeichnung: string | null; erfolgscode: string | null; count: string }>(
`SELECT kurs_kurzbezeichnung, erfolgscode, COUNT(*)::text AS count
FROM ausbildung
WHERE kurs_kurzbezeichnung IS NOT NULL
GROUP BY kurs_kurzbezeichnung, erfolgscode
ORDER BY count DESC
LIMIT 20`
);
log(`AT20-Sync: kurs_kurzbezeichnung/erfolgscode distribution (top 20):`);
for (const row of sample.rows) {
log(` kurzbezeichnung=${JSON.stringify(row.kurs_kurzbezeichnung)} erfolgscode=${JSON.stringify(row.erfolgscode)} count=${row.count}`);
}
const result = await pool.query<{ rowCount: number }>(
`INSERT INTO atemschutz_traeger (id, user_id, atemschutz_lehrgang, lehrgang_datum)
SELECT uuid_generate_v4(), a.user_id, true, MIN(a.kurs_datum)
FROM ausbildung a
WHERE TRIM(a.kurs_kurzbezeichnung) = 'AT20'
AND TRIM(a.erfolgscode) = 'mit Erfolg'
GROUP BY a.user_id
ON CONFLICT (user_id) DO UPDATE
SET atemschutz_lehrgang = true,
lehrgang_datum = COALESCE(atemschutz_traeger.lehrgang_datum, EXCLUDED.lehrgang_datum),
updated_at = NOW()`
);
log(`AT20-Sync: ${result.rowCount ?? 0} atemschutz_traeger rows upserted`);
}
async function syncAusbildungen(
client: PoolClient,
ausbildungen: FdiskAusbildung[],