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
+106
View File
@@ -0,0 +1,106 @@
package compliance
import "time"
type GateDecision string
const (
GateDecisionPass GateDecision = "pass"
GateDecisionBlock GateDecision = "block"
GateDecisionNeedsAck GateDecision = "needs_ack"
)
type ManualReviewStatus string
const (
ManualReviewStatusNone ManualReviewStatus = "none"
ManualReviewStatusPending ManualReviewStatus = "pending"
ManualReviewStatusApproved ManualReviewStatus = "approved"
ManualReviewStatusRejected ManualReviewStatus = "rejected"
ManualReviewStatusCancelled ManualReviewStatus = "cancelled"
)
type RuntimeStatus struct {
Enabled bool `json:"enabled"`
ConfigEnabled bool `json:"config_enabled"`
MasterEnabled bool `json:"master_enabled"`
EnforcementMode string `json:"enforcement_mode"`
LLMJudgeEnabled bool `json:"llm_judge_enabled"`
SnapshotReloadInterval string `json:"snapshot_reload_interval"`
PublishGateTimeout string `json:"publish_gate_timeout"`
DictionaryVersion int64 `json:"dictionary_version"`
EnabledDictionaries []string `json:"enabled_dictionaries"`
}
type Violation struct {
ID int64 `json:"id"`
RecordID int64 `json:"record_id,omitempty"`
PlatformCode *string `json:"platform_code,omitempty"`
Source string `json:"source"`
DictionaryCode *string `json:"dictionary_code,omitempty"`
DictionaryName *string `json:"dictionary_name,omitempty"`
TermPattern *string `json:"term_pattern,omitempty"`
MatchedText string `json:"matched_text"`
StartOffset int `json:"start_offset"`
EndOffset int `json:"end_offset"`
DomPath *string `json:"dom_path,omitempty"`
Level string `json:"level"`
Hint *string `json:"hint,omitempty"`
ReferenceLaw *string `json:"reference_law,omitempty"`
}
type CheckResult struct {
RecordID int64 `json:"record_id,omitempty"`
Decision GateDecision `json:"decision"`
Passed bool `json:"passed"`
HighestLevel *string `json:"highest_level,omitempty"`
Violations []Violation `json:"violations"`
HitCount int `json:"hit_count"`
StoredHitCount int `json:"stored_hit_count"`
Truncated bool `json:"truncated"`
EnforcementMode string `json:"enforcement_mode"`
ContentHash string `json:"content_hash"`
PolicyFingerprint string `json:"policy_fingerprint"`
TargetPlatforms []string `json:"target_platforms"`
ManualReviewStatus ManualReviewStatus `json:"manual_review_status"`
ManualReviewID *int64 `json:"manual_review_id,omitempty"`
ManualReviewReason *string `json:"manual_review_reason,omitempty"`
ManualReviewDecidedAt *time.Time `json:"manual_review_decided_at,omitempty"`
CheckedAt time.Time `json:"checked_at"`
DurationMS int `json:"duration_ms"`
}
type AckRecord struct {
ID int64 `json:"id"`
CheckRecordID int64 `json:"check_record_id"`
ArticleID int64 `json:"article_id"`
ArticleVersionID int64 `json:"article_version_id"`
ContentHash string `json:"content_hash"`
PolicyFingerprint string `json:"policy_fingerprint"`
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
}
type ManualReview struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
ArticleID int64 `json:"article_id"`
ArticleVersionID int64 `json:"article_version_id"`
CheckRecordID *int64 `json:"check_record_id,omitempty"`
Status ManualReviewStatus `json:"status"`
RequestedBy int64 `json:"requested_by"`
RequestedAt time.Time `json:"requested_at"`
RequestNote *string `json:"request_note,omitempty"`
ReviewedBy *int64 `json:"reviewed_by,omitempty"`
ReviewedAt *time.Time `json:"reviewed_at,omitempty"`
DecisionReason *string `json:"decision_reason,omitempty"`
CancelledBy *int64 `json:"cancelled_by,omitempty"`
CancelledAt *time.Time `json:"cancelled_at,omitempty"`
CancelReason *string `json:"cancel_reason,omitempty"`
ViolationSummary []Violation `json:"violation_summary"`
OriginalPlatforms []string `json:"original_target_platforms"`
ArticleTitle *string `json:"article_title,omitempty"`
ArticlePlaintext *string `json:"article_plaintext,omitempty"`
ApplicantName *string `json:"applicant_name,omitempty"`
TenantName *string `json:"tenant_name,omitempty"`
}