Import nicht an der JSON-Ablage scheitern lassen

Im Container lief der Import bis zum Ende der Auswertung und brach dann
mit EACCES beim Schreiben der ersten JSON-Datei ab. Weil die Ablage vor
dem Datenbankschreiben stand, wurde keine einzige Erklärung importiert.

Reihenfolge umgedreht: Erst die Datenbank, danach die JSON-Dateien. Ein
Fehler dabei wird einmal gemeldet und beendet nur die Ablage, nicht den
Lauf. Neu ist --no-json, das sie ganz abschaltet.

Getestet: Normalfall schreibt 120 Dateien, simulierter Schreibfehler
meldet ihn und importiert vollständig weiter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Weapie 2026-09-08 10:02:32 +02:00
parent d76ff12fbe
commit ae752322f0
2 changed files with 53 additions and 10 deletions

View File

@ -153,7 +153,7 @@ Massenimporte gibt es zwei Wege:
| Befehl | Zweck | | Befehl | Zweck |
|---|---| |---|---|
| `npm run import-csv` | **Führender Weg:** DSE-Gesamtliste einlesen (`--dry-run`, `--prune`) | | `npm run import-csv` | **Führender Weg:** DSE-Gesamtliste einlesen (`--dry-run`, `--prune`, `--no-json`) |
| `npm run check-completeness` | Berichtet fehlende Pflichtangaben (`--list`) | | `npm run check-completeness` | Berichtet fehlende Pflichtangaben (`--list`) |
| `npm run compare-csv-pdf` | Gesamtliste gegen die alten Merkblatt-PDFs abgleichen (`--detail`) | | `npm run compare-csv-pdf` | Gesamtliste gegen die alten Merkblatt-PDFs abgleichen (`--detail`) |
| `npm run import-policy -- data/policies/<datei>.json` | Einzelne Erklärung aus JSON importieren (`--update` überschreibt) | | `npm run import-policy -- data/policies/<datei>.json` | Einzelne Erklärung aus JSON importieren (`--update` überschreibt) |
@ -184,6 +184,12 @@ Zwei Angaben stehen nicht in der Liste und werden ergänzt:
Werte wie „entfällt“ in der Spalte Datenquelle gelten als leer – sonst würde die Werte wie „entfällt“ in der Spalte Datenquelle gelten als leer – sonst würde die
Art.-14-Pflicht zu den Datenkategorien fälschlich ausgelöst. Art.-14-Pflicht zu den Datenkategorien fälschlich ausgelöst.
Die Datenbank wird zuerst geschrieben, die JSON-Dateien danach. Sie dienen nur
der Nachvollziehbarkeit im Repository – schlägt das Schreiben fehl, etwa weil
das Verzeichnis im Container nicht beschreibbar ist, meldet der Lauf das und
der Import bleibt trotzdem vollständig. Mit `--no-json` lässt sich die Ablage
ganz abschalten; im Container ist das der Normalfall.
Der PDF-Import (`scripts/lib/pdf-policy.js`) bleibt für die alten Merkblätter Der PDF-Import (`scripts/lib/pdf-policy.js`) bleibt für die alten Merkblätter
erhalten und dient als Gegenprobe. erhalten und dient als Gegenprobe.

View File

@ -2,8 +2,9 @@
* Importiert die DSE-Gesamtliste des Amtes Leezen (Excel-Export, CSV). * Importiert die DSE-Gesamtliste des Amtes Leezen (Excel-Export, CSV).
* *
* node scripts/import-csv.js --dry-run nur prüfen und berichten * node scripts/import-csv.js --dry-run nur prüfen und berichten
* node scripts/import-csv.js JSON schreiben und importieren * node scripts/import-csv.js importieren und JSON ablegen
* node scripts/import-csv.js --prune zusätzlich verwaiste Datensätze löschen * node scripts/import-csv.js --prune zusätzlich verwaiste Datensätze löschen
* node scripts/import-csv.js --no-json nur in die Datenbank (z. B. im Container)
* *
* Die Liste ist führend für die Angaben je Verarbeitungstätigkeit. Die für alle * Die Liste ist führend für die Angaben je Verarbeitungstätigkeit. Die für alle
* Erklärungen gleichen Bausteine kommen aus den zentralen Standardtexten und * Erklärungen gleichen Bausteine kommen aus den zentralen Standardtexten und
@ -114,6 +115,7 @@ function addressBlock(value) {
async function main() { async function main() {
const dryRun = process.argv.includes("--dry-run") const dryRun = process.argv.includes("--dry-run")
const prune = process.argv.includes("--prune") const prune = process.argv.includes("--prune")
const ohneJson = process.argv.includes("--no-json")
if (!fs.existsSync(CSV)) { if (!fs.existsSync(CSV)) {
console.error(`Liste nicht gefunden: ${CSV}`) console.error(`Liste nicht gefunden: ${CSV}`)
@ -264,17 +266,26 @@ async function main() {
return return
} }
fs.mkdirSync(JSON_DIR, { recursive: true }) // Die JSON-Ablage ist nur zur Nachvollziehbarkeit im Repository gedacht.
// Im Container liegt sie im Volume und ist je nach Einhängung nicht
// beschreibbar – das darf den eigentlichen Import nicht verhindern.
let jsonZiel = ohneJson ? null : JSON_DIR
if (jsonZiel) {
try {
fs.mkdirSync(jsonZiel, { recursive: true })
} catch (error) {
console.warn(`Hinweis: ${jsonZiel} nicht anlegbar (${error.code}) – JSON-Ablage wird übersprungen.`)
jsonZiel = null
}
}
let neu = 0 let neu = 0
let aktualisiert = 0 let aktualisiert = 0
let geschrieben = 0
let jsonFehler = null
for (const { nummer, daten, overrides, bestehend } of aufbereitet) { for (const { nummer, daten, overrides, bestehend } of aufbereitet) {
fs.writeFileSync( // Datenbank zuerst: Sie ist der Zweck des Laufs.
path.join(JSON_DIR, `${daten.slug}.json`),
JSON.stringify({ _quelle: `DSE_Gesamtliste_Amt_Leezen.CSV · ${nummer}`, _abweichungen: overrides, ...daten }, null, 2),
"utf8"
)
if (bestehend) { if (bestehend) {
await prisma.privacyPolicy.update({ where: { id: bestehend.id }, data: daten }) await prisma.privacyPolicy.update({ where: { id: bestehend.id }, data: daten })
aktualisiert++ aktualisiert++
@ -282,6 +293,21 @@ async function main() {
await prisma.privacyPolicy.create({ data: daten }) await prisma.privacyPolicy.create({ data: daten })
neu++ neu++
} }
if (!jsonZiel) continue
try {
fs.writeFileSync(
path.join(jsonZiel, `${daten.slug}.json`),
JSON.stringify({ _quelle: `DSE_Gesamtliste_Amt_Leezen.CSV · ${nummer}`, _abweichungen: overrides, ...daten }, null, 2),
"utf8"
)
geschrieben++
} catch (error) {
// Einmal melden, dann nicht weiter versuchen
jsonFehler = error
jsonZiel = null
}
} }
console.log(`Neu angelegt: ${neu}`) console.log(`Neu angelegt: ${neu}`)
@ -296,7 +322,18 @@ async function main() {
console.log(`Unberührt: ${verwaist.length} (mit --prune entfernen)`) console.log(`Unberührt: ${verwaist.length} (mit --prune entfernen)`)
} }
console.log(`JSON-Dateien: data/policies/`) if (ohneJson) {
console.log(`JSON-Ablage: übersprungen (--no-json)`)
} else if (jsonFehler) {
console.log(`JSON-Dateien: ${geschrieben} von ${aufbereitet.length} geschrieben`)
console.warn("")
console.warn(`WARNUNG: JSON-Ablage abgebrochen – ${jsonFehler.code} bei ${jsonFehler.path}`)
console.warn("Der Import in die Datenbank ist davon unberührt und vollständig.")
console.warn("Die JSON-Dateien dienen nur der Nachvollziehbarkeit im Repository;")
console.warn("im Container lassen sie sich mit --no-json ganz abschalten.")
} else {
console.log(`JSON-Dateien: ${geschrieben} in data/policies/`)
}
} }
main() main()