Add _assertPermission() that checks role_permissions table for
specific permission keys (super_admin bypasses). Wire it into
CreateRole (rbac:roles:create), UpdateRole (rbac:roles:update),
and DeleteRole (rbac:roles:delete). Previously only the coarse
can_manage role check was enforced, making the permission grants
in role_permissions purely cosmetic for these endpoints.
- Add region column to leaudit_documents + LeauditDocument model
- AuditServiceImpl: read region from document.region, not APP_REGION
- RuleServiceImpl: ListBindings/CreateBinding accept Region parameter
- RuleBindingCreateDTO: add region field
- RuleController: pass region from query param/DTO to service
- APP_REGION removed from binding queries; region flows from document
Region is now per-document: each document carries its region at upload
time, and rules are matched to the document's region at run time.
- DB: add region column to leaudit_rule_sets + leaudit_rule_type_bindings
- DB: change UNIQUE constraint from (rule_type) to (rule_type, region)
- Config: add APP_REGION to app.toml + AppSettings + __init__.pyi
- AuditServiceImpl: filter bindings by APP_REGION
- RuleServiceImpl: ListBindings/CreateBinding use APP_REGION
- Seed script: accept --region arg, tag rules by region
- OssPathUtils: BuildRuleYamlKey already accepts Region parameter
Each region can now have its own independent copy of the same rule_type,
stored in separate OSS paths and DB rows, keyed by region.
finalize_run() is the single source of truth for terminal run state.
Previously save_evaluation_results wrote a binary pass/fail status and
finished_at BEFORE rescue outcomes/metrics were saved, then finalize_run
overwrote it. Now scores only are written here; terminal state is set
once by finalize_run after all sub-results are persisted.
17-table PostgreSQL schema with full Chinese column comments,
FastAPI project structure (admin/common/modules),
DSL rule files, and schema migration scripts.