package app import ( "context" "encoding/json" "errors" "fmt" "strings" "time" "unicode/utf8" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" "go.uber.org/zap" sharedcompliance "github.com/geo-platform/tenant-api/internal/shared/compliance" "github.com/geo-platform/tenant-api/internal/shared/response" ) type ComplianceService struct { pool *pgxpool.Pool audits *AuditService logger *zap.Logger } func NewComplianceService(pool *pgxpool.Pool, audits *AuditService, logger *zap.Logger) *ComplianceService { return &ComplianceService{pool: pool, audits: audits, logger: logger} } type ComplianceDictionary struct { ID int64 `json:"id"` Code string `json:"code"` Name string `json:"name"` PlatformScope string `json:"platform_scope"` ApplicablePlatforms []string `json:"applicable_platforms"` DefaultLevel string `json:"default_level"` Enabled bool `json:"enabled"` Version int `json:"version"` Description *string `json:"description,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` TermCount int `json:"term_count"` } type UpsertComplianceDictionaryRequest struct { Code string `json:"code"` Name string `json:"name"` PlatformScope string `json:"platform_scope"` ApplicablePlatforms []string `json:"applicable_platforms"` DefaultLevel string `json:"default_level"` Enabled *bool `json:"enabled"` Description *string `json:"description"` } type ComplianceDictionaryTerm struct { ID int64 `json:"id"` DictionaryID int64 `json:"dictionary_id"` MatchType string `json:"match_type"` Pattern string `json:"pattern"` LevelOverride *string `json:"level_override,omitempty"` Hint *string `json:"hint,omitempty"` ReferenceLaw *string `json:"reference_law,omitempty"` Enabled bool `json:"enabled"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type CreateComplianceDictionaryTermRequest struct { MatchType string `json:"match_type"` Pattern string `json:"pattern"` LevelOverride *string `json:"level_override"` Hint *string `json:"hint"` ReferenceLaw *string `json:"reference_law"` Enabled *bool `json:"enabled"` } type BatchImportComplianceTermsRequest struct { Terms []CreateComplianceDictionaryTermRequest `json:"terms"` } type CompliancePolicy struct { ID int64 `json:"id"` MasterEnabled *bool `json:"master_enabled,omitempty"` EnforcementMode string `json:"enforcement_mode"` EnabledDictionaries []int64 `json:"enabled_dictionaries"` LLMJudgeEnabled bool `json:"llm_judge_enabled"` LLMCategories []string `json:"llm_categories"` Revision int64 `json:"revision"` UpdatedAt time.Time `json:"updated_at"` } type UpdateCompliancePolicyRequest struct { MasterEnabled *bool `json:"master_enabled"` EnforcementMode string `json:"enforcement_mode"` EnabledDictionaries []int64 `json:"enabled_dictionaries"` LLMJudgeEnabled *bool `json:"llm_judge_enabled"` LLMCategories []string `json:"llm_categories"` } type ComplianceManualReviewListRequest struct { Status string TenantID *int64 Page int PageSize int } type ComplianceManualReviewListResponse struct { Items []sharedcompliance.ManualReview `json:"items"` Total int64 `json:"total"` Page int `json:"page"` PageSize int `json:"page_size"` } type ComplianceRecordListRequest struct { TenantID *int64 ArticleID *int64 Decision string Page int PageSize int } type ComplianceRecordListResponse struct { Items []sharedcompliance.CheckResult `json:"items"` Total int64 `json:"total"` Page int `json:"page"` PageSize int `json:"page_size"` } type ComplianceStats struct { CheckCount int64 `json:"check_count"` BlockedCount int64 `json:"blocked_count"` NeedsAckCount int64 `json:"needs_ack_count"` PassedCount int64 `json:"passed_count"` AckCount int64 `json:"ack_count"` ManualPendingCount int64 `json:"manual_pending_count"` ManualApprovedCount int64 `json:"manual_approved_count"` ManualRejectedCount int64 `json:"manual_rejected_count"` ByLevel map[string]int64 `json:"by_level"` BySource map[string]int64 `json:"by_source"` } func (s *ComplianceService) ListDictionaries(ctx context.Context) ([]ComplianceDictionary, error) { rows, err := s.pool.Query(ctx, ` SELECT d.id, d.code, d.name, d.platform_scope, COALESCE(d.applicable_platforms, '{}'), d.default_level, d.enabled, d.version, d.description, d.created_at, d.updated_at, COUNT(t.id)::int AS term_count FROM ops.compliance_dictionaries d LEFT JOIN ops.compliance_dictionary_terms t ON t.dictionary_id = d.id GROUP BY d.id ORDER BY d.id DESC `) if err != nil { return nil, response.ErrInternal(52001, "ops_compliance_dictionary_query_failed", "failed to list compliance dictionaries") } defer rows.Close() out := make([]ComplianceDictionary, 0) for rows.Next() { item, scanErr := scanComplianceDictionary(rows) if scanErr != nil { return nil, response.ErrInternal(52001, "ops_compliance_dictionary_query_failed", "failed to scan compliance dictionary") } out = append(out, item) } return out, rows.Err() } func (s *ComplianceService) CreateDictionary(ctx context.Context, req UpsertComplianceDictionaryRequest) (*ComplianceDictionary, error) { normalized, err := normalizeDictionaryInput(req, false) if err != nil { return nil, err } actor := ActorFromContext(ctx) var actorID *int64 if actor != nil && actor.OperatorID > 0 { actorID = &actor.OperatorID } var row ComplianceDictionary var description pgtype.Text err = s.pool.QueryRow(ctx, ` INSERT INTO ops.compliance_dictionaries ( code, name, platform_scope, applicable_platforms, default_level, enabled, description, created_by, updated_by ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$8) RETURNING id, code, name, platform_scope, COALESCE(applicable_platforms, '{}'), default_level, enabled, version, description, created_at, updated_at, 0 `, normalized.Code, normalized.Name, normalized.PlatformScope, normalized.ApplicablePlatforms, normalized.DefaultLevel, normalized.Enabled, normalized.Description, actorID).Scan( &row.ID, &row.Code, &row.Name, &row.PlatformScope, &row.ApplicablePlatforms, &row.DefaultLevel, &row.Enabled, &row.Version, &description, &row.CreatedAt, &row.UpdatedAt, &row.TermCount, ) if err != nil { if isOpsUniqueViolation(err) { return nil, response.ErrConflict(40971, "compliance_dictionary_code_exists", "dictionary code already exists") } return nil, response.ErrInternal(52002, "ops_compliance_dictionary_create_failed", "failed to create compliance dictionary") } if description.Valid { row.Description = &description.String } s.audit(ctx, "compliance.dictionary.create", "compliance_dictionary", row.ID, map[string]any{"code": row.Code}) return &row, nil } func (s *ComplianceService) UpdateDictionary(ctx context.Context, id int64, req UpsertComplianceDictionaryRequest) (*ComplianceDictionary, error) { normalized, err := normalizeDictionaryInput(req, true) if err != nil { return nil, err } actor := ActorFromContext(ctx) var actorID *int64 if actor != nil && actor.OperatorID > 0 { actorID = &actor.OperatorID } var row ComplianceDictionary var description pgtype.Text err = s.pool.QueryRow(ctx, ` UPDATE ops.compliance_dictionaries SET name = $2, platform_scope = $3, applicable_platforms = $4, default_level = $5, enabled = $6, description = $7, updated_by = $8, version = version + 1, updated_at = NOW() WHERE id = $1 RETURNING id, code, name, platform_scope, COALESCE(applicable_platforms, '{}'), default_level, enabled, version, description, created_at, updated_at, (SELECT COUNT(*)::int FROM ops.compliance_dictionary_terms t WHERE t.dictionary_id = ops.compliance_dictionaries.id) `, id, normalized.Name, normalized.PlatformScope, normalized.ApplicablePlatforms, normalized.DefaultLevel, normalized.Enabled, normalized.Description, actorID).Scan( &row.ID, &row.Code, &row.Name, &row.PlatformScope, &row.ApplicablePlatforms, &row.DefaultLevel, &row.Enabled, &row.Version, &description, &row.CreatedAt, &row.UpdatedAt, &row.TermCount, ) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, response.ErrNotFound(40471, "compliance_dictionary_not_found", "compliance dictionary not found") } return nil, response.ErrInternal(52003, "ops_compliance_dictionary_update_failed", "failed to update compliance dictionary") } if description.Valid { row.Description = &description.String } s.audit(ctx, "compliance.dictionary.update", "compliance_dictionary", row.ID, map[string]any{"code": row.Code}) return &row, nil } func (s *ComplianceService) DeleteDictionary(ctx context.Context, id int64) error { tag, err := s.pool.Exec(ctx, `DELETE FROM ops.compliance_dictionaries WHERE id = $1`, id) if err != nil { return response.ErrInternal(52004, "ops_compliance_dictionary_delete_failed", "failed to delete compliance dictionary") } if tag.RowsAffected() == 0 { return response.ErrNotFound(40471, "compliance_dictionary_not_found", "compliance dictionary not found") } s.audit(ctx, "compliance.dictionary.delete", "compliance_dictionary", id, nil) return nil } func (s *ComplianceService) ListTerms(ctx context.Context, dictionaryID int64) ([]ComplianceDictionaryTerm, error) { rows, err := s.pool.Query(ctx, ` SELECT id, dictionary_id, match_type, pattern, level_override, hint, reference_law, enabled, created_at, updated_at FROM ops.compliance_dictionary_terms WHERE dictionary_id = $1 ORDER BY id DESC `, dictionaryID) if err != nil { return nil, response.ErrInternal(52005, "ops_compliance_terms_query_failed", "failed to list compliance terms") } defer rows.Close() out := make([]ComplianceDictionaryTerm, 0) for rows.Next() { item, scanErr := scanComplianceDictionaryTerm(rows) if scanErr != nil { return nil, response.ErrInternal(52005, "ops_compliance_terms_query_failed", "failed to scan compliance term") } out = append(out, item) } return out, rows.Err() } func (s *ComplianceService) CreateTerm(ctx context.Context, dictionaryID int64, req CreateComplianceDictionaryTermRequest) (*ComplianceDictionaryTerm, error) { normalized, err := normalizeTermInput(req) if err != nil { return nil, err } var item ComplianceDictionaryTerm err = s.pool.QueryRow(ctx, ` INSERT INTO ops.compliance_dictionary_terms ( dictionary_id, match_type, pattern, level_override, hint, reference_law, enabled ) VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING id, dictionary_id, match_type, pattern, level_override, hint, reference_law, enabled, created_at, updated_at `, dictionaryID, normalized.MatchType, normalized.Pattern, normalized.LevelOverride, normalized.Hint, normalized.ReferenceLaw, normalized.Enabled).Scan( &item.ID, &item.DictionaryID, &item.MatchType, &item.Pattern, new(pgtype.Text), new(pgtype.Text), new(pgtype.Text), &item.Enabled, &item.CreatedAt, &item.UpdatedAt, ) if err != nil { if isOpsForeignKeyViolation(err) { return nil, response.ErrNotFound(40471, "compliance_dictionary_not_found", "compliance dictionary not found") } return nil, response.ErrInternal(52006, "ops_compliance_term_create_failed", "failed to create compliance term") } item, err = s.getTerm(ctx, item.ID) if err != nil { return nil, err } _ = s.bumpDictionaryVersion(ctx, dictionaryID) s.audit(ctx, "compliance.term.create", "compliance_dictionary", dictionaryID, map[string]any{"term_id": item.ID}) return &item, nil } func (s *ComplianceService) BatchImportTerms(ctx context.Context, dictionaryID int64, req BatchImportComplianceTermsRequest) ([]ComplianceDictionaryTerm, error) { if len(req.Terms) == 0 { return nil, response.ErrBadRequest(40001, "invalid_params", "terms is required") } if len(req.Terms) > 1000 { return nil, response.ErrBadRequest(40001, "invalid_params", "terms cannot exceed 1000 rows") } out := make([]ComplianceDictionaryTerm, 0, len(req.Terms)) for _, item := range req.Terms { created, err := s.CreateTerm(ctx, dictionaryID, item) if err != nil { return nil, err } out = append(out, *created) } return out, nil } func (s *ComplianceService) DeleteTerm(ctx context.Context, dictionaryID, termID int64) error { tag, err := s.pool.Exec(ctx, ` DELETE FROM ops.compliance_dictionary_terms WHERE id = $1 AND dictionary_id = $2 `, termID, dictionaryID) if err != nil { return response.ErrInternal(52007, "ops_compliance_term_delete_failed", "failed to delete compliance term") } if tag.RowsAffected() == 0 { return response.ErrNotFound(40472, "compliance_term_not_found", "compliance term not found") } _ = s.bumpDictionaryVersion(ctx, dictionaryID) s.audit(ctx, "compliance.term.delete", "compliance_dictionary", dictionaryID, map[string]any{"term_id": termID}) return nil } func (s *ComplianceService) PublishDictionary(ctx context.Context, dictionaryID int64) (*ComplianceDictionary, error) { tx, err := s.pool.Begin(ctx) if err != nil { return nil, response.ErrInternal(52008, "ops_compliance_dictionary_publish_failed", "failed to begin dictionary publish") } defer tx.Rollback(ctx) dict, err := s.loadDictionaryForUpdate(ctx, tx, dictionaryID) if err != nil { return nil, err } dict.Version++ if _, err := tx.Exec(ctx, ` UPDATE ops.compliance_dictionaries SET version = $2, updated_at = NOW() WHERE id = $1 `, dictionaryID, dict.Version); err != nil { return nil, response.ErrInternal(52008, "ops_compliance_dictionary_publish_failed", "failed to bump dictionary version") } if err := s.insertDictionaryVersionSnapshot(ctx, tx, dictionaryID, dict.Version); err != nil { return nil, err } if err := tx.Commit(ctx); err != nil { return nil, response.ErrInternal(52008, "ops_compliance_dictionary_publish_failed", "failed to commit dictionary publish") } s.audit(ctx, "compliance.dictionary.publish", "compliance_dictionary", dictionaryID, map[string]any{"version": dict.Version}) return s.GetDictionary(ctx, dictionaryID) } func (s *ComplianceService) RollbackDictionary(ctx context.Context, dictionaryID int64, version int) (*ComplianceDictionary, error) { if version <= 0 { return nil, response.ErrBadRequest(40001, "invalid_params", "version must be positive") } var snapshot []byte err := s.pool.QueryRow(ctx, ` SELECT snapshot FROM ops.compliance_dictionary_versions WHERE dictionary_id = $1 AND version = $2 `, dictionaryID, version).Scan(&snapshot) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, response.ErrNotFound(40473, "compliance_dictionary_version_not_found", "dictionary version not found") } return nil, response.ErrInternal(52009, "ops_compliance_dictionary_rollback_failed", "failed to load dictionary snapshot") } var parsed struct { Name string `json:"name"` PlatformScope string `json:"platform_scope"` ApplicablePlatforms []string `json:"applicable_platforms"` DefaultLevel string `json:"default_level"` Terms []struct { MatchType string `json:"match_type"` Pattern string `json:"pattern"` LevelOverride *string `json:"level_override"` Hint *string `json:"hint"` ReferenceLaw *string `json:"reference_law"` Enabled bool `json:"enabled"` } `json:"terms"` } _ = json.Unmarshal(snapshot, &parsed) tx, err := s.pool.Begin(ctx) if err != nil { return nil, response.ErrInternal(52009, "ops_compliance_dictionary_rollback_failed", "failed to begin dictionary rollback") } defer tx.Rollback(ctx) tag, err := tx.Exec(ctx, ` UPDATE ops.compliance_dictionaries SET name = COALESCE(NULLIF($2, ''), name), platform_scope = COALESCE(NULLIF($3, ''), platform_scope), applicable_platforms = $4, default_level = COALESCE(NULLIF($5, ''), default_level), version = version + 1, updated_at = NOW() WHERE id = $1 `, dictionaryID, parsed.Name, parsed.PlatformScope, normalizedPlatformArray(parsed.ApplicablePlatforms, parsed.PlatformScope), parsed.DefaultLevel) if err != nil { return nil, response.ErrInternal(52009, "ops_compliance_dictionary_rollback_failed", "failed to rollback dictionary") } if tag.RowsAffected() == 0 { return nil, response.ErrNotFound(40471, "compliance_dictionary_not_found", "compliance dictionary not found") } if _, err := tx.Exec(ctx, `DELETE FROM ops.compliance_dictionary_terms WHERE dictionary_id = $1`, dictionaryID); err != nil { return nil, response.ErrInternal(52009, "ops_compliance_dictionary_rollback_failed", "failed to clear dictionary terms") } for _, term := range parsed.Terms { pattern := strings.TrimSpace(term.Pattern) if pattern == "" { continue } matchType := normalizeTermMatchType(term.MatchType) if matchType == "" { matchType = "exact" } if _, err := tx.Exec(ctx, ` INSERT INTO ops.compliance_dictionary_terms ( dictionary_id, match_type, pattern, level_override, hint, reference_law, enabled ) VALUES ($1,$2,$3,$4,$5,$6,$7) `, dictionaryID, matchType, pattern, nullableStringPointer(term.LevelOverride), nullableStringPointer(term.Hint), nullableStringPointer(term.ReferenceLaw), term.Enabled); err != nil { return nil, response.ErrInternal(52009, "ops_compliance_dictionary_rollback_failed", "failed to restore dictionary terms") } } if err := tx.Commit(ctx); err != nil { return nil, response.ErrInternal(52009, "ops_compliance_dictionary_rollback_failed", "failed to commit dictionary rollback") } s.audit(ctx, "compliance.dictionary.rollback", "compliance_dictionary", dictionaryID, map[string]any{"version": version}) return s.GetDictionary(ctx, dictionaryID) } func (s *ComplianceService) GetDictionary(ctx context.Context, id int64) (*ComplianceDictionary, error) { var item ComplianceDictionary var description pgtype.Text err := s.pool.QueryRow(ctx, ` SELECT d.id, d.code, d.name, d.platform_scope, COALESCE(d.applicable_platforms, '{}'), d.default_level, d.enabled, d.version, d.description, d.created_at, d.updated_at, (SELECT COUNT(*)::int FROM ops.compliance_dictionary_terms t WHERE t.dictionary_id = d.id) FROM ops.compliance_dictionaries d WHERE d.id = $1 `, id).Scan( &item.ID, &item.Code, &item.Name, &item.PlatformScope, &item.ApplicablePlatforms, &item.DefaultLevel, &item.Enabled, &item.Version, &description, &item.CreatedAt, &item.UpdatedAt, &item.TermCount, ) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, response.ErrNotFound(40471, "compliance_dictionary_not_found", "compliance dictionary not found") } return nil, response.ErrInternal(52001, "ops_compliance_dictionary_query_failed", "failed to load compliance dictionary") } if description.Valid { item.Description = &description.String } return &item, nil } func (s *ComplianceService) GetGlobalPolicy(ctx context.Context) (*CompliancePolicy, error) { policy, err := s.getPolicy(ctx) if err != nil { return nil, err } return policy, nil } func (s *ComplianceService) UpdateGlobalPolicy(ctx context.Context, req UpdateCompliancePolicyRequest) (*CompliancePolicy, error) { policy, err := s.updatePolicy(ctx, req) if err != nil { return nil, err } s.audit(ctx, "compliance.policy.global.update", "compliance_policy", policy.ID, nil) return policy, nil } func (s *ComplianceService) SetGlobalMasterSwitch(ctx context.Context, enabled bool) (*CompliancePolicy, error) { req := UpdateCompliancePolicyRequest{MasterEnabled: &enabled} policy, err := s.updatePolicy(ctx, req) if err != nil { return nil, err } s.audit(ctx, "compliance.policy.global.master_switch", "compliance_policy", policy.ID, map[string]any{"enabled": enabled}) return policy, nil } func (s *ComplianceService) ListManualReviews(ctx context.Context, req ComplianceManualReviewListRequest) (*ComplianceManualReviewListResponse, error) { req.Page, req.PageSize = normalizePage(req.Page, req.PageSize) where, args := manualReviewWhere(req.Status, req.TenantID) var total int64 if err := s.pool.QueryRow(ctx, "SELECT COUNT(*) FROM compliance_manual_reviews mr WHERE "+where, args...).Scan(&total); err != nil { return nil, response.ErrInternal(52020, "ops_compliance_manual_reviews_query_failed", "failed to count manual reviews") } args = append(args, req.PageSize, (req.Page-1)*req.PageSize) limitArg := len(args) - 1 offsetArg := len(args) rows, err := s.pool.Query(ctx, fmt.Sprintf(` SELECT mr.id, mr.tenant_id, mr.article_id, mr.article_version_id, mr.original_check_record_id, mr.requested_by, mr.requested_at, mr.request_note, mr.status, mr.cancelled_by, mr.cancelled_at, mr.cancel_reason, mr.reviewed_by, mr.reviewed_at, mr.decision_reason, mr.original_violation_summary, mr.original_target_platforms, av.title, u.name, t.name FROM compliance_manual_reviews mr LEFT JOIN article_versions av ON av.id = mr.article_version_id LEFT JOIN users u ON u.id = mr.requested_by LEFT JOIN tenants t ON t.id = mr.tenant_id WHERE %s ORDER BY mr.requested_at DESC, mr.id DESC LIMIT $%d OFFSET $%d `, where, limitArg, offsetArg), args...) if err != nil { return nil, response.ErrInternal(52020, "ops_compliance_manual_reviews_query_failed", "failed to list manual reviews") } defer rows.Close() items := make([]sharedcompliance.ManualReview, 0) for rows.Next() { item, scanErr := scanManualReviewForOps(rows, false) if scanErr != nil { return nil, response.ErrInternal(52020, "ops_compliance_manual_reviews_query_failed", "failed to scan manual review") } items = append(items, item) } return &ComplianceManualReviewListResponse{Items: items, Total: total, Page: req.Page, PageSize: req.PageSize}, rows.Err() } func (s *ComplianceService) GetManualReview(ctx context.Context, id int64) (*sharedcompliance.ManualReview, error) { review, err := s.loadManualReview(ctx, id, true) if err != nil { return nil, err } return review, nil } func (s *ComplianceService) ApproveManualReview(ctx context.Context, id int64, reason string) (*sharedcompliance.ManualReview, error) { return s.decideManualReview(ctx, id, "approved", reason) } func (s *ComplianceService) RejectManualReview(ctx context.Context, id int64, reason string) (*sharedcompliance.ManualReview, error) { return s.decideManualReview(ctx, id, "rejected", reason) } func (s *ComplianceService) ListRecords(ctx context.Context, req ComplianceRecordListRequest) (*ComplianceRecordListResponse, error) { req.Page, req.PageSize = normalizePage(req.Page, req.PageSize) where, args := complianceRecordWhere(req) var total int64 if err := s.pool.QueryRow(ctx, "SELECT COUNT(*) FROM compliance_check_records WHERE "+where, args...).Scan(&total); err != nil { return nil, response.ErrInternal(52030, "ops_compliance_records_query_failed", "failed to count compliance records") } args = append(args, req.PageSize, (req.Page-1)*req.PageSize) limitArg := len(args) - 1 offsetArg := len(args) rows, err := s.pool.Query(ctx, fmt.Sprintf(` SELECT id, tenant_id, article_id, article_version_id, target_platforms, content_hash, policy_fingerprint, enforcement_mode, highest_level, passed, hit_count, stored_hit_count, truncated, manual_review_status, manual_review_id, checked_at, duration_ms FROM compliance_check_records WHERE %s ORDER BY checked_at DESC, id DESC LIMIT $%d OFFSET $%d `, where, limitArg, offsetArg), args...) if err != nil { return nil, response.ErrInternal(52030, "ops_compliance_records_query_failed", "failed to list compliance records") } defer rows.Close() items := make([]sharedcompliance.CheckResult, 0) for rows.Next() { record, scanErr := scanCheckRecordForOps(rows) if scanErr != nil { return nil, response.ErrInternal(52030, "ops_compliance_records_query_failed", "failed to scan compliance record") } violations, err := s.loadRecordViolations(ctx, record.ID, record.TenantID) if err != nil { return nil, err } items = append(items, *checkResultFromOpsRecord(record, violations)) } return &ComplianceRecordListResponse{Items: items, Total: total, Page: req.Page, PageSize: req.PageSize}, rows.Err() } func (s *ComplianceService) Stats(ctx context.Context) (*ComplianceStats, error) { stats := &ComplianceStats{ ByLevel: map[string]int64{}, BySource: map[string]int64{}, } if err := s.pool.QueryRow(ctx, ` SELECT COUNT(*)::bigint, COUNT(*) FILTER (WHERE enforcement_mode = 'mandatory' AND highest_level = 'block')::bigint, COUNT(*) FILTER (WHERE hit_count > 0 AND NOT (enforcement_mode = 'mandatory' AND highest_level = 'block'))::bigint, COUNT(*) FILTER (WHERE hit_count = 0)::bigint FROM compliance_check_records `).Scan(&stats.CheckCount, &stats.BlockedCount, &stats.NeedsAckCount, &stats.PassedCount); err != nil { return nil, response.ErrInternal(52040, "ops_compliance_stats_query_failed", "failed to load compliance stats") } _ = s.pool.QueryRow(ctx, `SELECT COUNT(*)::bigint FROM compliance_ack_records`).Scan(&stats.AckCount) _ = s.pool.QueryRow(ctx, ` SELECT COUNT(*) FILTER (WHERE status = 'pending')::bigint, COUNT(*) FILTER (WHERE status = 'approved')::bigint, COUNT(*) FILTER (WHERE status = 'rejected')::bigint FROM compliance_manual_reviews `).Scan(&stats.ManualPendingCount, &stats.ManualApprovedCount, &stats.ManualRejectedCount) levelRows, err := s.pool.Query(ctx, `SELECT level, COUNT(*)::bigint FROM compliance_violations GROUP BY level`) if err == nil { defer levelRows.Close() for levelRows.Next() { var level string var count int64 if scanErr := levelRows.Scan(&level, &count); scanErr == nil { stats.ByLevel[level] = count } } } sourceRows, err := s.pool.Query(ctx, `SELECT source, COUNT(*)::bigint FROM compliance_violations GROUP BY source`) if err == nil { defer sourceRows.Close() for sourceRows.Next() { var source string var count int64 if scanErr := sourceRows.Scan(&source, &count); scanErr == nil { stats.BySource[source] = count } } } return stats, nil } func (s *ComplianceService) decideManualReview(ctx context.Context, id int64, status, reason string) (*sharedcompliance.ManualReview, error) { reason = strings.TrimSpace(reason) if reason == "" { return nil, response.ErrBadRequest(40001, "invalid_params", "reason is required") } if utf8.RuneCountInString(reason) > 1000 { return nil, response.ErrBadRequest(40001, "invalid_params", "reason must be 1000 characters or less") } actor := ActorFromContext(ctx) if actor == nil || actor.OperatorID <= 0 { return nil, response.ErrUnauthorized(40101, "missing_operator", "operator context is required") } tx, err := s.pool.Begin(ctx) if err != nil { return nil, response.ErrInternal(52021, "ops_compliance_manual_review_decision_failed", "failed to begin manual review decision") } defer tx.Rollback(ctx) var reviewID int64 var articleID int64 var versionID int64 err = tx.QueryRow(ctx, ` UPDATE compliance_manual_reviews SET status = $2, reviewed_by = $3, reviewed_at = NOW(), decision_reason = $4 WHERE id = $1 AND status = 'pending' RETURNING id, article_id, article_version_id `, id, status, actor.OperatorID, reason).Scan(&reviewID, &articleID, &versionID) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, response.ErrConflict(41010, "compliance_manual_review_not_cancellable", "manual review is not pending") } return nil, response.ErrInternal(52021, "ops_compliance_manual_review_decision_failed", "failed to update manual review") } if _, err := tx.Exec(ctx, ` UPDATE article_versions SET manual_review_status = $1, manual_review_id = $2, manual_review_updated_at = NOW() WHERE id = $3 AND article_id = $4 `, status, reviewID, versionID, articleID); err != nil { return nil, response.ErrInternal(52021, "ops_compliance_manual_review_decision_failed", "failed to stamp article version") } if err := tx.Commit(ctx); err != nil { return nil, response.ErrInternal(52021, "ops_compliance_manual_review_decision_failed", "failed to commit manual review decision") } s.audit(ctx, "compliance.manual_review."+status, "compliance_manual_review", id, map[string]any{"reason": reason}) return s.loadManualReview(ctx, id, true) } func (s *ComplianceService) getPolicy(ctx context.Context) (*CompliancePolicy, error) { var policy CompliancePolicy if err := scanPolicy(s.pool.QueryRow(ctx, ` SELECT id, master_enabled, enforcement_mode, enabled_dictionaries, llm_judge_enabled, llm_categories, revision, updated_at FROM ops.compliance_policies WHERE id = 1 LIMIT 1 `), &policy); err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, response.ErrNotFound(40474, "compliance_policy_not_found", "compliance policy not found") } return nil, response.ErrInternal(52010, "ops_compliance_policy_query_failed", "failed to load compliance policy") } return &policy, nil } func (s *ComplianceService) updatePolicy(ctx context.Context, req UpdateCompliancePolicyRequest) (*CompliancePolicy, error) { existing, _ := s.getPolicy(ctx) mode := normalizeComplianceMode(req.EnforcementMode) if mode == "" { if existing != nil && existing.EnforcementMode != "" { mode = existing.EnforcementMode } else { mode = "mandatory" } } llmEnabled := false if req.LLMJudgeEnabled != nil { llmEnabled = *req.LLMJudgeEnabled } else if existing != nil { llmEnabled = existing.LLMJudgeEnabled } masterEnabled := req.MasterEnabled if masterEnabled == nil { if existing != nil { masterEnabled = existing.MasterEnabled } if masterEnabled == nil { defaultMaster := true masterEnabled = &defaultMaster } } enabledDictionaries := req.EnabledDictionaries if enabledDictionaries == nil && existing != nil { enabledDictionaries = existing.EnabledDictionaries } llmCategoriesValue := req.LLMCategories if llmCategoriesValue == nil && existing != nil { llmCategoriesValue = existing.LLMCategories } enabledDicts, _ := json.Marshal(enabledDictionaries) llmCategories, _ := json.Marshal(llmCategoriesValue) actor := ActorFromContext(ctx) var actorID *int64 if actor != nil && actor.OperatorID > 0 { actorID = &actor.OperatorID } var policy CompliancePolicy if err := scanPolicy(s.pool.QueryRow(ctx, ` INSERT INTO ops.compliance_policies ( id, master_enabled, enforcement_mode, enabled_dictionaries, llm_judge_enabled, llm_categories, updated_by ) VALUES (1, $1, $2, $3, $4, $5, $6) ON CONFLICT (id) DO UPDATE SET master_enabled = EXCLUDED.master_enabled, enforcement_mode = EXCLUDED.enforcement_mode, enabled_dictionaries = EXCLUDED.enabled_dictionaries, llm_judge_enabled = EXCLUDED.llm_judge_enabled, llm_categories = EXCLUDED.llm_categories, updated_by = EXCLUDED.updated_by, revision = ops.compliance_policies.revision + 1, updated_at = NOW() RETURNING id, master_enabled, enforcement_mode, enabled_dictionaries, llm_judge_enabled, llm_categories, revision, updated_at `, masterEnabled, mode, enabledDicts, llmEnabled, llmCategories, actorID), &policy); err != nil { return nil, response.ErrInternal(52011, "ops_compliance_policy_update_failed", "failed to update compliance policy") } return &policy, nil } func (s *ComplianceService) loadManualReview(ctx context.Context, id int64, includePlaintext bool) (*sharedcompliance.ManualReview, error) { query := ` SELECT mr.id, mr.tenant_id, mr.article_id, mr.article_version_id, mr.original_check_record_id, mr.requested_by, mr.requested_at, mr.request_note, mr.status, mr.cancelled_by, mr.cancelled_at, mr.cancel_reason, mr.reviewed_by, mr.reviewed_at, mr.decision_reason, mr.original_violation_summary, mr.original_target_platforms, av.title, u.name, t.name ` if includePlaintext { query += `, av.plaintext_snapshot` } query += ` FROM compliance_manual_reviews mr LEFT JOIN article_versions av ON av.id = mr.article_version_id LEFT JOIN users u ON u.id = mr.requested_by LEFT JOIN tenants t ON t.id = mr.tenant_id WHERE mr.id = $1 ` row := s.pool.QueryRow(ctx, query, id) review, err := scanManualReviewForOps(row, includePlaintext) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, response.ErrNotFound(40475, "compliance_manual_review_not_found", "manual review not found") } return nil, response.ErrInternal(52020, "ops_compliance_manual_reviews_query_failed", "failed to load manual review") } return &review, nil } func (s *ComplianceService) loadRecordViolations(ctx context.Context, recordID, tenantID int64) ([]sharedcompliance.Violation, error) { rows, err := s.pool.Query(ctx, ` SELECT id, record_id, platform_code, source, dictionary_code, dictionary_name, term_pattern, matched_text, start_offset, end_offset, dom_path, level, hint, reference_law FROM compliance_violations WHERE record_id = $1 AND tenant_id = $2 ORDER BY id `, recordID, tenantID) if err != nil { return nil, response.ErrInternal(52031, "ops_compliance_violations_query_failed", "failed to load compliance violations") } defer rows.Close() out := make([]sharedcompliance.Violation, 0) for rows.Next() { item, scanErr := scanViolationForOps(rows) if scanErr != nil { return nil, response.ErrInternal(52031, "ops_compliance_violations_query_failed", "failed to scan compliance violation") } out = append(out, item) } return out, rows.Err() } func (s *ComplianceService) bumpDictionaryVersion(ctx context.Context, dictionaryID int64) error { _, err := s.pool.Exec(ctx, ` UPDATE ops.compliance_dictionaries SET version = version + 1, updated_at = NOW() WHERE id = $1 `, dictionaryID) return err } func (s *ComplianceService) loadDictionaryForUpdate(ctx context.Context, tx pgx.Tx, id int64) (*ComplianceDictionary, error) { var item ComplianceDictionary err := tx.QueryRow(ctx, ` SELECT id, code, name, platform_scope, COALESCE(applicable_platforms, '{}'), default_level, enabled, version, description, created_at, updated_at, 0 FROM ops.compliance_dictionaries WHERE id = $1 FOR UPDATE `, id).Scan(&item.ID, &item.Code, &item.Name, &item.PlatformScope, &item.ApplicablePlatforms, &item.DefaultLevel, &item.Enabled, &item.Version, new(pgtype.Text), &item.CreatedAt, &item.UpdatedAt, &item.TermCount) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, response.ErrNotFound(40471, "compliance_dictionary_not_found", "compliance dictionary not found") } return nil, response.ErrInternal(52001, "ops_compliance_dictionary_query_failed", "failed to load compliance dictionary") } return &item, nil } func (s *ComplianceService) insertDictionaryVersionSnapshot(ctx context.Context, tx pgx.Tx, dictionaryID int64, version int) error { var snapshot []byte err := tx.QueryRow(ctx, ` SELECT jsonb_build_object( 'code', d.code, 'name', d.name, 'platform_scope', d.platform_scope, 'applicable_platforms', COALESCE(to_jsonb(d.applicable_platforms), '[]'::jsonb), 'default_level', d.default_level, 'terms', COALESCE(( SELECT jsonb_agg(jsonb_build_object( 'id', t.id, 'match_type', t.match_type, 'pattern', t.pattern, 'level_override', t.level_override, 'hint', t.hint, 'reference_law', t.reference_law, 'enabled', t.enabled ) ORDER BY t.id) FROM ops.compliance_dictionary_terms t WHERE t.dictionary_id = d.id ), '[]'::jsonb) ) FROM ops.compliance_dictionaries d WHERE d.id = $1 `, dictionaryID).Scan(&snapshot) if err != nil { return response.ErrInternal(52008, "ops_compliance_dictionary_publish_failed", "failed to build dictionary snapshot") } actor := ActorFromContext(ctx) var actorID *int64 if actor != nil && actor.OperatorID > 0 { actorID = &actor.OperatorID } _, err = tx.Exec(ctx, ` INSERT INTO ops.compliance_dictionary_versions (dictionary_id, version, snapshot, published_by) VALUES ($1,$2,$3,$4) ON CONFLICT (dictionary_id, version) DO NOTHING `, dictionaryID, version, snapshot, actorID) if err != nil { return response.ErrInternal(52008, "ops_compliance_dictionary_publish_failed", "failed to save dictionary snapshot") } return nil } func (s *ComplianceService) getTerm(ctx context.Context, termID int64) (ComplianceDictionaryTerm, error) { row := s.pool.QueryRow(ctx, ` SELECT id, dictionary_id, match_type, pattern, level_override, hint, reference_law, enabled, created_at, updated_at FROM ops.compliance_dictionary_terms WHERE id = $1 `, termID) item, err := scanComplianceDictionaryTerm(row) if err != nil { return item, response.ErrInternal(52005, "ops_compliance_terms_query_failed", "failed to load compliance term") } return item, nil } func (s *ComplianceService) audit(ctx context.Context, action, targetType string, targetID int64, metadata map[string]any) { if s == nil || s.audits == nil { return } actor := ActorFromContext(ctx) if actor == nil { return } if err := s.audits.Append(ctx, actor.audit(action, targetType, targetID, metadata)); err != nil && s.logger != nil { s.logger.Warn("ops compliance audit failed", zap.String("action", action), zap.Error(err)) } } type complianceDictionaryScanner interface{ Scan(dest ...any) error } func scanComplianceDictionary(scanner complianceDictionaryScanner) (ComplianceDictionary, error) { var item ComplianceDictionary var description pgtype.Text if err := scanner.Scan(&item.ID, &item.Code, &item.Name, &item.PlatformScope, &item.ApplicablePlatforms, &item.DefaultLevel, &item.Enabled, &item.Version, &description, &item.CreatedAt, &item.UpdatedAt, &item.TermCount); err != nil { return item, err } if description.Valid { item.Description = &description.String } return item, nil } func scanComplianceDictionaryTerm(scanner complianceDictionaryScanner) (ComplianceDictionaryTerm, error) { var item ComplianceDictionaryTerm var level pgtype.Text var hint pgtype.Text var referenceLaw pgtype.Text if err := scanner.Scan(&item.ID, &item.DictionaryID, &item.MatchType, &item.Pattern, &level, &hint, &referenceLaw, &item.Enabled, &item.CreatedAt, &item.UpdatedAt); err != nil { return item, err } if level.Valid { item.LevelOverride = &level.String } if hint.Valid { item.Hint = &hint.String } if referenceLaw.Valid { item.ReferenceLaw = &referenceLaw.String } return item, nil } func scanPolicy(scanner complianceDictionaryScanner, policy *CompliancePolicy) error { var master pgtype.Bool var enabledRaw []byte var llmCategoriesRaw []byte if err := scanner.Scan(&policy.ID, &master, &policy.EnforcementMode, &enabledRaw, &policy.LLMJudgeEnabled, &llmCategoriesRaw, &policy.Revision, &policy.UpdatedAt); err != nil { return err } if master.Valid { policy.MasterEnabled = &master.Bool } _ = json.Unmarshal(enabledRaw, &policy.EnabledDictionaries) _ = json.Unmarshal(llmCategoriesRaw, &policy.LLMCategories) if policy.EnabledDictionaries == nil { policy.EnabledDictionaries = []int64{} } if policy.LLMCategories == nil { policy.LLMCategories = []string{} } return nil } func scanManualReviewForOps(scanner complianceDictionaryScanner, includePlaintext bool) (sharedcompliance.ManualReview, error) { var item sharedcompliance.ManualReview var checkID pgtype.Int8 var requestNote pgtype.Text var cancelledBy pgtype.Int8 var cancelledAt pgtype.Timestamptz var cancelReason pgtype.Text var reviewedBy pgtype.Int8 var reviewedAt pgtype.Timestamptz var decisionReason pgtype.Text var summary []byte var platforms []string var title pgtype.Text var applicant pgtype.Text var tenant pgtype.Text dest := []any{ &item.ID, &item.TenantID, &item.ArticleID, &item.ArticleVersionID, &checkID, &item.RequestedBy, &item.RequestedAt, &requestNote, &item.Status, &cancelledBy, &cancelledAt, &cancelReason, &reviewedBy, &reviewedAt, &decisionReason, &summary, &platforms, &title, &applicant, &tenant, } var plaintext pgtype.Text if includePlaintext { dest = append(dest, &plaintext) } if err := scanner.Scan(dest...); err != nil { return item, err } if checkID.Valid { item.CheckRecordID = &checkID.Int64 } if requestNote.Valid { item.RequestNote = &requestNote.String } if cancelledBy.Valid { item.CancelledBy = &cancelledBy.Int64 } if cancelledAt.Valid { item.CancelledAt = &cancelledAt.Time } if cancelReason.Valid { item.CancelReason = &cancelReason.String } if reviewedBy.Valid { item.ReviewedBy = &reviewedBy.Int64 } if reviewedAt.Valid { item.ReviewedAt = &reviewedAt.Time } if decisionReason.Valid { item.DecisionReason = &decisionReason.String } _ = json.Unmarshal(summary, &item.ViolationSummary) item.OriginalPlatforms = platforms if title.Valid { item.ArticleTitle = &title.String } if applicant.Valid { item.ApplicantName = &applicant.String } if tenant.Valid { item.TenantName = &tenant.String } if includePlaintext && plaintext.Valid { item.ArticlePlaintext = &plaintext.String } return item, nil } type opsCheckRecordRow struct { ID int64 TenantID int64 ArticleID int64 ArticleVersionID int64 TargetPlatforms []string ContentHash string PolicyFingerprint string EnforcementMode string HighestLevel *string Passed bool HitCount int StoredHitCount int Truncated bool ManualReviewStatus sharedcompliance.ManualReviewStatus ManualReviewID *int64 CheckedAt time.Time DurationMS int } func scanCheckRecordForOps(scanner complianceDictionaryScanner) (opsCheckRecordRow, error) { var record opsCheckRecordRow var articleID pgtype.Int8 var versionID pgtype.Int8 var highest pgtype.Text var manualReviewID pgtype.Int8 var manualStatus string if err := scanner.Scan(&record.ID, &record.TenantID, &articleID, &versionID, &record.TargetPlatforms, &record.ContentHash, &record.PolicyFingerprint, &record.EnforcementMode, &highest, &record.Passed, &record.HitCount, &record.StoredHitCount, &record.Truncated, &manualStatus, &manualReviewID, &record.CheckedAt, &record.DurationMS); err != nil { return record, err } if articleID.Valid { record.ArticleID = articleID.Int64 } if versionID.Valid { record.ArticleVersionID = versionID.Int64 } if highest.Valid { record.HighestLevel = &highest.String } if manualReviewID.Valid { record.ManualReviewID = &manualReviewID.Int64 } record.ManualReviewStatus = sharedcompliance.ManualReviewStatus(manualStatus) return record, nil } func scanViolationForOps(scanner complianceDictionaryScanner) (sharedcompliance.Violation, error) { var item sharedcompliance.Violation var platform pgtype.Text var dictCode pgtype.Text var dictName pgtype.Text var termPattern pgtype.Text var domPath pgtype.Text var hint pgtype.Text var ref pgtype.Text if err := scanner.Scan(&item.ID, &item.RecordID, &platform, &item.Source, &dictCode, &dictName, &termPattern, &item.MatchedText, &item.StartOffset, &item.EndOffset, &domPath, &item.Level, &hint, &ref); err != nil { return item, err } if platform.Valid { item.PlatformCode = &platform.String } if dictCode.Valid { item.DictionaryCode = &dictCode.String } if dictName.Valid { item.DictionaryName = &dictName.String } if termPattern.Valid { item.TermPattern = &termPattern.String } if domPath.Valid { item.DomPath = &domPath.String } if hint.Valid { item.Hint = &hint.String } if ref.Valid { item.ReferenceLaw = &ref.String } return item, nil } func checkResultFromOpsRecord(record opsCheckRecordRow, violations []sharedcompliance.Violation) *sharedcompliance.CheckResult { decision := sharedcompliance.GateDecisionPass if record.HitCount > 0 { decision = sharedcompliance.GateDecisionNeedsAck if record.EnforcementMode == "mandatory" && record.HighestLevel != nil && *record.HighestLevel == "block" { decision = sharedcompliance.GateDecisionBlock } } return &sharedcompliance.CheckResult{ RecordID: record.ID, Decision: decision, Passed: record.Passed, HighestLevel: record.HighestLevel, Violations: violations, HitCount: record.HitCount, StoredHitCount: record.StoredHitCount, Truncated: record.Truncated, EnforcementMode: record.EnforcementMode, ContentHash: record.ContentHash, PolicyFingerprint: record.PolicyFingerprint, TargetPlatforms: record.TargetPlatforms, ManualReviewStatus: record.ManualReviewStatus, ManualReviewID: record.ManualReviewID, CheckedAt: record.CheckedAt, DurationMS: record.DurationMS, } } func normalizeDictionaryInput(req UpsertComplianceDictionaryRequest, updating bool) (UpsertComplianceDictionaryRequest, error) { req.Code = strings.TrimSpace(req.Code) req.Name = strings.TrimSpace(req.Name) req.PlatformScope = strings.ToLower(strings.TrimSpace(req.PlatformScope)) req.DefaultLevel = normalizeComplianceLevel(req.DefaultLevel) if !updating && req.Code == "" { return req, response.ErrBadRequest(40001, "invalid_params", "code is required") } if req.Name == "" { return req, response.ErrBadRequest(40001, "invalid_params", "name is required") } if req.PlatformScope == "" { req.PlatformScope = "all" } if req.PlatformScope != "all" && req.PlatformScope != "specific" { return req, response.ErrBadRequest(40001, "invalid_params", "platform_scope must be all or specific") } req.ApplicablePlatforms = normalizedPlatformArray(req.ApplicablePlatforms, req.PlatformScope) if req.PlatformScope == "specific" && len(req.ApplicablePlatforms) == 0 { return req, response.ErrBadRequest(40001, "invalid_params", "applicable_platforms is required for specific scope") } if req.DefaultLevel == "" { req.DefaultLevel = "block" } enabled := true if req.Enabled != nil { enabled = *req.Enabled } req.Enabled = &enabled if req.Description != nil { value := strings.TrimSpace(*req.Description) req.Description = &value } return req, nil } func normalizeTermInput(req CreateComplianceDictionaryTermRequest) (CreateComplianceDictionaryTermRequest, error) { req.MatchType = normalizeTermMatchType(req.MatchType) if req.MatchType == "" { req.MatchType = "exact" } req.Pattern = strings.TrimSpace(req.Pattern) if req.Pattern == "" { return req, response.ErrBadRequest(40001, "invalid_params", "pattern is required") } if req.LevelOverride != nil { level := normalizeComplianceLevel(*req.LevelOverride) if level == "" { return req, response.ErrBadRequest(40001, "invalid_params", "level_override is invalid") } req.LevelOverride = &level } enabled := true if req.Enabled != nil { enabled = *req.Enabled } req.Enabled = &enabled return req, nil } func normalizeTermMatchType(value string) string { value = strings.ToLower(strings.TrimSpace(value)) switch value { case "", "exact": return "exact" case "regex": return value default: return "" } } func normalizeComplianceLevel(level string) string { level = strings.ToLower(strings.TrimSpace(level)) switch level { case "block", "high", "medium", "info": return level default: return "" } } func normalizeComplianceMode(mode string) string { mode = strings.ToLower(strings.TrimSpace(mode)) switch mode { case "mandatory", "advisory", "disabled": return mode default: return "" } } func normalizedPlatformArray(platforms []string, scope string) []string { if strings.EqualFold(strings.TrimSpace(scope), "all") { return nil } seen := map[string]struct{}{} out := make([]string, 0, len(platforms)) for _, platform := range platforms { platform = strings.TrimSpace(platform) if platform == "" { continue } if _, ok := seen[platform]; ok { continue } seen[platform] = struct{}{} out = append(out, platform) } return out } func nullableStringPointer(value *string) *string { if value == nil { return nil } trimmed := strings.TrimSpace(*value) if trimmed == "" { return nil } return &trimmed } func manualReviewWhere(status string, tenantID *int64) (string, []any) { where := "1=1" args := []any{} status = strings.ToLower(strings.TrimSpace(status)) if status != "" { args = append(args, status) where += fmt.Sprintf(" AND mr.status = $%d", len(args)) } if tenantID != nil && *tenantID > 0 { args = append(args, *tenantID) where += fmt.Sprintf(" AND mr.tenant_id = $%d", len(args)) } return where, args } func complianceRecordWhere(req ComplianceRecordListRequest) (string, []any) { where := "1=1" args := []any{} if req.TenantID != nil && *req.TenantID > 0 { args = append(args, *req.TenantID) where += fmt.Sprintf(" AND tenant_id = $%d", len(args)) } if req.ArticleID != nil && *req.ArticleID > 0 { args = append(args, *req.ArticleID) where += fmt.Sprintf(" AND article_id = $%d", len(args)) } switch strings.TrimSpace(req.Decision) { case "pass": where += " AND hit_count = 0" case "block": where += " AND enforcement_mode = 'mandatory' AND highest_level = 'block'" case "needs_ack": where += " AND hit_count > 0 AND NOT (enforcement_mode = 'mandatory' AND highest_level = 'block')" } return where, args } func normalizePage(page, size int) (int, int) { if page <= 0 { page = 1 } if size <= 0 || size > 200 { size = 50 } return page, size } func isOpsUniqueViolation(err error) bool { var pgErr *pgconn.PgError return errors.As(err, &pgErr) && pgErr.Code == "23505" } func isOpsForeignKeyViolation(err error) bool { var pgErr *pgconn.PgError return errors.As(err, &pgErr) && pgErr.Code == "23503" }