Files
breakpilot-compliance/backend-compliance/scripts/seed_template_rules.py
T
Benjamin Admin bb183b0e75
CI / detect-changes (push) Successful in 12s
CI / branch-name (push) Has been skipped
CI / test-python-backend (push) Successful in 33s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 19s
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 7s
CI / validate-canonical-controls (push) Successful in 16s
CI / loc-budget (push) Failing after 18s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m27s
CI / test-go (push) Failing after 46s
CI / iace-gt-coverage (push) Successful in 25s
feat(template-rules): backend foundation for profile-based document recommendations
Introduces the sustainable backend replacement for the hardcoded inline rules in
admin-compliance/app/sdk/document-generator/templateRecommendations.ts.

What's in this commit (Phase 1.1 - 1.5 of the rustling-yawning-boot plan):

- Migration 147: 4 new tables
  - compliance_template_rules (rule shell, document_type, current_version_id)
  - compliance_template_rule_versions (lifecycle, JSONB conditions,
    source_citation, change_summary, approval timestamps)
  - compliance_template_rule_approvals (audit trail)
  - compliance_tenant_rule_overrides (per-tenant classification overrides)
  Plus partial unique index for "only one is_live=1 version per rule".

- SQLAlchemy models: TemplateRuleDB, TemplateRuleVersionDB,
  TemplateRuleApprovalDB, TenantRuleOverrideDB (compliance/db/).

- Pydantic schemas (compliance/schemas/template_rule.py): full request/response
  set including RecommendationRequest/Result with reasons and override tracking.

- TemplateRuleService (compliance/services/): CRUD + Lifecycle transitions
  (submit_for_review/approve/publish/reject) following legal_document_service.py
  pattern with _transition() helper and approval audit trail. Plus tenant
  override upsert.

- RecommendationService: condition evaluator (eq, neq, in, not_in, gte/lte/gt/lt,
  exists, truthy) over JSONB conditions, override application, reason generation
  for human-readable explanations in workspace UI.

- 18 FastAPI routes in compliance/api/template_rule_routes.py covering rule CRUD,
  version lifecycle, override management and POST /recommend evaluation endpoint.

- Seed data: 33 initial rules ported from templateRecommendations.ts in
  compliance/data/template_rule_seed_data.py, written as published versions
  on first seed run. Idempotent via rule_key.

Phase 1.6 (pytest suite) and Phase 2 (editorial UI in admin-compliance) follow
in separate commits.

[migration-approved]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-06 23:13:50 +02:00

90 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""
Seed-Runner: legt die in ``compliance.data.template_rule_seed_data.SEED_RULES``
definierten Regeln als published Versionen in ``compliance_template_rules`` an.
Idempotent über ``rule_key`` — wiederholtes Ausführen erzeugt keine Duplikate.
Quellen-Citation = ``rationale`` als Default (anwaltlich zu prüfen).
"""
from __future__ import annotations
import os
import sys
from datetime import datetime, timezone
# Pfad-Setup für Standalone-Ausführung
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from classroom_engine.database import SessionLocal # noqa: E402
from compliance.data.template_rule_seed_data import SEED_RULES # noqa: E402
from compliance.db.template_rule_models import ( # noqa: E402
TemplateRuleDB,
TemplateRuleVersionDB,
TemplateRuleApprovalDB,
)
def seed() -> None:
db = SessionLocal()
try:
created = 0
skipped = 0
for entry in SEED_RULES:
existing = (
db.query(TemplateRuleDB)
.filter(TemplateRuleDB.rule_key == entry["rule_key"])
.first()
)
if existing:
skipped += 1
continue
rule = TemplateRuleDB(
rule_key=entry["rule_key"],
document_type=entry["document_type"],
title=entry["title"],
)
db.add(rule)
db.flush()
now = datetime.now(timezone.utc)
version = TemplateRuleVersionDB(
rule_id=rule.id,
version_number=1,
status="published",
is_live=1,
classification=entry["classification"],
conditions=entry["conditions"],
source_citation=entry.get("rationale", "TODO — anwaltlich zu pruefen"),
rationale=entry.get("rationale"),
change_summary="Initial-Seed der Inline-Regeln",
created_by="seed",
submitted_by="seed",
submitted_at=now,
approved_by="seed",
approved_at=now,
published_by="seed",
published_at=now,
)
db.add(version)
db.flush()
rule.current_version_id = version.id
for action in ("created", "submitted", "approved", "published"):
db.add(TemplateRuleApprovalDB(
version_id=version.id, action=action, approver="seed",
))
created += 1
db.commit()
print(f"OK created={created} skipped={skipped} (already present)")
finally:
db.close()
if __name__ == "__main__":
seed()