固化七月迭代审计治理进展以隔离线上热修
Constraint: 切换 main 前必须保存当前七月分支全部项目进展,套餐生效提案仅属于 Iteration/7-11。 Rejected: 将七月套餐修复直接移植到 main | 两个分支的可靠投递架构不同。 Confidence: medium Scope-risk: broad Directive: 不得将本提交整体 cherry-pick 到 main;main 套餐热修必须基于其纯 Asynq 代码独立实施。 Tested: git diff --check;openspec validate fix-package-activation-starvation --strict。 Not-tested: 按用户要求未运行自动化测试;go build ./... 因当前审计改造中的 Enterprise 模型字面量和 role.recordFailure 参数类型错误未通过。
This commit is contained in:
76
internal/model/audit_event.go
Normal file
76
internal/model/audit_event.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
// AuditEvent 是不可变内部业务审计事件。
|
||||
type AuditEvent struct {
|
||||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||||
EventID string `gorm:"column:event_id;type:varchar(64);not null;uniqueIndex" json:"event_id"`
|
||||
OccurredAt time.Time `gorm:"column:occurred_at;type:timestamptz;not null" json:"occurred_at"`
|
||||
Category string `gorm:"column:category;type:varchar(64);not null" json:"category"`
|
||||
ActionCode string `gorm:"column:action_code;type:varchar(100);not null" json:"action_code"`
|
||||
ActionName string `gorm:"column:action_name;type:varchar(200);not null" json:"action_name"`
|
||||
Summary string `gorm:"column:summary;type:varchar(500);not null" json:"summary"`
|
||||
ActorKind string `gorm:"column:actor_kind;type:varchar(32);not null" json:"actor_kind"`
|
||||
ActorID string `gorm:"column:actor_id;type:varchar(128);not null" json:"actor_id"`
|
||||
ActorName string `gorm:"column:actor_name;type:varchar(200);not null" json:"actor_name"`
|
||||
ActorShopID *uint `gorm:"column:actor_shop_id" json:"actor_shop_id,omitempty"`
|
||||
ActorShopName string `gorm:"column:actor_shop_name;type:varchar(200);not null;default:''" json:"actor_shop_name,omitempty"`
|
||||
ActorEnterpriseID *uint `gorm:"column:actor_enterprise_id" json:"actor_enterprise_id,omitempty"`
|
||||
ActorEnterpriseName string `gorm:"column:actor_enterprise_name;type:varchar(200);not null;default:''" json:"actor_enterprise_name,omitempty"`
|
||||
Source string `gorm:"column:source;type:varchar(32);not null" json:"source"`
|
||||
RequestPath string `gorm:"column:request_path;type:varchar(300);not null;default:''" json:"request_path,omitempty"`
|
||||
RequestMethod string `gorm:"column:request_method;type:varchar(16);not null;default:''" json:"request_method,omitempty"`
|
||||
IPAddress string `gorm:"column:ip_address;type:varchar(64);not null;default:''" json:"ip_address,omitempty"`
|
||||
UserAgent string `gorm:"column:user_agent;type:varchar(500);not null;default:''" json:"user_agent,omitempty"`
|
||||
ScopeType string `gorm:"column:scope_type;type:varchar(32);not null" json:"scope_type"`
|
||||
ScopeID string `gorm:"column:scope_id;type:varchar(128);not null;default:''" json:"scope_id,omitempty"`
|
||||
ScopeName string `gorm:"column:scope_name;type:varchar(200);not null;default:''" json:"scope_name,omitempty"`
|
||||
Result string `gorm:"column:result;type:varchar(16);not null" json:"result"`
|
||||
RiskLevel string `gorm:"column:risk_level;type:varchar(16);not null" json:"risk_level"`
|
||||
ErrorCode string `gorm:"column:error_code;type:varchar(100);not null;default:''" json:"error_code,omitempty"`
|
||||
ErrorSummary string `gorm:"column:error_summary;type:varchar(500);not null;default:''" json:"error_summary,omitempty"`
|
||||
RequestID string `gorm:"column:request_id;type:varchar(100);not null;default:''" json:"request_id,omitempty"`
|
||||
CorrelationID string `gorm:"column:correlation_id;type:varchar(100);not null;default:''" json:"correlation_id,omitempty"`
|
||||
ParentEventID string `gorm:"column:parent_event_id;type:varchar(64);not null;default:''" json:"parent_event_id,omitempty"`
|
||||
BatchTotal int `gorm:"column:batch_total;not null;default:0" json:"batch_total"`
|
||||
SuccessCount int `gorm:"column:success_count;not null;default:0" json:"success_count"`
|
||||
FailCount int `gorm:"column:fail_count;not null;default:0" json:"fail_count"`
|
||||
Metadata datatypes.JSON `gorm:"column:metadata;type:jsonb;not null;default:'{}'" json:"metadata"`
|
||||
ContentHash string `gorm:"column:content_hash;type:varchar(64);not null" json:"content_hash"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
|
||||
}
|
||||
|
||||
// TableName 返回统一审计事件表名。
|
||||
func (AuditEvent) TableName() string {
|
||||
return "tb_audit_event"
|
||||
}
|
||||
|
||||
// AuditEventResource 是审计事件发生时的独立资源快照。
|
||||
type AuditEventResource struct {
|
||||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||||
AuditEventID uint `gorm:"column:audit_event_id;not null" json:"audit_event_id"`
|
||||
ResourceType string `gorm:"column:resource_type;type:varchar(64);not null" json:"resource_type"`
|
||||
ResourceID *string `gorm:"column:resource_id;type:varchar(128)" json:"resource_id,omitempty"`
|
||||
ResourceKey string `gorm:"column:resource_key;type:varchar(200);not null" json:"resource_key"`
|
||||
DisplayName string `gorm:"column:display_name;type:varchar(255);not null;default:''" json:"display_name"`
|
||||
Relation string `gorm:"column:relation;type:varchar(16);not null" json:"relation"`
|
||||
Role string `gorm:"column:role;type:varchar(64);not null" json:"role"`
|
||||
IdentitySnapshot datatypes.JSON `gorm:"column:identity_snapshot;type:jsonb;not null;default:'{}'" json:"identity_snapshot"`
|
||||
BeforeData datatypes.JSON `gorm:"column:before_data;type:jsonb;not null;default:'{}'" json:"before_data"`
|
||||
AfterData datatypes.JSON `gorm:"column:after_data;type:jsonb;not null;default:'{}'" json:"after_data"`
|
||||
SubjectVisibility string `gorm:"column:subject_visibility;type:varchar(24);not null" json:"subject_visibility"`
|
||||
SubjectSummary string `gorm:"column:subject_summary;type:varchar(500);not null;default:''" json:"subject_summary,omitempty"`
|
||||
SubjectData datatypes.JSON `gorm:"column:subject_data;type:jsonb;not null;default:'{}'" json:"subject_data"`
|
||||
SortOrder int `gorm:"column:sort_order;not null;default:0" json:"sort_order"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
|
||||
}
|
||||
|
||||
// TableName 返回审计事件资源表名。
|
||||
func (AuditEventResource) TableName() string {
|
||||
return "tb_audit_event_resource"
|
||||
}
|
||||
@@ -19,7 +19,7 @@ type AgentRechargeOnlineResponse struct {
|
||||
RechargeSource string `json:"recharge_source" description:"充值来源 (agent_online:代理在线自充)"`
|
||||
RechargeSourceName string `json:"recharge_source_name" description:"充值来源名称(中文)"`
|
||||
Amount int64 `json:"amount" description:"在线充值金额(分),范围10000分~100000000分"`
|
||||
QRContent string `json:"qr_content" description:"支付渠道原始扫码付款内容,由前端渲染二维码"`
|
||||
QRContent string `json:"qr_content" description:"支付链接(HTTPS URL),由前端渲染二维码"`
|
||||
Status int `json:"status" description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款, 6:已驳回)"`
|
||||
StatusName string `json:"status_name" description:"状态名称(中文)"`
|
||||
}
|
||||
|
||||
113
internal/model/dto/audit_dto.go
Normal file
113
internal/model/dto/audit_dto.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package dto
|
||||
|
||||
// AuditEventListRequest 是平台审计事件列表的组合筛选参数。
|
||||
type AuditEventListRequest struct {
|
||||
CreatedFrom string `json:"created_from" query:"created_from" description:"开始时间(RFC3339,含时区)"`
|
||||
CreatedTo string `json:"created_to" query:"created_to" description:"结束时间(RFC3339,含时区,不包含该时刻)"`
|
||||
Action string `json:"action" query:"action" description:"稳定动作编码"`
|
||||
Category string `json:"category" query:"category" description:"动作类别"`
|
||||
ActorKind string `json:"actor_kind" query:"actor_kind" description:"操作者类型"`
|
||||
ActorID string `json:"actor_id" query:"actor_id" description:"操作者稳定ID"`
|
||||
Source string `json:"source" query:"source" description:"操作入口来源"`
|
||||
Result string `json:"result" query:"result" description:"结果 (success:成功, failed:失败, denied:拒绝, partial:部分成功, unknown:未知)"`
|
||||
Risk string `json:"risk" query:"risk" description:"风险等级 (low:低, normal:普通, high:高, critical:严重)"`
|
||||
ScopeType string `json:"scope_type" query:"scope_type" description:"业务范围类型"`
|
||||
ScopeID string `json:"scope_id" query:"scope_id" description:"业务范围稳定ID"`
|
||||
ResourceType string `json:"resource_type" query:"resource_type" description:"Resource Registry 注册类型"`
|
||||
ResourceID string `json:"resource_id" query:"resource_id" description:"资源内部稳定ID"`
|
||||
ResourceKey string `json:"resource_key" query:"resource_key" description:"资源业务稳定Key"`
|
||||
RequestID string `json:"request_id" query:"request_id" description:"HTTP请求关联ID"`
|
||||
CorrelationID string `json:"correlation_id" query:"correlation_id" description:"跨步骤业务链路ID"`
|
||||
Page int `json:"page" query:"page" minimum:"1" description:"页码,默认1"`
|
||||
PageSize int `json:"page_size" query:"page_size" minimum:"1" maximum:"100" description:"每页数量,默认20,最大100"`
|
||||
}
|
||||
|
||||
// AuditEventIDParams 是审计事件详情路径参数。
|
||||
type AuditEventIDParams struct {
|
||||
EventID string `json:"event_id" path:"event_id" required:"true" description:"稳定审计事件ID"`
|
||||
}
|
||||
|
||||
// AuditActorEventsRequest 是操作者行为时间线参数。
|
||||
type AuditActorEventsRequest struct {
|
||||
Kind string `json:"kind" path:"kind" required:"true" description:"操作者类型 (account:人工账号, openapi:开放接口账号, system_task:系统任务, scheduled_job:计划任务, external_system:外部系统)"`
|
||||
ID string `json:"id" path:"id" required:"true" description:"操作者稳定ID"`
|
||||
Action string `json:"action" query:"action" description:"稳定动作编码"`
|
||||
Result string `json:"result" query:"result" description:"事件结果"`
|
||||
Risk string `json:"risk" query:"risk" description:"风险等级"`
|
||||
ResourceType string `json:"resource_type" query:"resource_type" description:"资源类型"`
|
||||
ResourceID string `json:"resource_id" query:"resource_id" description:"资源内部稳定ID"`
|
||||
CreatedFrom string `json:"created_from" query:"created_from" description:"开始时间(RFC3339,含时区)"`
|
||||
CreatedTo string `json:"created_to" query:"created_to" description:"结束时间(RFC3339,含时区,不包含该时刻)"`
|
||||
Page int `json:"page" query:"page" minimum:"1" description:"页码,默认1"`
|
||||
PageSize int `json:"page_size" query:"page_size" minimum:"1" maximum:"100" description:"每页数量,默认20,最大100"`
|
||||
}
|
||||
|
||||
// AuditResourceSearchRequest 是首批注册资源的精确搜索参数。
|
||||
type AuditResourceSearchRequest struct {
|
||||
ResourceType string `json:"resource_type" query:"resource_type" required:"true" description:"资源类型 (iot_card:IoT卡, device:设备, shop:店铺, order:订单, refund:退款单)"`
|
||||
Keyword string `json:"keyword" query:"keyword" required:"true" description:"精确业务标识;卡支持ICCID/VirtualNo,设备支持VirtualNo/IMEI/SN"`
|
||||
Page int `json:"page" query:"page" minimum:"1" description:"页码,默认1"`
|
||||
PageSize int `json:"page_size" query:"page_size" minimum:"1" maximum:"100" description:"每页数量,默认20,最大100"`
|
||||
}
|
||||
|
||||
// AuditResourceTimelineRequest 是通用资源时间线参数。
|
||||
type AuditResourceTimelineRequest struct {
|
||||
ResourceType string `json:"resource_type" path:"resource_type" required:"true" description:"Resource Registry 注册类型"`
|
||||
ResourceID string `json:"resource_id" path:"resource_id" required:"true" description:"资源内部稳定ID"`
|
||||
CreatedFrom string `json:"created_from" query:"created_from" description:"开始时间(RFC3339,含时区)"`
|
||||
CreatedTo string `json:"created_to" query:"created_to" description:"结束时间(RFC3339,含时区,不包含该时刻)"`
|
||||
Action string `json:"action" query:"action" description:"稳定动作编码"`
|
||||
Result string `json:"result" query:"result" description:"事件结果"`
|
||||
Page int `json:"page" query:"page" minimum:"1" description:"页码,默认1"`
|
||||
PageSize int `json:"page_size" query:"page_size" minimum:"1" maximum:"100" description:"每页数量,默认20,最大100"`
|
||||
}
|
||||
|
||||
// SubjectResourceActivityRequest 是代理和企业安全资源活动的路径及分页参数。
|
||||
type SubjectResourceActivityRequest struct {
|
||||
ResourceType string `json:"resource_type" path:"resource_type" required:"true" description:"资源类型 (iot_card:IoT卡, device:设备, asset_allocation_record:资产分配记录, exchange_order:换货单, shop:店铺, enterprise:企业)"`
|
||||
Identifier string `json:"identifier" path:"identifier" required:"true" description:"业务稳定标识;卡使用ICCID,设备使用VirtualNo,其他资源使用对应业务编号"`
|
||||
Page int `json:"page" query:"page" minimum:"1" description:"页码,默认1"`
|
||||
PageSize int `json:"page_size" query:"page_size" minimum:"1" maximum:"100" description:"每页数量,默认20,最大100"`
|
||||
}
|
||||
|
||||
// IntegrationFilterRequest 是外部集成调查的公共受控筛选参数。
|
||||
type IntegrationFilterRequest struct {
|
||||
CreatedFrom string `json:"created_from" query:"created_from" required:"true" description:"开始时间(RFC3339,含时区,必填)"`
|
||||
CreatedTo string `json:"created_to" query:"created_to" required:"true" description:"结束时间(RFC3339,含时区,不包含该时刻,必填)"`
|
||||
IntegrationID string `json:"integration_id" query:"integration_id" description:"稳定外部集成记录ID"`
|
||||
Provider string `json:"provider" query:"provider" description:"外部服务提供方稳定编码"`
|
||||
Direction string `json:"direction" query:"direction" description:"交互方向 (inbound:入站, outbound:出站)"`
|
||||
Operation string `json:"operation" query:"operation" description:"外部操作稳定编码"`
|
||||
Result string `json:"result" query:"result" description:"原始结果 (pending:待处理, success:成功, failed:失败, unknown:结果未知, not_found:未找到, invalid_payload:无效载荷, conflict:冲突, ignored:已忽略, merged:已合并, rate_limited:已限频, completed:已提前完成, cancelled:已取消)"`
|
||||
ResultCategory string `json:"result_category" query:"result_category" description:"派生结果类别 (processing:处理中, succeeded:成功, indeterminate:结果不确定, failed:失败, not_sent:未发送)"`
|
||||
ExternalID string `json:"external_id" query:"external_id" description:"外部系统业务或请求标识"`
|
||||
ResourceType string `json:"resource_type" query:"resource_type" description:"本地主要资源类型"`
|
||||
ResourceID string `json:"resource_id" query:"resource_id" description:"本地主要资源稳定ID"`
|
||||
ResourceKey string `json:"resource_key" query:"resource_key" description:"本地主要资源稳定Key"`
|
||||
TriggerSource string `json:"trigger_source" query:"trigger_source" description:"触发来源稳定编码"`
|
||||
TriggerScene string `json:"trigger_scene" query:"trigger_scene" description:"触发业务场景"`
|
||||
TriggerSeries string `json:"trigger_series" query:"trigger_series" description:"显式技术尝试序列ID"`
|
||||
StateChanged *bool `json:"state_changed" query:"state_changed" description:"是否改变本地业务状态"`
|
||||
HTTPStatus *int `json:"http_status" query:"http_status" minimum:"100" maximum:"599" description:"外部HTTP响应状态码"`
|
||||
ProviderCode string `json:"provider_code" query:"provider_code" description:"外部服务稳定结果码"`
|
||||
RequestID string `json:"request_id" query:"request_id" description:"来源HTTP请求ID"`
|
||||
CorrelationID string `json:"correlation_id" query:"correlation_id" description:"跨步骤业务链路ID"`
|
||||
}
|
||||
|
||||
// IntegrationOverviewRequest 是外部集成交互总览参数。
|
||||
type IntegrationOverviewRequest struct {
|
||||
IntegrationFilterRequest
|
||||
Bucket string `json:"bucket" query:"bucket" description:"趋势时间粒度 (hour:小时, day:自然日),默认hour"`
|
||||
}
|
||||
|
||||
// IntegrationListRequest 是外部集成交互列表参数。
|
||||
type IntegrationListRequest struct {
|
||||
IntegrationFilterRequest
|
||||
Page int `json:"page" query:"page" minimum:"1" description:"页码,默认1"`
|
||||
PageSize int `json:"page_size" query:"page_size" minimum:"1" maximum:"100" description:"每页数量,默认20,最大100"`
|
||||
}
|
||||
|
||||
// IntegrationIDParams 是外部集成详情路径参数。
|
||||
type IntegrationIDParams struct {
|
||||
IntegrationID string `json:"integration_id" path:"integration_id" required:"true" description:"稳定外部集成记录ID,来自列表、通知target_key或调查节点"`
|
||||
}
|
||||
@@ -163,7 +163,6 @@ type ShopBusinessOwnerCandidatePageResult struct {
|
||||
type UpdateShopCreditLimitRequest struct {
|
||||
CreditEnabled *bool `json:"credit_enabled" validate:"required" required:"true" description:"是否启用实际信用额度"`
|
||||
CreditLimit *int64 `json:"credit_limit" validate:"required,min=0" required:"true" minimum:"0" description:"实际信用额度(分);关闭时必须为0"`
|
||||
Version *int `json:"version" validate:"required,min=0" required:"true" minimum:"0" description:"主钱包乐观锁版本"`
|
||||
}
|
||||
|
||||
// UpdateShopCreditLimitParams 调整既有店铺实际信用额度参数。
|
||||
|
||||
18
internal/model/dto/shop_dto_test.go
Normal file
18
internal/model/dto/shop_dto_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestUpdateShopCreditLimitRequestDoesNotExposeVersion 验证乐观锁版本不属于前端调额契约。
|
||||
func TestUpdateShopCreditLimitRequestDoesNotExposeVersion(t *testing.T) {
|
||||
typeOfRequest := reflect.TypeOf(UpdateShopCreditLimitRequest{})
|
||||
for i := 0; i < typeOfRequest.NumField(); i++ {
|
||||
jsonName := strings.Split(typeOfRequest.Field(i).Tag.Get("json"), ",")[0]
|
||||
if jsonName == "version" {
|
||||
t.Fatal("调额请求不应暴露由服务端管理的乐观锁版本")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ type IntegrationLog struct {
|
||||
Metadata datatypes.JSON `gorm:"column:metadata;type:jsonb" json:"metadata,omitempty"`
|
||||
RecoveryStrategy *string `gorm:"column:recovery_strategy;type:varchar(255)" json:"recovery_strategy,omitempty"`
|
||||
RequestID *string `gorm:"column:request_id;type:varchar(64)" json:"request_id,omitempty"`
|
||||
CorrelationID *string `gorm:"column:correlation_id;type:varchar(64)" json:"correlation_id,omitempty"`
|
||||
CorrelationID *string `gorm:"column:correlation_id;type:varchar(100)" json:"correlation_id,omitempty"`
|
||||
AuditEventID *uint `gorm:"column:audit_event_id" json:"audit_event_id,omitempty"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null;autoUpdateTime" json:"updated_at"`
|
||||
|
||||
@@ -19,6 +19,7 @@ type OutboxEvent struct {
|
||||
BusinessKey string `gorm:"column:business_key;type:varchar(150);not null;default:''" json:"business_key,omitempty"`
|
||||
RequestID string `gorm:"column:request_id;type:varchar(100);not null;default:'';index" json:"request_id,omitempty"`
|
||||
CorrelationID string `gorm:"column:correlation_id;type:varchar(100);not null;default:'';index" json:"correlation_id,omitempty"`
|
||||
ParentEventID string `gorm:"column:parent_event_id;type:varchar(64);not null;default:'';index" json:"parent_event_id,omitempty"`
|
||||
Payload datatypes.JSON `gorm:"column:payload;type:jsonb;not null" json:"payload"`
|
||||
Status int `gorm:"column:status;type:int;not null;default:1;index:idx_outbox_event_type_status,priority:2" json:"status"`
|
||||
RetryCount int `gorm:"column:retry_count;type:int;not null;default:0" json:"retry_count"`
|
||||
|
||||
Reference in New Issue
Block a user