feat: DSFA vollständiges DB-Schema + PDF-Ingest + Tests
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 36s
CI / test-python-backend-compliance (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 22s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 36s
CI / test-python-backend-compliance (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 22s
- Migration 030: alle fehlenden Spalten für compliance_dsfas (Sections 0-7) flat fields: processing_description, legal_basis, dpo_*, authority_*, ... JSONB arrays: risks, mitigations, wp248_criteria_met, ai_trigger_ids, ... JSONB objects: section_progress, threshold_analysis, review_schedule, metadata - dsfa_routes.py: DSFACreate/DSFAUpdate erweitert (60+ neue Optional-Felder) _dsfa_to_response: alle neuen Felder mit safe _get() Helper PUT-Handler: vollständige JSONB_FIELDS-Liste (22 Felder) - Tests: 101 (+49) Tests — TestAIUseCaseModules + TestDSFAFullSchema - ingest-dsfa-bundesland.sh: KNOWN_PDF_URLS (15 direkte URLs), download_pdfs() find_pdf_for_state() Helper, PDF-first mit Text-Fallback in ingest_all() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -77,18 +77,80 @@ declare -A STATE_NAMES=(
|
||||
["th"]="Thüringen"
|
||||
)
|
||||
|
||||
# PDF-URLs der Muss-Listen (direkte Download-Links)
|
||||
declare -A PDF_URLS=(
|
||||
["bw_privat"]="https://www.baden-wuerttemberg.datenschutz.de/dsfa-muss-liste/"
|
||||
["hh_beide"]="https://datenschutz.hamburg.de/infothek/datenschutz-folgenabschaetzung"
|
||||
["nw_oeffentlich"]="https://www.ldi.nrw.de/datenschutz/datenschutz-folgenabschaetzung"
|
||||
["ni_beide"]="https://lfd.niedersachsen.de/startseite/themen/datenschutzfolgenabschaetzung/"
|
||||
["be_beide"]="https://www.datenschutz-berlin.de/themen/verarbeitungen-mit-hohem-risiko/datenschutz-folgenabschaetzung/"
|
||||
["bfdi_liste"]="https://www.bfdi.bund.de/DE/Fachthemen/Inhalte/Datenschutzbehoerden/DSFA.html"
|
||||
# Direkte PDF-Download-URLs der Behörden-Muss-Listen (Art. 35 Abs. 4 DSGVO)
|
||||
# Quellen: DSFA_AUTHORITY_RESOURCES in admin-compliance/lib/sdk/dsfa/types.ts
|
||||
declare -A KNOWN_PDF_URLS=(
|
||||
["bfdi_public"]="https://www.bfdi.bund.de/SharedDocs/Downloads/DE/Muster/Liste_VerarbeitungsvorgaengeArt35.pdf"
|
||||
["bw_privat"]="https://www.baden-wuerttemberg.datenschutz.de/wp-content/uploads/2018/05/Liste-von-Verarbeitungsvorg%C3%A4ngen-nach-Art.-35-Abs.-4-DS-GVO-LfDI-BW.pdf"
|
||||
["be_public"]="https://www.datenschutz-berlin.de/fileadmin/user_upload/pdf/dokumente/2018-BlnBDI_DSFA-oeffentlich.pdf"
|
||||
["be_privat"]="https://www.datenschutz-berlin.de/fileadmin/user_upload/pdf/dokumente/2018-BlnBDI_DSFA-nicht-oeffentlich.pdf"
|
||||
["bb_public"]="https://www.lda.brandenburg.de/sixcms/media.php/9/DSFA-Liste_%C3%B6ffentlicher_Bereich.pdf"
|
||||
["bb_privat"]="https://www.lda.brandenburg.de/sixcms/media.php/9/DSFA-Liste_nicht_%C3%B6ffentlicher_Bereich.pdf"
|
||||
["hb_public"]="https://www.datenschutz.bremen.de/sixcms/media.php/13/Liste%20von%20Verarbeitungsvorg%C3%A4ngen%20nach%20Artikel%2035.pdf"
|
||||
["hb_privat"]="https://www.datenschutz.bremen.de/sixcms/media.php/13/DSFA%20Muss-Liste%20LfDI%20HB.pdf"
|
||||
["hh_public"]="https://datenschutz-hamburg.de/fileadmin/user_upload/HmbBfDI/Datenschutz/Informationen/Liste_Art_35-4_DSGVO_HmbBfDI-oeffentlicher_Bereich_v2.0a.pdf"
|
||||
["hh_privat"]="https://datenschutz-hamburg.de/fileadmin/user_upload/HmbBfDI/Datenschutz/Informationen/DSFA_Muss-Liste_fuer_den_nicht-oeffentlicher_Bereich_-_Stand_17.10.2018.pdf"
|
||||
["mv_public"]="https://www.datenschutz-mv.de/static/DS/Dateien/DS-GVO/HilfsmittelzurUmsetzung/MV-DSFA-Muss-Liste-Oeffentlicher-Bereich.pdf"
|
||||
["ni_public"]="https://www.lfd.niedersachsen.de/download/134414/DSFA_Muss-Liste_fuer_den_oeffentlichen_Bereich.pdf"
|
||||
["ni_privat"]="https://www.lfd.niedersachsen.de/download/131098/Liste_von_Verarbeitungsvorgaengen_nach_Art._35_Abs._4_DS-GVO.pdf"
|
||||
["sl_privat"]="https://www.datenschutz.saarland.de/fileadmin/user_upload/uds/alle_Dateien_und_Ordner_bis_2025/Download/dsfa_muss_liste_dsk_de.pdf"
|
||||
["st_public"]="https://datenschutz.sachsen-anhalt.de/fileadmin/Bibliothek/Landesaemter/LfD/Informationen/Internationales/Datenschutz-Grundverordnung/Liste_DSFA/Art-35-Liste-oeffentlicher_Bereich.pdf"
|
||||
["st_privat"]="https://datenschutz.sachsen-anhalt.de/fileadmin/Bibliothek/Landesaemter/LfD/Informationen/Internationales/Datenschutz-Grundverordnung/Liste_DSFA/Art-35-Liste-nichtoeffentlicher_Bereich.pdf"
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# Phase 2: Text-Zusammenfassungen (für Bundesländer ohne direkte PDFs)
|
||||
# Phase 2a: PDF-Downloads
|
||||
# =============================================================================
|
||||
|
||||
download_pdfs() {
|
||||
log "Lade Behörden-PDFs herunter (${#KNOWN_PDF_URLS[@]} URLs)..."
|
||||
local success=0
|
||||
local failed=0
|
||||
|
||||
for key in "${!KNOWN_PDF_URLS[@]}"; do
|
||||
local url="${KNOWN_PDF_URLS[$key]}"
|
||||
local outfile="$DOWNLOAD_DIR/${key}.pdf"
|
||||
|
||||
if [[ -f "$outfile" && $(wc -c < "$outfile") -gt 1000 ]]; then
|
||||
ok "PDF bereits vorhanden: $key"
|
||||
((success++)) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
curl -sk --max-time 30 -L -A "BreakPilot-Compliance/1.0" -o "$outfile" "$url" 2>/dev/null
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -eq 0 && -f "$outfile" && $(wc -c < "$outfile") -gt 1000 ]]; then
|
||||
ok "PDF heruntergeladen: $key"
|
||||
((success++)) || true
|
||||
else
|
||||
warn "PDF fehlgeschlagen: $key — nutze Text-Fallback"
|
||||
rm -f "$outfile"
|
||||
((failed++)) || true
|
||||
fi
|
||||
done
|
||||
|
||||
log "PDF-Downloads: $success OK, $failed fehlgeschlagen"
|
||||
}
|
||||
|
||||
# Gibt den Pfad zur ersten vorhandenen PDF-Datei für einen State-ID-Prefix zurück.
|
||||
# Gibt leeren String zurück, wenn keine PDF gefunden.
|
||||
find_pdf_for_state() {
|
||||
local state_id="$1"
|
||||
for key in "${!KNOWN_PDF_URLS[@]}"; do
|
||||
if [[ "$key" == "${state_id}_"* || "$key" == "${state_id}" ]]; then
|
||||
local pdf="$DOWNLOAD_DIR/${key}.pdf"
|
||||
if [[ -f "$pdf" && $(wc -c < "$pdf") -gt 1000 ]]; then
|
||||
echo "$pdf"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Phase 2b: Text-Zusammenfassungen (für Bundesländer ohne direkte PDFs)
|
||||
# =============================================================================
|
||||
|
||||
create_text_summaries() {
|
||||
@@ -331,32 +393,40 @@ ingest_all() {
|
||||
log "Starte Ingest in Corpus: $COLLECTION"
|
||||
log "RAG-URL: $RAG_URL"
|
||||
|
||||
# WP248-Dokument (für alle Bundesländer relevant)
|
||||
# WP248-Dokument (für alle Bundesländer relevant — kein PDF verfügbar)
|
||||
ingest_document \
|
||||
"$DOWNLOAD_DIR/dsfa_wpk248_kriterien.txt" \
|
||||
"wp248_rev01" "EU" "Article 29 Working Party / EDPB" "leitlinie"
|
||||
|
||||
# BfDI
|
||||
ingest_document \
|
||||
"$DOWNLOAD_DIR/bfdi_muss_liste.txt" \
|
||||
"muss_liste_bfdi" "Bund" "BfDI" "muss_liste"
|
||||
# BfDI — PDF bevorzugen, Text als Fallback
|
||||
local bfdi_pdf
|
||||
bfdi_pdf=$(find_pdf_for_state "bfdi")
|
||||
if [[ -n "$bfdi_pdf" ]]; then
|
||||
ingest_document "$bfdi_pdf" "muss_liste_bfdi" "Bund" "BfDI" "muss_liste"
|
||||
else
|
||||
ingest_document "$DOWNLOAD_DIR/bfdi_muss_liste.txt" "muss_liste_bfdi" "Bund" "BfDI" "muss_liste"
|
||||
fi
|
||||
|
||||
# Baden-Württemberg
|
||||
ingest_document \
|
||||
"$DOWNLOAD_DIR/bw_dsfa_anforderungen.txt" \
|
||||
"muss_liste_bw" "Baden-Württemberg" "LfDI BW" "muss_liste"
|
||||
# Baden-Württemberg — PDF bevorzugen, Text als Fallback
|
||||
local bw_pdf
|
||||
bw_pdf=$(find_pdf_for_state "bw")
|
||||
if [[ -n "$bw_pdf" ]]; then
|
||||
ingest_document "$bw_pdf" "muss_liste_bw" "Baden-Württemberg" "LfDI BW" "muss_liste"
|
||||
else
|
||||
ingest_document "$DOWNLOAD_DIR/bw_dsfa_anforderungen.txt" "muss_liste_bw" "Baden-Württemberg" "LfDI BW" "muss_liste"
|
||||
fi
|
||||
|
||||
# Bayern
|
||||
# Bayern — kein direktes PDF bekannt, Text
|
||||
ingest_document \
|
||||
"$DOWNLOAD_DIR/by_dsfa_anforderungen.txt" \
|
||||
"muss_liste_by" "Bayern" "LDA Bayern" "muss_liste"
|
||||
|
||||
# NRW
|
||||
# NRW — kein direktes PDF bekannt, Text
|
||||
ingest_document \
|
||||
"$DOWNLOAD_DIR/nrw_dsfa_anforderungen.txt" \
|
||||
"muss_liste_nw" "Nordrhein-Westfalen" "LDI NRW" "muss_liste"
|
||||
|
||||
# Weitere Bundesländer aus DSFA_AUTHORITY_RESOURCES-Daten (als Text)
|
||||
# Weitere Bundesländer — PDF bevorzugen, Text als Fallback
|
||||
for state_id in be bb hb hh he mv ni rp sl sn st sh th; do
|
||||
local txt_file="$DOWNLOAD_DIR/${state_id}_dsfa_anforderungen.txt"
|
||||
if [[ ! -f "$txt_file" ]]; then
|
||||
@@ -383,12 +453,24 @@ Quelle: DSK-Positionspapier, WP248, Art. 35 Abs. 4 DSGVO
|
||||
EOF
|
||||
fi
|
||||
|
||||
ingest_document \
|
||||
"$txt_file" \
|
||||
"muss_liste_${state_id}" \
|
||||
"${STATE_NAMES[$state_id]:-$state_id}" \
|
||||
"${AUTHORITY_LABELS[$state_id]:-Datenschutzbehörde $state_id}" \
|
||||
"muss_liste"
|
||||
# PDF bevorzugen, Text als Fallback
|
||||
local state_pdf
|
||||
state_pdf=$(find_pdf_for_state "$state_id")
|
||||
if [[ -n "$state_pdf" ]]; then
|
||||
ingest_document \
|
||||
"$state_pdf" \
|
||||
"muss_liste_${state_id}" \
|
||||
"${STATE_NAMES[$state_id]:-$state_id}" \
|
||||
"${AUTHORITY_LABELS[$state_id]:-Datenschutzbehörde $state_id}" \
|
||||
"muss_liste"
|
||||
else
|
||||
ingest_document \
|
||||
"$txt_file" \
|
||||
"muss_liste_${state_id}" \
|
||||
"${STATE_NAMES[$state_id]:-$state_id}" \
|
||||
"${AUTHORITY_LABELS[$state_id]:-Datenschutzbehörde $state_id}" \
|
||||
"muss_liste"
|
||||
fi
|
||||
done
|
||||
|
||||
log "Ingest abgeschlossen"
|
||||
@@ -427,16 +509,17 @@ main() {
|
||||
log "Download-Dir: $DOWNLOAD_DIR"
|
||||
log "Skip-Download: $SKIP_DOWNLOAD"
|
||||
|
||||
# Schritt 1: Text-Zusammenfassungen erstellen (immer)
|
||||
# Schritt 1: Text-Zusammenfassungen erstellen (immer als Fallback)
|
||||
create_text_summaries
|
||||
|
||||
# Schritt 2: PDFs herunterladen (wenn nicht --skip-download)
|
||||
# Schritt 2: PDFs herunterladen (wenn nicht --skip-download oder --only-text)
|
||||
if [[ "$SKIP_DOWNLOAD" == false && "$ONLY_TEXT" == false ]]; then
|
||||
log "PDF-Downloads übersprungen (direkte URLs zu Behörden-PDFs variieren) – nutze Text-Dateien"
|
||||
log "Tipp: Laden Sie PDFs manuell herunter und legen Sie sie in $DOWNLOAD_DIR ab"
|
||||
download_pdfs
|
||||
else
|
||||
log "PDF-Downloads übersprungen (--skip-download oder --only-text gesetzt)"
|
||||
fi
|
||||
|
||||
# Schritt 3: Ingest
|
||||
# Schritt 3: Ingest (PDF bevorzugt, Text als Fallback)
|
||||
ingest_all
|
||||
|
||||
# Schritt 4: Verifikation
|
||||
|
||||
Reference in New Issue
Block a user