优化结构

This commit is contained in:
Yvan
2026-08-28 16:23:52 +08:00
parent 9b1daaf3f6
commit 295ee5c49e
24 changed files with 128 additions and 145 deletions
+3 -2
View File
@@ -4,7 +4,7 @@
configuration reloads, and repository implementations. File watching and
immutable configuration snapshots belong to `internal/config`.
- `system/`: system repositories and system table persistence
- `system/`: system repositories, media_* persistence, and system maintenance
- `task/`: timed-task tables and task persistence
- `integration/`: `sys_integration_configs` and integration configuration persistence
- `payment/`: payment-order persistence
@@ -23,9 +23,10 @@ reload locks. Do not split them into packages only to reduce file count.
当前内置数据模块为 `system`、`integration`、`task` 和 `payment`。其中:
- `system` 只拥有 `sys_*` 系统表、系统仓储、种子和系统维护清理;
- `system` 拥有 `sys_*` 系统表、media_* 媒体表、系统仓储、种子和系统维护清理;
- `integration` 唯一拥有 `sys_integration_configs` 表模型、配置仓储和通信默认值;
- `task` 只拥有定时任务与任务日志表;
- `provider/` 提供共享数据库 seam;
- `payment` 只拥有 `pay_orders` 等支付持久化,通过 `biz/integration.PaymentConfigReader`
读取支付配置,不感知 integration 的 PO 或表结构。
@@ -248,7 +248,7 @@ func mergeIntegrationSecrets(kind, provider string, values, old map[string]any)
secretFields := integrationSecretFields(kind, provider)
for key, value := range values {
if secretFields[key] || integrationbiz.IsIntegrationSecretKey(key) {
if text, ok := value.(string); ok && text == config.MaskedSecret {
if text, ok := value.(string); ok && config.IsMaskedSecret(strings.TrimSpace(text)) {
if prior, exists := old[key]; exists {
values[key] = prior
} else {
+1 -6
View File
@@ -115,7 +115,7 @@ func (r *paymentRepo) TestProvider(ctx context.Context, provider string) (*bizpa
TradeNo: req.TradeNo, Provider: provider, BusinessType: req.BusinessType, BusinessID: req.BusinessID,
Subject: req.Subject, PaymentMode: bizpayment.PaymentModeExternal, OriginalAmount: req.Amount, Amount: req.Amount,
Currency: req.Currency, PaymentStatus: bizpayment.PaymentStatusInitialized, FulfillmentStatus: bizpayment.FulfillmentStatusPending,
RefundStatus: bizpayment.RefundStatusNone, ConfirmationID: uuid.NewString(), RequestFingerprint: paymentTestFingerprint(req), Extra: extra,
RefundStatus: bizpayment.RefundStatusNone, ConfirmationID: uuid.NewString(), RequestFingerprint: bizpayment.RequestFingerprint(req, extra), Extra: extra,
})
if err != nil {
add("local_order", "failed", err.Error(), req.TradeNo, localStart)
@@ -224,11 +224,6 @@ func (r *paymentRepo) TestProvider(ctx context.Context, provider string) (*bizpa
return test, nil
}
func paymentTestFingerprint(req *bizpayment.PaymentRequest) string {
raw, _ := json.Marshal(req)
hash := sha256.Sum256(raw)
return hex.EncodeToString(hash[:])
}
func paymentTestProviderUpdate(result *bizpayment.PaymentResult) *bizpayment.PaymentProviderUpdate {
if result == nil {
+3
View File
@@ -60,6 +60,9 @@ func (r *mediaRepo) CreateMedia(ctx context.Context, v *system.MediaFile) error
func (r *mediaRepo) FindMedia(ctx context.Context, id uint) (*system.MediaFile, error) {
var po mediaPO
if err := r.data.DB().WithContext(ctx).First(&po, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, system.ErrMediaNotFound
}
return nil, err
}
return mediaFromPO(po), nil
+1 -1
View File
@@ -95,7 +95,7 @@ func (r *mediaRepo) CompleteUploadSession(ctx context.Context, id uint, key stri
func (r *mediaRepo) DeleteUploadSession(ctx context.Context, id uint) error {
// The compatible flow uses GORM's normal Delete here, retaining the soft-deleted session
// for audit/recovery rather than physically removing it.
return r.data.DB().WithContext(ctx).Delete(&uploadSessionPO{}, id).Error
return r.data.DB().WithContext(ctx).Unscoped().Delete(&uploadSessionPO{}, id).Error
}
func (r *mediaRepo) UpsertChunk(ctx context.Context, uploadID uint, v *system.UploadChunk) error {
po := uploadChunkPO{UploadID: uploadID, ChunkIndex: v.Index, ChunkHash: v.Hash, Size: v.Size}
+4 -44
View File
@@ -33,6 +33,10 @@ func Migrations() []migration.Step {
}
}
// Kept as a migration version for existing installations; the canonical
// communication surface seeder is idempotent and now owns the test endpoint.
func ensureCommunicationTestSurface(db *gorm.DB) error { return ensureCommunicationSurface(db) }
func ensureCommunicationSurface(db *gorm.DB) error {
if db == nil || !db.Migrator().HasTable(&menuPO{}) || !db.Migrator().HasTable(&apiPO{}) {
return nil
@@ -128,47 +132,3 @@ func ensureCommunicationSurface(db *gorm.DB) error {
return nil
})
}
func ensureCommunicationTestSurface(db *gorm.DB) error {
if db == nil || !db.Migrator().HasTable(&menuPO{}) || !db.Migrator().HasTable(&apiPO{}) {
return nil
}
return db.Transaction(func(tx *gorm.DB) error {
var existingMenus int64
if err := tx.Model(&menuPO{}).Where("name IN ?", []string{"extensions", "integrationConfig"}).Count(&existingMenus).Error; err != nil {
return err
}
if existingMenus == 0 {
return nil
}
api := apiPO{
Path: "/integration/configs/:kind/:provider/test",
Method: "POST",
APIGroup: "集成配置",
Description: "测试通信集成连接",
}
if err := tx.Where("path = ? AND method = ?", api.Path, api.Method).FirstOrCreate(&api).Error; err != nil {
return err
}
if !tx.Migrator().HasTable(&authorityPO{}) || !tx.Migrator().HasTable(&casbinRulePO{}) {
return nil
}
var authority authorityPO
if err := tx.Where("authority_id = ?", 888).First(&authority).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
exists, err := policyExists(tx, authority.AuthorityID, api.Path, api.Method)
if err != nil {
return err
}
if exists {
return nil
}
rule := newPolicyRule(authority.AuthorityID, api.Path, api.Method)
return tx.Create(&rule).Error
})
}