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

@@ -0,0 +1,39 @@
package postgres
import (
"context"
"strings"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"github.com/break/junhong_cmp_fiber/internal/model"
)
// GatewayReadonlyCardStore 网关只读资产存储。
type GatewayReadonlyCardStore struct {
db *gorm.DB
}
// NewGatewayReadonlyCardStore 创建网关只读资产存储。
func NewGatewayReadonlyCardStore(db *gorm.DB) *GatewayReadonlyCardStore {
return &GatewayReadonlyCardStore{db: db}
}
// IsReadonly 判断网关请求卡号(ICCID 或设备 IMEI)是否为只读资产;按唯一索引查询,不缓存。
func (s *GatewayReadonlyCardStore) IsReadonly(ctx context.Context, identifier string) (bool, error) {
var count int64
err := s.db.WithContext(ctx).Model(&model.GatewayReadonlyCard{}).
Where("identifier = ?", strings.ToUpper(strings.TrimSpace(identifier))).
Limit(1).Count(&count).Error
return count > 0, err
}
// BatchCreate 批量写入只读资产,卡号统一大写,已存在的跳过。
func (s *GatewayReadonlyCardStore) BatchCreate(ctx context.Context, rows []*model.GatewayReadonlyCard) error {
for _, row := range rows {
row.Identifier = strings.ToUpper(strings.TrimSpace(row.Identifier))
}
return s.db.WithContext(ctx).Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "identifier"}}, DoNothing: true}).
CreateInBatches(rows, 1000).Error
}