feat: 网关只读资产改为数据表,只读资产只允许查询类调用
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m36s

- 新增 tb_gateway_readonly_card(卡 ICCID / 设备 IMEI)与开关 JUNHONG_GATEWAY_READONLY_ENABLED,
  替换环境变量名单 JUNHONG_GATEWAY_READONLY_ICCIDS
- 只读资产只放行查卡状态、查实名、查流量、查设备信息、查设备槽位、同步设备状态;
  停机、复机、限速、实名认证链接与设备写操作在网关出口本地拦截;查表失败按拦截;不缓存
- 测试环境部署开启只读模式;新增技术方案与清理顺序文档

Change: add-gateway-readonly-prod-import

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
邹进
2026-10-29 17:55:52 +09:00
parent a7428c7924
commit 5cf67b98de
19 changed files with 536 additions and 41 deletions

View File

@@ -26,6 +26,7 @@ import (
internalMiddleware "github.com/break/junhong_cmp_fiber/internal/middleware"
"github.com/break/junhong_cmp_fiber/internal/routes"
"github.com/break/junhong_cmp_fiber/internal/service/verification"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/auth"
pkgbootstrap "github.com/break/junhong_cmp_fiber/pkg/bootstrap"
"github.com/break/junhong_cmp_fiber/pkg/config"
@@ -71,7 +72,7 @@ func main() {
storageSvc := initStorage(cfg, appLogger)
// 9. 初始化 Gateway 客户端(可选)
gatewayClient := initGateway(cfg, appLogger)
gatewayClient := initGateway(cfg, db, appLogger)
// 卡网关调用按本系统运营商账户限流与统计(默认只统计不拦截)。
gatewayLimit := gatewaylimit.NewRuntime(db, redisClient, appLogger)
if gatewayClient != nil {
@@ -448,7 +449,7 @@ func initStorage(cfg *config.Config, appLogger *zap.Logger) *storage.Service {
return storage.NewService(provider, &cfg.Storage)
}
func initGateway(cfg *config.Config, appLogger *zap.Logger) *gateway.Client {
func initGateway(cfg *config.Config, db *gorm.DB, appLogger *zap.Logger) *gateway.Client {
if cfg.Gateway.BaseURL == "" {
appLogger.Info("Gateway 未配置,跳过初始化")
return nil
@@ -459,7 +460,11 @@ func initGateway(cfg *config.Config, appLogger *zap.Logger) *gateway.Client {
cfg.Gateway.AppID,
cfg.Gateway.AppSecret,
appLogger,
).WithTimeout(time.Duration(cfg.Gateway.Timeout) * time.Second).WithReadonlyCards(cfg.Gateway.ReadonlyICCIDs)
).WithTimeout(time.Duration(cfg.Gateway.Timeout) * time.Second)
if cfg.Gateway.ReadonlyEnabled {
// 测试环境只读模式:只读资产表中的卡与设备只允许查询类调用(add-gateway-readonly-prod-import)。
client.WithReadonlyChecker(postgres.NewGatewayReadonlyCardStore(db).IsReadonly)
}
appLogger.Info("Gateway 客户端初始化成功",
zap.String("base_url", cfg.Gateway.BaseURL),

View File

@@ -294,7 +294,7 @@ func initWorkerRuntime(ctx context.Context, cfg *config.Config, appLogger *zap.L
}
storageSvc := initStorage(cfg, appLogger)
gatewayClient := initGateway(cfg, appLogger)
gatewayClient := initGateway(cfg, db, appLogger)
// 卡网关调用按本系统运营商账户限流与统计(默认只统计不拦截)。
gatewayLimit := gatewaylimit.NewRuntime(db, redisClient, appLogger)
if gatewayClient != nil {
@@ -1445,7 +1445,7 @@ func initStorage(cfg *config.Config, appLogger *zap.Logger) *storage.Service {
}
// initGateway 初始化 Gateway 客户端
func initGateway(cfg *config.Config, appLogger *zap.Logger) *gateway.Client {
func initGateway(cfg *config.Config, db *gorm.DB, appLogger *zap.Logger) *gateway.Client {
if cfg.Gateway.BaseURL == "" {
appLogger.Info("Gateway 未配置,跳过初始化(轮询任务将无法查询真实数据)")
return nil
@@ -1456,7 +1456,11 @@ func initGateway(cfg *config.Config, appLogger *zap.Logger) *gateway.Client {
cfg.Gateway.AppID,
cfg.Gateway.AppSecret,
appLogger,
).WithTimeout(time.Duration(cfg.Gateway.Timeout) * time.Second).WithReadonlyCards(cfg.Gateway.ReadonlyICCIDs)
).WithTimeout(time.Duration(cfg.Gateway.Timeout) * time.Second)
if cfg.Gateway.ReadonlyEnabled {
// 测试环境只读模式:只读资产表中的卡与设备只允许查询类调用(add-gateway-readonly-prod-import)。
client.WithReadonlyChecker(postgres.NewGatewayReadonlyCardStore(db).IsReadonly)
}
appLogger.Info("Gateway 客户端初始化成功",
zap.String("base_url", cfg.Gateway.BaseURL),