This commit is contained in:
@@ -1,5 +1,63 @@
|
||||
package constants
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
// AuditRiskQueryMaxRange 是风险调查允许的最大连续时间范围。
|
||||
AuditRiskQueryMaxRange = 31 * 24 * time.Hour
|
||||
// AuditRiskHourlyTrendMaxRange 是风险趋势使用小时粒度的最大时间范围。
|
||||
AuditRiskHourlyTrendMaxRange = 72 * time.Hour
|
||||
// AuditRiskSignalHighRisk 表示高风险或严重风险信号。
|
||||
AuditRiskSignalHighRisk = "high_risk"
|
||||
// AuditRiskSignalFinance 表示涉及资金资源的风险信号。
|
||||
AuditRiskSignalFinance = "finance"
|
||||
// AuditRiskSignalSecurity 表示安全类别风险信号。
|
||||
AuditRiskSignalSecurity = "security"
|
||||
// AuditRiskSignalFailed 表示执行失败信号。
|
||||
AuditRiskSignalFailed = "failed"
|
||||
// AuditRiskSignalDenied 表示业务或权限拒绝信号。
|
||||
AuditRiskSignalDenied = "denied"
|
||||
// AuditRiskSignalPartial 表示部分成功信号。
|
||||
AuditRiskSignalPartial = "partial"
|
||||
// AuditRiskSignalUnknown 表示结果未知信号。
|
||||
AuditRiskSignalUnknown = "unknown"
|
||||
)
|
||||
|
||||
const (
|
||||
// AuditRecordSourceAuditEvent 表示统一内部审计事件节点。
|
||||
AuditRecordSourceAuditEvent = "audit_event"
|
||||
// AuditRecordSourceIntegrationLog 表示外部交互日志节点。
|
||||
AuditRecordSourceIntegrationLog = "integration_log"
|
||||
// AuditRecordSourceOutboxEvent 表示可靠事件投递摘要节点。
|
||||
AuditRecordSourceOutboxEvent = "outbox_event"
|
||||
// AuditRecordSourceAsynqTask 表示具有持久化任务资源的异步任务摘要节点。
|
||||
AuditRecordSourceAsynqTask = "asynq_task"
|
||||
// AuditRecordSourceDomainLedgerRef 表示业务权威表的稳定引用节点。
|
||||
AuditRecordSourceDomainLedgerRef = "domain_ledger_ref"
|
||||
// AuditRecordSourceAgentWalletTransaction 表示代理钱包权威流水节点。
|
||||
AuditRecordSourceAgentWalletTransaction = "agent_wallet_transaction"
|
||||
// AuditRecordSourceAssetWalletTransaction 表示资产钱包权威流水节点。
|
||||
AuditRecordSourceAssetWalletTransaction = "asset_wallet_transaction"
|
||||
// AuditRecordSourceAgentWalletReservation 表示代理钱包预占事实节点。
|
||||
AuditRecordSourceAgentWalletReservation = "agent_wallet_reservation"
|
||||
// AuditRecordSourceOrder 表示订单业务事实节点。
|
||||
AuditRecordSourceOrder = "order"
|
||||
// AuditRecordSourcePayment 表示支付业务事实节点。
|
||||
AuditRecordSourcePayment = "payment"
|
||||
// AuditRecordSourceRefund 表示退款业务事实节点。
|
||||
AuditRecordSourceRefund = "refund"
|
||||
// AuditRecordSourceAgentRecharge 表示代理充值业务事实节点。
|
||||
AuditRecordSourceAgentRecharge = "agent_recharge"
|
||||
// AuditRecordSourceRechargeOrder 表示个人资产充值业务事实节点。
|
||||
AuditRecordSourceRechargeOrder = "recharge_order"
|
||||
// AuditRecordSourceCommissionRecord 表示佣金业务事实节点。
|
||||
AuditRecordSourceCommissionRecord = "commission_record"
|
||||
// AuditRecordSourceCommissionWithdrawal 表示佣金提现业务事实节点。
|
||||
AuditRecordSourceCommissionWithdrawal = "commission_withdrawal"
|
||||
// AuditRecordSourceApprovalInstance 表示审批业务事实节点。
|
||||
AuditRecordSourceApprovalInstance = "approval_instance"
|
||||
)
|
||||
|
||||
const (
|
||||
// AuditActionAccountCreated 表示创建账号。
|
||||
AuditActionAccountCreated = "account.created"
|
||||
@@ -105,6 +163,12 @@ const (
|
||||
AuditActionIotCardManualRefreshed = "iot_card.manual_refresh"
|
||||
// AuditActionIotCardPersonalRefreshed 表示个人客户刷新名下 IoT 卡并同步实际变化的内部事实。
|
||||
AuditActionIotCardPersonalRefreshed = "iot_card.personal_refresh"
|
||||
// AuditActionIotCardWorkerRealnameSynced 表示 Worker 观测并同步 IoT 卡实名事实。
|
||||
AuditActionIotCardWorkerRealnameSynced = "iot_card.worker_realname_sync"
|
||||
// AuditActionIotCardWorkerTrafficSynced 表示 Worker 观测并同步 IoT 卡流量事实。
|
||||
AuditActionIotCardWorkerTrafficSynced = "iot_card.worker_traffic_sync"
|
||||
// AuditActionIotCardWorkerNetworkSynced 表示 Worker 观测并同步 IoT 卡网络事实。
|
||||
AuditActionIotCardWorkerNetworkSynced = "iot_card.worker_network_sync"
|
||||
// AuditActionIotCardManualStopped 表示人工停用 IoT 卡网络。
|
||||
AuditActionIotCardManualStopped = "iot_card.manual_stop"
|
||||
// AuditActionIotCardManualStarted 表示人工恢复 IoT 卡网络。
|
||||
@@ -155,6 +219,8 @@ const (
|
||||
AuditActionDeviceCardUnbound = "device.unbind_card"
|
||||
// AuditActionDeviceCurrentCardSwitched 表示切换设备当前使用的 IoT 卡。
|
||||
AuditActionDeviceCurrentCardSwitched = "device.switch_current_card"
|
||||
// AuditActionDeviceWorkerObservationSynced 表示 Worker 根据 Gateway 观测同步设备及当前卡槽事实。
|
||||
AuditActionDeviceWorkerObservationSynced = "device.worker_observation_sync"
|
||||
// AuditActionCardExchangeCreated 表示创建卡换货单。
|
||||
AuditActionCardExchangeCreated = "exchange.card.create"
|
||||
// AuditActionCardExchangeShippingInfoSubmitted 表示个人客户提交卡换货收货信息。
|
||||
@@ -369,6 +435,8 @@ const (
|
||||
AuditActionNotificationCleanup = "notification.cleanup"
|
||||
// AuditActionNotificationCleanupItem 表示系统清理单条过期通知。
|
||||
AuditActionNotificationCleanupItem = "notification.cleanup_item"
|
||||
// AuditActionLogRetentionCleanup 表示留存任务物理清理已归档在线日志。
|
||||
AuditActionLogRetentionCleanup = "audit.retention_cleanup"
|
||||
// AuditActionPollingConfigCreated 表示创建轮询配置。
|
||||
AuditActionPollingConfigCreated = "polling_config.create"
|
||||
// AuditActionPollingConfigUpdated 表示更新轮询配置。
|
||||
@@ -466,6 +534,8 @@ const (
|
||||
AuditResourceOutboxEvent = "outbox_event"
|
||||
// AuditResourceIntegrationLog 表示外部集成日志资源。
|
||||
AuditResourceIntegrationLog = "integration_log"
|
||||
// AuditResourceLogArchiveMonth 表示已归档日志自然月。
|
||||
AuditResourceLogArchiveMonth = "log_archive_month"
|
||||
// AuditResourceDeviceBatchTask 表示设备批量分配任务资源。
|
||||
AuditResourceDeviceBatchTask = "device_batch_task"
|
||||
// AuditResourceIotCardImportTask 表示 IoT 卡导入任务资源。
|
||||
@@ -598,10 +668,14 @@ const (
|
||||
AuditResourceRoleApprovalIntegration = "approval_integration"
|
||||
// AuditResourceRoleCallbackIntegration 表示外部回调对应的集成交互事实。
|
||||
AuditResourceRoleCallbackIntegration = "callback_integration"
|
||||
// AuditResourceRoleWorkerIntegration 表示 Worker 外部观测对应的集成交互事实。
|
||||
AuditResourceRoleWorkerIntegration = "worker_integration"
|
||||
// AuditResourceRoleApprovalOutbox 表示审批链路对应的可靠 Outbox 事实。
|
||||
AuditResourceRoleApprovalOutbox = "approval_outbox"
|
||||
// AuditResourceRoleBatchTask 表示批量根事件的任务资源。
|
||||
AuditResourceRoleBatchTask = "batch_task"
|
||||
// AuditResourceRoleRetentionMonth 表示留存清理目标自然月。
|
||||
AuditResourceRoleRetentionMonth = "retention_month"
|
||||
// AuditResourceRoleBatchItem 表示批量子事件的单项资源。
|
||||
AuditResourceRoleBatchItem = "batch_item"
|
||||
// AuditResourceRoleNotificationTarget 表示本次写操作的通知资源。
|
||||
@@ -897,6 +971,8 @@ const (
|
||||
AuditActorIDRefundCommissionPostProcessing = "refund_commission_post_processing"
|
||||
// AuditActorIDCommissionCalculationWorker 表示订单佣金计算任务。
|
||||
AuditActorIDCommissionCalculationWorker = "commission_calculation_worker"
|
||||
// AuditActorIDRetentionWorker 表示日志留存清理任务。
|
||||
AuditActorIDRetentionWorker = "retention_worker"
|
||||
// AuditSourceAdminAPI 表示后台管理 API 入口。
|
||||
AuditSourceAdminAPI = "admin_api"
|
||||
// AuditSourcePersonalAPI 表示个人客户 API 入口。
|
||||
|
||||
37
pkg/constants/audit_archive.go
Normal file
37
pkg/constants/audit_archive.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
// TaskTypeAuditDailyArchive 表示统一审计每日冷归档任务。
|
||||
TaskTypeAuditDailyArchive = "audit:daily:archive"
|
||||
// TaskTypeIntegrationDailyArchive 表示 Integration Log 每日冷归档任务。
|
||||
TaskTypeIntegrationDailyArchive = "integration:daily:archive"
|
||||
// TaskTypeIntegrationMonthlyFinalize 表示 Integration Log 月度最终版本复核任务。
|
||||
TaskTypeIntegrationMonthlyFinalize = "integration:monthly:finalize"
|
||||
// TaskTypeAuditMonthlyRetention 表示审计日志月度物理清理任务。
|
||||
TaskTypeAuditMonthlyRetention = "audit:monthly:retention"
|
||||
|
||||
// AuditArchiveSource 表示 Audit Event 与 Event Resource 归档数据源。
|
||||
AuditArchiveSource = "audit"
|
||||
// AuditArchiveSchemaVersion 表示审计归档 JSONL 结构版本。
|
||||
AuditArchiveSchemaVersion = "v1"
|
||||
// AuditArchiveTimezone 表示审计归档自然日时区。
|
||||
AuditArchiveTimezone = "Asia/Shanghai"
|
||||
// AuditArchiveInstanceID 表示当前单库审计归档实例。
|
||||
AuditArchiveInstanceID = "primary"
|
||||
// IntegrationArchiveSource 表示 Integration Log 归档数据源。
|
||||
IntegrationArchiveSource = "integration"
|
||||
// IntegrationArchiveSchemaVersion 表示 Integration Log 归档 JSONL 结构版本。
|
||||
IntegrationArchiveSchemaVersion = "v1"
|
||||
|
||||
// ArchiveStatusPending 表示归档任务等待执行。
|
||||
ArchiveStatusPending = "pending"
|
||||
// ArchiveStatusRunning 表示归档任务正在执行。
|
||||
ArchiveStatusRunning = "running"
|
||||
// ArchiveStatusSuccess 表示归档对象与 metadata 已复核成功。
|
||||
ArchiveStatusSuccess = "success"
|
||||
// ArchiveStatusFailed 表示归档任务执行失败并等待重试。
|
||||
ArchiveStatusFailed = "failed"
|
||||
|
||||
// AuditRetentionDeleteBatchSize 表示月度物理清理单批删除上限。
|
||||
AuditRetentionDeleteBatchSize = 1000
|
||||
)
|
||||
@@ -298,6 +298,8 @@ func QueueForTaskType(taskType string) string {
|
||||
return QueueDataCleanup
|
||||
case TaskTypeDailyTrafficFlush:
|
||||
return QueueDailyTrafficFlush
|
||||
case TaskTypeAuditDailyArchive, TaskTypeIntegrationDailyArchive, TaskTypeIntegrationMonthlyFinalize, TaskTypeAuditMonthlyRetention:
|
||||
return QueueDataCleanup
|
||||
case TaskTypeOutboxDeliver:
|
||||
return QueueOutboxDeliver
|
||||
case TaskTypeCardObservationSeries:
|
||||
|
||||
@@ -152,6 +152,7 @@ const (
|
||||
ReferenceTypeCommission = "commission" // 分佣
|
||||
ReferenceTypeWithdrawal = "withdrawal" // 提现
|
||||
ReferenceTypeTopup = "topup" // 充值
|
||||
ReferenceTypeRecharge = "recharge" // 个人资产充值支付
|
||||
ReferenceTypeRefund = "refund" // 退款
|
||||
ReferenceTypeExchange = "exchange" // 换货
|
||||
ReferenceTypeManualAdjustment = "manual_adjustment" // 人工余额调整
|
||||
|
||||
@@ -173,6 +173,9 @@ const (
|
||||
CodeWeComApplicationNotFound = 1210 // 企业微信应用配置不存在
|
||||
CodeWeComCredentialInvalid = 1211 // 企业微信加密凭据不可用
|
||||
|
||||
// 审计留存相关错误 (1220-1229)
|
||||
CodeAuditDataArchived = 1220 // 查询范围已归档,当前不支持在线查询
|
||||
|
||||
// 服务端错误 (2000-2999) -> 5xx HTTP 状态码
|
||||
CodeInternalError = 2001 // 内部服务器错误
|
||||
CodeDatabaseError = 2002 // 数据库错误
|
||||
@@ -316,6 +319,7 @@ var allErrorCodes = []int{
|
||||
CodePaymentMethodUnavailable,
|
||||
CodeWeComApplicationNotFound,
|
||||
CodeWeComCredentialInvalid,
|
||||
CodeAuditDataArchived,
|
||||
CodeInternalError,
|
||||
CodeDatabaseError,
|
||||
CodeRedisError,
|
||||
@@ -453,6 +457,7 @@ var errorMessages = map[int]string{
|
||||
CodePaymentMethodUnavailable: "当前资产不支持所选支付方式",
|
||||
CodeWeComApplicationNotFound: "企业微信应用配置不存在或已禁用",
|
||||
CodeWeComCredentialInvalid: "企业微信凭据配置无效",
|
||||
CodeAuditDataArchived: "数据已归档,第一阶段不支持在线查询",
|
||||
CodeInvalidCredentials: "用户名或密码错误",
|
||||
CodeAccountLocked: "账号已锁定",
|
||||
CodePasswordExpired: "密码已过期",
|
||||
@@ -499,6 +504,8 @@ func GetHTTPStatus(code int) int {
|
||||
return 403 // Forbidden
|
||||
case CodeNotFound:
|
||||
return 404 // Not Found
|
||||
case CodeAuditDataArchived:
|
||||
return 410 // Gone
|
||||
case CodeConflict,
|
||||
CodeUsernameExists,
|
||||
CodePhoneExists,
|
||||
|
||||
@@ -28,6 +28,7 @@ type AppError struct {
|
||||
Code int // 应用错误码
|
||||
Message string // 错误消息
|
||||
Err error // 底层错误(可选)
|
||||
Data any // 可安全返回的结构化错误上下文(可选)
|
||||
}
|
||||
|
||||
func (e *AppError) Error() string {
|
||||
@@ -59,6 +60,13 @@ func New(code int, customMsg ...string) *AppError {
|
||||
}
|
||||
}
|
||||
|
||||
// NewWithData 创建携带安全结构化上下文的 AppError。
|
||||
func NewWithData(code int, data any, customMsg ...string) *AppError {
|
||||
err := New(code, customMsg...)
|
||||
err.Data = data
|
||||
return err
|
||||
}
|
||||
|
||||
// Wrap 用错误码和消息包装现有错误
|
||||
// 优先使用 errorMessages 映射表中的消息,允许通过可选参数覆盖
|
||||
// 用法:
|
||||
|
||||
@@ -51,6 +51,7 @@ func handleError(c *fiber.Ctx, err error, logger *zap.Logger) error {
|
||||
var code int
|
||||
var message string
|
||||
var httpStatus int
|
||||
var data any
|
||||
|
||||
var appErr *AppError
|
||||
var fiberErr *fiber.Error
|
||||
@@ -60,6 +61,7 @@ func handleError(c *fiber.Ctx, err error, logger *zap.Logger) error {
|
||||
code = appErr.Code
|
||||
message = appErr.Message
|
||||
httpStatus = GetHTTPStatus(appErr.Code)
|
||||
data = appErr.Data
|
||||
|
||||
// 记录错误日志(包含完整上下文)
|
||||
logFields := append(errCtx.ToLogFields(),
|
||||
@@ -116,7 +118,7 @@ func handleError(c *fiber.Ctx, err error, logger *zap.Logger) error {
|
||||
// 6. 返回统一 JSON 响应
|
||||
errResp := c.Status(httpStatus).JSON(fiber.Map{
|
||||
"code": code,
|
||||
"data": nil,
|
||||
"data": data,
|
||||
"msg": message,
|
||||
"timestamp": time.Now().Format(time.RFC3339),
|
||||
})
|
||||
|
||||
@@ -59,11 +59,17 @@ func NewS3Provider(cfg *config.StorageConfig) (*S3Provider, error) {
|
||||
}
|
||||
|
||||
func (p *S3Provider) Upload(ctx context.Context, key string, reader io.Reader, contentType string) error {
|
||||
return p.UploadWithMetadata(ctx, key, reader, contentType, nil)
|
||||
}
|
||||
|
||||
// UploadWithMetadata 上传对象并保存用于完整性复核的 metadata。
|
||||
func (p *S3Provider) UploadWithMetadata(ctx context.Context, key string, reader io.Reader, contentType string, metadata map[string]string) error {
|
||||
input := &s3manager.UploadInput{
|
||||
Bucket: aws.String(p.bucket),
|
||||
Key: aws.String(key),
|
||||
Body: reader,
|
||||
ContentType: aws.String(contentType),
|
||||
Metadata: aws.StringMap(metadata),
|
||||
}
|
||||
|
||||
_, err := p.uploader.UploadWithContext(ctx, input)
|
||||
@@ -73,6 +79,26 @@ func (p *S3Provider) Upload(ctx context.Context, key string, reader io.Reader, c
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stat 读取对象大小、内容类型和 metadata。
|
||||
func (p *S3Provider) Stat(ctx context.Context, key string) (*ObjectMetadata, error) {
|
||||
result, err := p.client.HeadObjectWithContext(ctx, &s3.HeadObjectInput{
|
||||
Bucket: aws.String(p.bucket),
|
||||
Key: aws.String(key),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取对象 metadata 失败: %w", err)
|
||||
}
|
||||
metadata := make(map[string]string, len(result.Metadata))
|
||||
for name, value := range result.Metadata {
|
||||
metadata[strings.ToLower(name)] = aws.StringValue(value)
|
||||
}
|
||||
return &ObjectMetadata{
|
||||
Size: aws.Int64Value(result.ContentLength),
|
||||
ContentType: aws.StringValue(result.ContentType),
|
||||
Metadata: metadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *S3Provider) Download(ctx context.Context, key string) (io.ReadCloser, error) {
|
||||
input := &s3.GetObjectInput{
|
||||
Bucket: aws.String(p.bucket),
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
|
||||
type Provider interface {
|
||||
Upload(ctx context.Context, key string, reader io.Reader, contentType string) error
|
||||
UploadWithMetadata(ctx context.Context, key string, reader io.Reader, contentType string, metadata map[string]string) error
|
||||
Stat(ctx context.Context, key string) (*ObjectMetadata, error)
|
||||
Download(ctx context.Context, key string) (io.ReadCloser, error)
|
||||
DownloadToTemp(ctx context.Context, key string) (localPath string, cleanup func(), err error)
|
||||
Delete(ctx context.Context, key string) error
|
||||
@@ -15,3 +17,10 @@ type Provider interface {
|
||||
GetUploadURL(ctx context.Context, key string, contentType string, expires time.Duration) (string, error)
|
||||
GetDownloadURL(ctx context.Context, key string, expires time.Duration) (string, error)
|
||||
}
|
||||
|
||||
// ObjectMetadata 是对象存储返回的受控对象属性。
|
||||
type ObjectMetadata struct {
|
||||
Size int64
|
||||
ContentType string
|
||||
Metadata map[string]string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user