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
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>
90 lines
2.7 KiB
Python
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()
|