feat(compliance): add content compliance detection across tenant, ops, and clients

Implements the Revision 8/9 compliance design: tenant + ops backends, ops-web
content-safety pages, admin-web editor/publish gate integration, desktop publish
block surfacing, and supporting migrations / shared types / config plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 20:48:14 +08:00
parent 81577b6154
commit 745cdd79cf
73 changed files with 12747 additions and 1892 deletions
+22
View File
@@ -22,6 +22,7 @@ type Deps struct {
KolSubs *app.KolSubscriptionService
Audits *app.AuditService
SiteDomains *app.SiteDomainMappingService
Compliance *app.ComplianceService
}
func RegisterRoutes(d Deps) {
@@ -96,5 +97,26 @@ func RegisterRoutes(d Deps) {
authed.PATCH("/site-domain-mappings/:id", updateSiteDomainMappingHandler(d.SiteDomains))
authed.POST("/site-domain-mappings/:id/active", setSiteDomainMappingActiveHandler(d.SiteDomains))
authed.DELETE("/site-domain-mappings/:id", deleteSiteDomainMappingHandler(d.SiteDomains))
compliance := authed.Group("/compliance")
compliance.GET("/dictionaries", listComplianceDictionariesHandler(d.Compliance))
compliance.POST("/dictionaries", createComplianceDictionaryHandler(d.Compliance))
compliance.PUT("/dictionaries/:id", updateComplianceDictionaryHandler(d.Compliance))
compliance.DELETE("/dictionaries/:id", deleteComplianceDictionaryHandler(d.Compliance))
compliance.GET("/dictionaries/:id/terms", listComplianceTermsHandler(d.Compliance))
compliance.POST("/dictionaries/:id/terms", createComplianceTermHandler(d.Compliance))
compliance.POST("/dictionaries/:id/terms:batch-import", batchImportComplianceTermsHandler(d.Compliance))
compliance.DELETE("/dictionaries/:id/terms/:term_id", deleteComplianceTermHandler(d.Compliance))
compliance.POST("/dictionaries/:id/publish", publishComplianceDictionaryHandler(d.Compliance))
compliance.POST("/dictionaries/:id/rollback", rollbackComplianceDictionaryHandler(d.Compliance))
compliance.GET("/policy/global", getGlobalCompliancePolicyHandler(d.Compliance))
compliance.PUT("/policy/global", updateGlobalCompliancePolicyHandler(d.Compliance))
compliance.POST("/policy/global/master-switch", setGlobalComplianceMasterSwitchHandler(d.Compliance))
compliance.GET("/manual-reviews", listComplianceManualReviewsHandler(d.Compliance))
compliance.GET("/manual-reviews/:id", getComplianceManualReviewHandler(d.Compliance))
compliance.POST("/manual-reviews/:id/approve", approveComplianceManualReviewHandler(d.Compliance))
compliance.POST("/manual-reviews/:id/reject", rejectComplianceManualReviewHandler(d.Compliance))
compliance.GET("/stats", complianceStatsHandler(d.Compliance))
compliance.GET("/records", listComplianceRecordsHandler(d.Compliance))
}
}