refactor(repository): 收敛 model/repository 分层为唯一持久化入口

将 OpenFlare 与平台业务的数据访问从 model 与 apps 直连迁入 repository,
model 仅保留实体与无 IO 规则;补充 code-check 架构守卫与开发规范。
This commit is contained in:
ryan
2026-07-24 17:00:17 +08:00
parent 23a5488203
commit 943818f7d4
184 changed files with 5592 additions and 4364 deletions
@@ -15,6 +15,8 @@ import (
"testing"
"time"
"github.com/Rain-kl/Wavelet/internal/repository"
oftls "github.com/Rain-kl/Wavelet/internal/apps/openflare/tls"
"github.com/Rain-kl/Wavelet/internal/infra/config"
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
@@ -76,7 +78,7 @@ func TestBuildSnapshotReadsZoneDomainCertificates(t *testing.T) {
require.NoError(t, err)
route := &model.ProxyRoute{SiteName: "tls-site", OriginURL: "http://origin:8080", Upstreams: `["http://origin:8080"]`, Enabled: true, EnableHTTPS: true}
require.NoError(t, model.CreateProxyRouteRecord(ctx, route))
require.NoError(t, repository.CreateProxyRouteRecord(ctx, route))
zone := &model.Zone{Domain: "example.com"}
require.NoError(t, db.DB(ctx).Create(zone).Error)
require.NoError(t, db.DB(ctx).Create(&model.ZoneDomain{ZoneID: zone.ID, ProxyRouteID: &route.ID, Domain: "one.example.com", CertID: &first.ID}).Error)
@@ -11,6 +11,8 @@ import (
"strconv"
"strings"
"github.com/Rain-kl/Wavelet/internal/repository"
"github.com/Rain-kl/Wavelet/internal/model"
)
@@ -208,7 +210,7 @@ func relayAgentAddress(node *model.OpenFlareNode) string {
}
func resolveTunnelOpenRestyUpstreamURL(ctx context.Context) string {
nodes, err := model.ListOpenFlareNodes(ctx)
nodes, err := repository.ListOpenFlareNodes(ctx)
if err == nil {
for index := range nodes {
node := &nodes[index]
@@ -230,7 +232,7 @@ func listWAFIPGroupsByIDs(ctx context.Context, ids []uint) ([]*model.OpenFlareWA
}
groups := make([]*model.OpenFlareWAFIPGroup, 0, len(ids))
for _, id := range ids {
group, err := model.GetOpenFlareWAFIPGroupByID(ctx, id)
group, err := repository.GetOpenFlareWAFIPGroupByID(ctx, id)
if err != nil {
return nil, err
}
@@ -14,6 +14,8 @@ import (
"strings"
"time"
"github.com/Rain-kl/Wavelet/internal/repository"
"github.com/Rain-kl/Wavelet/internal/apps/openflare/websocket"
"github.com/Rain-kl/Wavelet/internal/model"
pkgprotocol "github.com/Rain-kl/Wavelet/pkg/protocol"
@@ -75,17 +77,17 @@ type CleanupResult struct {
// ListConfigVersions returns all config version summaries.
func ListConfigVersions(ctx context.Context) ([]*model.ConfigVersionSummary, error) {
return model.ListConfigVersionSummaries(ctx)
return repository.ListConfigVersionSummaries(ctx)
}
// GetConfigVersionDetail returns a config version by version.
func GetConfigVersionDetail(ctx context.Context, version string) (*model.ConfigVersion, error) {
return model.GetConfigVersionByVersion(ctx, version)
return repository.GetConfigVersionByVersion(ctx, version)
}
// GetActiveConfigVersion returns the active config version.
func GetActiveConfigVersion(ctx context.Context) (*model.ConfigVersion, error) {
return model.GetActiveConfigVersion(ctx)
return repository.GetActiveConfigVersion(ctx)
}
// PreviewConfigVersion renders the current draft configuration.
@@ -123,7 +125,7 @@ func DiffConfigVersion(ctx context.Context) (*ConfigDiffResult, error) {
ChangedOptionDetails: []ConfigOptionDiffItem{},
CurrentWebsiteCount: len(bundle.SnapshotRoutes),
}
activeVersion, err := model.GetActiveConfigVersion(ctx)
activeVersion, err := repository.GetActiveConfigVersion(ctx)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
for _, route := range bundle.SnapshotRoutes {
@@ -203,7 +205,7 @@ func PublishConfigVersion(ctx context.Context, createdBy string, force bool) (*m
if len(bundle.Routes) == 0 {
return nil, errors.New(errNoEnabledRoutes)
}
activeVersion, err := model.GetActiveConfigVersion(ctx)
activeVersion, err := repository.GetActiveConfigVersion(ctx)
if !force && err == nil && activeVersion.Checksum == bundle.Checksum {
return nil, errors.New(errNoChangesToPublish)
}
@@ -228,7 +230,7 @@ func PublishConfigVersion(ctx context.Context, createdBy string, force bool) (*m
IsActive: true,
CreatedBy: createdBy,
}
if err = model.PublishConfigVersionTx(ctx, record); err != nil {
if err = repository.PublishConfigVersionTx(ctx, record); err != nil {
if isUniqueConstraintError(err) {
return nil, errors.New(errVersionConflict)
}
@@ -243,11 +245,11 @@ func PublishConfigVersion(ctx context.Context, createdBy string, force bool) (*m
// ActivateConfigVersion activates an existing config version.
func ActivateConfigVersion(ctx context.Context, versionStr string) (*model.ConfigVersion, error) {
version, err := model.GetConfigVersionByVersion(ctx, versionStr)
version, err := repository.GetConfigVersionByVersion(ctx, versionStr)
if err != nil {
return nil, err
}
if err = model.ActivateConfigVersionTx(ctx, versionStr); err != nil {
if err = repository.ActivateConfigVersionTx(ctx, versionStr); err != nil {
return nil, err
}
version.IsActive = true
@@ -263,7 +265,7 @@ func CleanupConfigVersions(ctx context.Context, keepCount int) (*CleanupResult,
if keepCount < minConfigVersionKeepCount {
keepCount = minConfigVersionKeepCount
}
versions, err := model.ListConfigVersionSummaries(ctx)
versions, err := repository.ListConfigVersionSummaries(ctx)
if err != nil {
return nil, err
}
@@ -283,7 +285,7 @@ func CleanupConfigVersions(ctx context.Context, keepCount int) (*CleanupResult,
if len(deleteVersions) == 0 {
return &CleanupResult{DeletedCount: 0, Message: cleanupSuccessMessage}, nil
}
deletedCount, err := model.DeleteConfigVersionsByVersions(ctx, deleteVersions)
deletedCount, err := repository.DeleteConfigVersionsByVersions(ctx, deleteVersions)
if err != nil {
return nil, err
}
@@ -292,7 +294,7 @@ func CleanupConfigVersions(ctx context.Context, keepCount int) (*CleanupResult,
func nextVersionNumber(ctx context.Context, now time.Time) (string, error) {
prefix := now.Format("20060102")
latest, err := model.GetLatestConfigVersionByPrefix(ctx, prefix)
latest, err := repository.GetLatestConfigVersionByPrefix(ctx, prefix)
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Sprintf("%s-%03d", prefix, 1), nil
}
@@ -10,6 +10,8 @@ import (
"testing"
"time"
"github.com/Rain-kl/Wavelet/internal/repository"
"github.com/Rain-kl/Wavelet/internal/apps/openflare/waf"
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
"github.com/Rain-kl/Wavelet/internal/model"
@@ -101,7 +103,7 @@ func TestPublishConfigVersionCreatesVersion(t *testing.T) {
Upstreams: `["http://origin.publish.example.com:8080"]`,
Enabled: true,
}
require.NoError(t, model.CreateProxyRouteRecord(ctx, route))
require.NoError(t, repository.CreateProxyRouteRecord(ctx, route))
createSnapshotZoneDomains(t, ctx, route, "publish.example.com")
version, err := PublishConfigVersion(ctx, "tester", false)
@@ -145,15 +147,15 @@ func TestBuildSnapshotWAFDocumentUsesNormalizedSiteNames(t *testing.T) {
Upstreams: `["http://origin.example.com:8080"]`,
Enabled: true,
}
require.NoError(t, model.CreateProxyRouteRecord(ctx, route))
require.NoError(t, repository.CreateProxyRouteRecord(ctx, route))
createSnapshotZoneDomains(t, ctx, route, "example.com", "www.example.com")
require.NoError(t, waf.EnsureDefaultRuleGroup(ctx))
globalGroup, err := model.GetGlobalOpenFlareWAFRuleGroup(ctx)
globalGroup, err := repository.GetGlobalOpenFlareWAFRuleGroup(ctx)
require.NoError(t, err)
customGroup := createSnapshotRule(t, ctx, "pow-group", waf.DefaultRuleGraph())
require.NoError(t, model.ReplaceOpenFlareWAFRuleGroupBindings(ctx, customGroup.ID, []uint{route.ID}))
require.NoError(t, repository.ReplaceOpenFlareWAFRuleGroupBindings(ctx, customGroup.ID, []uint{route.ID}))
bundle, err := buildCurrentConfigBundle(ctx, true)
require.NoError(t, err)
@@ -203,11 +205,11 @@ func TestBuildCurrentConfigBundleEnablesGlobalPoWWithoutExplicitBinding(t *testi
Upstreams: `["http://origin.example.com:8080"]`,
Enabled: true,
}
require.NoError(t, model.CreateProxyRouteRecord(ctx, route))
require.NoError(t, repository.CreateProxyRouteRecord(ctx, route))
createSnapshotZoneDomains(t, ctx, route, "pow-global.example.com")
require.NoError(t, waf.EnsureDefaultRuleGroup(ctx))
globalGroup, err := model.GetGlobalOpenFlareWAFRuleGroup(ctx)
globalGroup, err := repository.GetGlobalOpenFlareWAFRuleGroup(ctx)
require.NoError(t, err)
graphJSON, err := json.Marshal(snapshotPoWGraph())
require.NoError(t, err)
@@ -10,6 +10,8 @@ import (
"path"
"strings"
"github.com/Rain-kl/Wavelet/internal/repository"
"github.com/Rain-kl/Wavelet/internal/model"
"github.com/Rain-kl/Wavelet/pkg/pagesarchive"
openrestyrender "github.com/Rain-kl/Wavelet/pkg/render/openresty"
@@ -26,13 +28,13 @@ func buildPagesRouteSnapshot(
if route == nil {
return "", nil, nil, nil, errors.New("pages 路由配置无效")
}
if !model.HasPagesProjectsTable(ctx) {
if !repository.HasPagesProjectsTable(ctx) {
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 模块不可用", route.SiteName)
}
if route.PagesProjectID == nil || *route.PagesProjectID == 0 {
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: 未绑定 Pages 项目", route.SiteName)
}
project, err := model.GetPagesProjectByID(ctx, *route.PagesProjectID)
project, err := repository.GetPagesProjectByID(ctx, *route.PagesProjectID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 项目不存在", route.SiteName)
@@ -45,7 +47,7 @@ func buildPagesRouteSnapshot(
if project.ActiveDeploymentID == nil || *project.ActiveDeploymentID == 0 {
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 项目没有激活部署", route.SiteName)
}
activeDeployment, err := model.GetPagesDeploymentByID(ctx, *project.ActiveDeploymentID)
activeDeployment, err := repository.GetPagesDeploymentByID(ctx, *project.ActiveDeploymentID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return "", nil, nil, nil, fmt.Errorf("路由 %s Pages 配置无效: pages 激活部署不存在", route.SiteName)
@@ -8,6 +8,8 @@ import (
"encoding/json"
"testing"
"github.com/Rain-kl/Wavelet/internal/repository"
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
"github.com/Rain-kl/Wavelet/internal/model"
openrestyrender "github.com/Rain-kl/Wavelet/pkg/render/openresty"
@@ -52,7 +54,7 @@ func TestBuildSnapshotRoutesPages(t *testing.T) {
UpstreamType: "pages",
PagesProjectID: &project.ID,
}
require.NoError(t, model.CreateProxyRouteRecord(ctx, route))
require.NoError(t, repository.CreateProxyRouteRecord(ctx, route))
createSnapshotZoneDomains(t, ctx, route, "speedtest.arctel.net")
bundle, err := buildCurrentConfigBundle(ctx, true)
@@ -162,7 +162,7 @@ type configBundle struct {
}
func buildCurrentConfigBundle(ctx context.Context, requireRoutes bool) (*configBundle, error) {
routes, err := model.ListEnabledProxyRoutes(ctx)
routes, err := repository.ListEnabledProxyRoutes(ctx)
if err != nil {
return nil, err
}
@@ -224,7 +224,7 @@ func buildCurrentConfigBundle(ctx context.Context, requireRoutes bool) (*configB
func buildSnapshotRoutes(ctx context.Context, routes []*model.ProxyRoute) ([]snapshotRoute, error) {
items := make([]snapshotRoute, 0, len(routes))
for _, route := range routes {
zoneDomains, err := model.ListZoneDomainsByRouteID(ctx, route.ID)
zoneDomains, err := repository.ListZoneDomainsByRouteID(ctx, route.ID)
if err != nil {
return nil, err
}
@@ -310,7 +310,7 @@ func buildSnapshotWAFDocument(ctx context.Context, routes []*model.ProxyRoute) (
if err := waf.EnsureDefaultRuleGroup(ctx); err != nil {
return snapshotWAFDocument{}, err
}
groups, err := model.ListOpenFlareWAFRuleGroups(ctx)
groups, err := repository.ListOpenFlareWAFRuleGroups(ctx)
if err != nil {
return snapshotWAFDocument{}, err
}
@@ -349,7 +349,7 @@ func buildSnapshotWAFDocument(ctx context.Context, routes []*model.ProxyRoute) (
if route == nil {
continue
}
domains, domainErr := model.ListZoneDomainsByRouteID(ctx, route.ID)
domains, domainErr := repository.ListZoneDomainsByRouteID(ctx, route.ID)
if domainErr != nil {
return snapshotWAFDocument{}, domainErr
}
@@ -358,7 +358,7 @@ func buildSnapshotWAFDocument(ctx context.Context, routes []*model.ProxyRoute) (
}
enabledRouteSiteNames[route.ID] = route.SiteName
}
rawBindings, err := model.ListOpenFlareWAFRuleGroupBindings(ctx)
rawBindings, err := repository.ListOpenFlareWAFRuleGroupBindings(ctx)
if err != nil {
return snapshotWAFDocument{}, err
}
@@ -456,7 +456,7 @@ func buildSnapshotWAFIPGroups(ctx context.Context, idSet map[uint]struct{}) ([]s
}
func snapshotWAFIPGroupExists(ctx context.Context, id uint) (bool, error) {
group, err := model.GetOpenFlareWAFIPGroupByID(ctx, id)
group, err := repository.GetOpenFlareWAFIPGroupByID(ctx, id)
if errors.Is(err, gorm.ErrRecordNotFound) {
return false, nil
}
@@ -593,7 +593,7 @@ func buildCertificateSupportFiles(ctx context.Context, routes []snapshotRoute) (
sort.Slice(certIDs, func(i, j int) bool { return certIDs[i] < certIDs[j] })
files := make([]SupportFile, 0, len(certIDs)*supportFilesPerCertificate)
for _, certID := range certIDs {
certificate, err := model.GetTLSCertificateByID(ctx, certID)
certificate, err := repository.GetTLSCertificateByID(ctx, certID)
if err != nil {
return nil, err
}
@@ -9,6 +9,8 @@ import (
"strings"
"testing"
"github.com/Rain-kl/Wavelet/internal/repository"
"github.com/Rain-kl/Wavelet/internal/apps/openflare/waf"
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
"github.com/Rain-kl/Wavelet/internal/model"
@@ -51,7 +53,7 @@ func TestWAFGraphSnapshotPreservesOrderAndGraphReferences(t *testing.T) {
ctx := context.Background()
route := &model.ProxyRoute{SiteName: "ordered.example.com", OriginURL: "http://origin:8080", Upstreams: `["http://origin:8080"]`, Enabled: true}
require.NoError(t, model.CreateProxyRouteRecord(ctx, route))
require.NoError(t, repository.CreateProxyRouteRecord(ctx, route))
createSnapshotZoneDomains(t, ctx, route, route.SiteName)
referenced := &model.OpenFlareWAFIPGroup{Name: "referenced", Type: "manual", Enabled: true, IPList: `["192.0.2.1"]`}
@@ -61,7 +63,7 @@ func TestWAFGraphSnapshotPreservesOrderAndGraphReferences(t *testing.T) {
customA := createSnapshotRule(t, ctx, "custom-a", waf.DefaultRuleGraph())
customB := createSnapshotRule(t, ctx, "custom-b", snapshotIPMatchGraph(referenced.ID))
require.NoError(t, model.ReplaceOpenFlareWAFSiteRuleGroupBindings(ctx, route.ID, []uint{customB.ID, customA.ID}))
require.NoError(t, repository.ReplaceOpenFlareWAFSiteRuleGroupBindings(ctx, route.ID, []uint{customB.ID, customA.ID}))
snapshot, err := buildSnapshotWAFDocument(ctx, []*model.ProxyRoute{route})
require.NoError(t, err)
@@ -91,7 +93,7 @@ func TestWAFGraphSnapshotEncodesEmptyBindingsAsArrays(t *testing.T) {
ctx := context.Background()
route := &model.ProxyRoute{SiteName: "empty-binding.example.com", OriginURL: "http://origin:8080", Upstreams: `["http://origin:8080"]`, Enabled: true}
require.NoError(t, model.CreateProxyRouteRecord(ctx, route))
require.NoError(t, repository.CreateProxyRouteRecord(ctx, route))
createSnapshotZoneDomains(t, ctx, route, route.SiteName)
snapshot, err := buildSnapshotWAFDocument(ctx, []*model.ProxyRoute{route})