From 2fc6cd3a2d4d5dc48839b918879593c35929d863 Mon Sep 17 00:00:00 2001 From: zxr <271055687@qq.com> Date: Sun, 21 Jun 2026 18:27:35 +0800 Subject: [PATCH] fix --- README.md | 3 - TODOS.md | 15 +- docs/P1故障救援策略.md | 3 +- docs/P1测试计划.md | 5 +- ...ntegrated-ops-platform-blueprint-design.md | 5 +- ...project-structure-data-model-api-design.md | 1079 ----------------- docs/本地开发与验收部署说明.md | 12 +- server/.gitea/workflows/cicd.yaml | 113 -- server/.gitignore | 35 - server/Makefile | 27 - server/README.md | 183 --- server/cmd/cli/main.go | 42 - server/cmd/main/main.go | 74 -- server/etc/sample.env | 5 - server/etc/sample.service | 16 - server/etc/sample_dev.yaml | 27 - server/etc/sample_prod.yaml | 27 - server/etc/sample_test.yaml | 27 - server/go.mod | 80 -- server/go.sum | 227 ---- server/internal/config/config.go | 33 - server/internal/impl/new.go | 29 - server/internal/logic/demo/demo.go | 125 -- server/internal/logic/ping/hello.go | 10 - server/internal/models/query.go | 6 - server/internal/models/sample_demo.go | 86 -- server/internal/routers/register.go | 36 - server/scripts/build.sh | 9 - server/scripts/lint.sh | 5 - server/scripts/update.sh | 7 - server/test/demo/crud.http | 31 - server/test/ping/hello.http | 2 - server/test/readme.md | 2 - 33 files changed, 19 insertions(+), 2367 deletions(-) delete mode 100644 docs/superpowers/specs/2026-06-21-ops-project-structure-data-model-api-design.md delete mode 100644 server/.gitea/workflows/cicd.yaml delete mode 100644 server/.gitignore delete mode 100644 server/Makefile delete mode 100644 server/README.md delete mode 100644 server/cmd/cli/main.go delete mode 100644 server/cmd/main/main.go delete mode 100644 server/etc/sample.env delete mode 100644 server/etc/sample.service delete mode 100644 server/etc/sample_dev.yaml delete mode 100644 server/etc/sample_prod.yaml delete mode 100644 server/etc/sample_test.yaml delete mode 100644 server/go.mod delete mode 100644 server/go.sum delete mode 100644 server/internal/config/config.go delete mode 100644 server/internal/impl/new.go delete mode 100644 server/internal/logic/demo/demo.go delete mode 100644 server/internal/logic/ping/hello.go delete mode 100644 server/internal/models/query.go delete mode 100644 server/internal/models/sample_demo.go delete mode 100644 server/internal/routers/register.go delete mode 100644 server/scripts/build.sh delete mode 100644 server/scripts/lint.sh delete mode 100644 server/scripts/update.sh delete mode 100644 server/test/demo/crud.http delete mode 100644 server/test/ping/hello.http delete mode 100644 server/test/readme.md diff --git a/README.md b/README.md index 8638848..dc64c37 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,7 @@ OPS 是面向医院信息化场景的开发运维一体化平台,首期交付 | `docs/integrated-ops-platform-blueprint-design.md` | 平台蓝图、分期路线和审查结论。 | | `docs/首期验收矩阵.md` | OPS 需求到演示路径、数据准备、通过标准和证据的映射。 | | `docs/首期数据模型与状态机.md` | 第 1 阶段核心模型、状态机和存储分工。 | -| `docs/首期项目架构数据模型与接口设计.md` | 第 1 阶段可编码的项目架构、数据模型和 REST API 设计。 | | `docs/首期UI状态覆盖.md` | 第 1 阶段页面状态覆盖要求。 | -| `docs/P1故障救援策略.md` | 采集、解析、通知、派单失败的救援策略。 | -| `docs/P1测试计划.md` | 第 1 阶段后端、前端和端到端测试计划。 | | `docs/本地开发与验收部署说明.md` | 本地开发、联调验收和 Linux/麒麟部署边界。 | | `docs/H3C华三首批接入调研.md` | H3C/华三首批接入基线和现场确认表。 | | `docs/国产时序数据库选型验证.md` | TDengine、Apache IoTDB、openGemini 选型验证。 | diff --git a/TODOS.md b/TODOS.md index 625f396..9052ed1 100644 --- a/TODOS.md +++ b/TODOS.md @@ -30,33 +30,30 @@ ## P1 -- [x] 定义采集失败、Trap/Syslog 解析失败、通知失败、派单失败的错误与救援策略。 +- [] 定义采集失败、Trap/Syslog 解析失败、通知失败、派单失败的错误与救援策略。 - 原因:一体化运维平台自身故障不能静默,否则验收时无法证明平台可靠性。 - 验收:每类失败都有重试、降级、用户提示、日志、审计和测试要求。 - - 产物:`docs/P1故障救援策略.md`。 -- [x] 为第 1 阶段建立后端与前端测试计划。 +- [] 为第 1 阶段建立后端与前端测试计划。 - 原因:当前仓库尚无实际 `server/`、`web/` 工程,测试策略需要先指导实现。 - 验收:后端包含单元、接口、SQLite 内存库测试;前端包含类型检查、状态渲染和核心 E2E。 - - 产物:`docs/P1测试计划.md`。 -- [x] 使用 gstack 工程评审口径梳理首期架构、数据模型和接口设计。 +- [] 使用 gstack 工程评审口径梳理首期架构、数据模型和接口设计。 - 原因:P0/P1 文档已形成验收、状态机、UI 状态、救援和测试计划,但后续初始化 `server/`、`web/` 前还需要一份可编码的模块边界和 REST API 规格。 - 验收:文档包含后端/前端模块划分、核心数据流、数据模型、统一响应、错误码、API 路由、前端状态映射和实施顺序。 - - 产物:`docs/首期项目架构数据模型与接口设计.md`。 -- [x] 区分本地开发命令和验收部署说明。 +- [] 区分本地开发命令和验收部署说明。 - 原因:本地开发和调试使用 Windows PowerShell;会议已确认验收部署需要面向 Linux 与麒麟系统,模板 README 不能直接成为交付文档。 - 验收:实际 `server/`、`web/` 文档提供 Windows PowerShell 本地开发路径;`deploy/` 提供 Linux/麒麟部署、迁移、回滚和烟测说明,且不包含真实凭据。 - 产物:`docs/本地开发与验收部署说明.md`、`deploy/README.md`。 -- [x] 完成 H3C/华三设备首批接入调研。 +- [] 完成 H3C/华三设备首批接入调研。 - 原因:会议确认现场设备以 H3C/华三为主,第 1 阶段应优先适配该品牌常见指标、接口状态和 Trap/Syslog 样例。 - 验收:明确首批设备型号、SNMP 版本、OID 清单、Trap 字典、Syslog 样例、账号权限和网络连通性。 - 产物:`docs/H3C华三首批接入调研.md`。 - 风险:仓库现有资料未提供现场具体型号、SNMP 版本、真实 Trap/Syslog 样例和账号权限;文档已提供首批接入基线和现场确认表,正式验收前必须由院方或现场工程师补齐。 -- [x] 完成国产/国内生态时序数据库选型验证。 +- [] 完成国产/国内生态时序数据库选型验证。 - 原因:高频指标和采集样本不应全部压入 PostgreSQL,需要选型 TDengine、Apache IoTDB、openGemini 或其他合适产品。 - 验收:形成选型记录,覆盖 Linux/麒麟部署、Go 连接方式、批量写入、范围查询、聚合、降采样、保留策略、备份恢复和授权风险。 - 产物:`docs/国产时序数据库选型验证.md`。 diff --git a/docs/P1故障救援策略.md b/docs/P1故障救援策略.md index e09afb7..8a2474e 100644 --- a/docs/P1故障救援策略.md +++ b/docs/P1故障救援策略.md @@ -80,7 +80,7 @@ ### 5.1 处理流程 ```text ------------+ +-------------+ +----------------+ ++-----------+ +-------------+ +----------------+ | 接收原文 | ---> | 写 raw_events | ---> | 尝试字典/规则解析 | +-----------+ +-------------+ +----------------+ | @@ -170,4 +170,3 @@ | 页面截图 | 资源详情、未解析事件池、通知记录、派单失败提示。 | | 日志 | 能按 `traceId` 查询采集、解析、通知、派单链路。 | | 数据库记录 | `collector_runs`、`raw_events`、`notification_records`、`ticket_transitions` 有对应记录。 | - diff --git a/docs/P1测试计划.md b/docs/P1测试计划.md index 2d32d78..72f0f13 100644 --- a/docs/P1测试计划.md +++ b/docs/P1测试计划.md @@ -2,7 +2,7 @@ ## 1. 文档目标 -本文定义 OPS 第 1 阶段后端、前端和端到端测试范围。当前仓库尚未初始化 `server/`、`web/`,本文先作为编码前测试规格,后续实现必须按本文补齐测试。 +本文定义 OPS 第 1 阶段后端、前端和端到端测试范围。当前仓库尚未保留实际 `server/`、`web/` 工程;本文作为编码和联调前测试规格,后续实现必须按本文补齐测试。 ## 2. 测试分层 @@ -73,7 +73,7 @@ ## 6. 本地验证命令 -后端初始化后至少运行: +后端至少运行: ```powershell Set-Location .\server @@ -111,4 +111,3 @@ pnpm build - 前端核心页面必须覆盖 `docs/首期UI状态覆盖.md` 中列出的状态。 - 端到端测试必须能证明主闭环,不得只校验静态页面存在。 - 测试不能使用 mock 数据库替代真实数据库行为。 - diff --git a/docs/integrated-ops-platform-blueprint-design.md b/docs/integrated-ops-platform-blueprint-design.md index b466601..9f576d2 100644 --- a/docs/integrated-ops-platform-blueprint-design.md +++ b/docs/integrated-ops-platform-blueprint-design.md @@ -1,4 +1,6 @@ - + + + # 一体化运维平台完整蓝图与分期落地方案 生成来源:`/office-hours` @@ -838,4 +840,3 @@ **审批结论:** - 用户已选择 A:按当前方案批准蓝图方向。后续进入 P1 待办处理与第 1 阶段实施准备;Git 远程凭据风险已按用户要求忽略,不作为当前交付阻塞项。 - diff --git a/docs/superpowers/specs/2026-06-21-ops-project-structure-data-model-api-design.md b/docs/superpowers/specs/2026-06-21-ops-project-structure-data-model-api-design.md deleted file mode 100644 index 2de40e9..0000000 --- a/docs/superpowers/specs/2026-06-21-ops-project-structure-data-model-api-design.md +++ /dev/null @@ -1,1079 +0,0 @@ -# OPS 项目目录、数据模型与接口文件设计 - -## 1. 设计目标 - -本文根据现有项目文档和 `server/` 模板结构,重新设计 OPS 的实际业务目录、完整数据模型文件边界和 REST 接口文件边界。 - -本设计替代已删除的旧设计文档,不以旧文档为基线。 - -目标: - -- 保留模板验证过的 Go 分层骨架:`cmd/`、`internal/config/`、`internal/impl/`、`internal/models/`、`internal/logic/`、`internal/routers/`。 -- 按 OPS-001 至 OPS-033 完整功能需求设计数据模型,先完整建模,再按阶段实现。 -- 首期优先打通“资源纳管 -> 采集/探测/Trap/Syslog -> 原始事件 -> 告警 -> 通知 -> 工单 -> 报表/大屏/审计”闭环。 -- 让 `templates/` 仅作为只读参考,不参与实际业务实现,不被实际业务代码 import。 -- 为后续生成 Go 模型、DTO、Service、Router 文件提供清晰边界和注释规范。 - -## 2. 关键决策 - -采用“按业务域拆分,保留模板分层”的 B 方案。 - -不采用以下方案: - -- 不做模板最小改造。原因是告警、工单、采集和权限会挤在少量文件中,后续维护困难。 -- 不新增大规模 `domain/service/repository` 重构层。原因是首期目标是可运行、可验收,过度重构会偏离模板和当前交付节奏。 - -约束: - -- `templates/front_sample/standard` 和 `templates/server_sample/` 只读参考。 -- 实际后端业务只落在 `server/`。 -- 未来实际前端业务只落在 `web/`。 -- 不新增旧项目名。 -- 命令示例只使用 Windows PowerShell。 -- PostgreSQL 保存事务数据,TDengine 保存时序样本,业务代码通过适配层访问 TDengine。 - -## 3. 后端目录结构 - -```text -server/ - cmd/ - main/ - main.go - cli/ - main.go - etc/ - ops_dev.example.yaml - ops_test.example.yaml - ops_prod.example.yaml - internal/ - config/ - config.go - impl/ - new.go - postgres.go - redis.go - tsdb.go - file_store.go - models/ - base.go - resource/ - metric/ - collector/ - event/ - alert/ - notification/ - ticket/ - asset/ - topology/ - ipam/ - traffic/ - knowledge/ - report/ - iam/ - audit/ - logic/ - response/ - statemachine/ - resource/ - metric/ - collector/ - event/ - alert/ - notification/ - ticket/ - asset/ - topology/ - ipam/ - traffic/ - knowledge/ - report/ - dashboard/ - iam/ - audit/ - room3d/ - routers/ - register.go - resource.go - metric.go - collector.go - event.go - alert.go - notification.go - ticket.go - asset.go - topology.go - ipam.go - traffic.go - knowledge.go - report.go - dashboard.go - iam.go - audit.go - room3d.go - test/ - resource/ - collector/ - event/ - alert/ - notification/ - ticket/ - room3d/ -``` - -目录职责: - -- `models/`:GORM 表结构、表名、索引、唯一约束和基础查询。模型文件不写状态机和业务编排。 -- `logic/`:业务编排、DTO、状态机、权限判断、错误救援、审计记录和外部适配。 -- `logic/statemachine/`:资源、采集、原始事件、告警、事件、通知、工单状态流转集中定义。 -- `logic/response/`:统一响应、错误码、`traceId` 和 `suggestion`。 -- `routers/`:HTTP 路由注册和参数绑定。Router 不直接操作数据库。 -- `impl/`:PostgreSQL、Redis、TDengine、文件存储等基础设施实例。 -- `test/`:HTTP 接口样例、验收脚本和后端测试支撑文件。 - -## 4. 前端目录结构 - -`web/` 当前不存在。后续从前端模板初始化后,建议使用以下业务边界: - -```text -web/ - src/ - api/ - types/ - common.ts - resource.ts - metric.ts - collector.ts - event.ts - alert.ts - notification.ts - ticket.ts - asset.ts - report.ts - iam.ts - resource.ts - metric.ts - collector.ts - event.ts - alert.ts - notification.ts - ticket.ts - asset.ts - report.ts - dashboard.ts - iam.ts - audit.ts - room3d.ts - views/ - dashboard/ - monitor/ - events/ - alerts/ - tickets/ - reports/ - screens/ - iam/ - system/ - room3d-api/ - store/ - modules/ - user.ts - permission.ts - ops-state.ts - components/ - ops-state/ - trace-error/ - resource-selector/ - alert-severity/ - ticket-transition/ -``` - -前端规则: - -- API 类型按业务域放入 `src/api/types/`。 -- 页面组件不得直接拼接非法状态,状态枚举以后端返回和前端类型定义为准。 -- 所有错误状态展示 `traceId`。 -- loading、empty、error、success、partial、forbidden、stale、operating、operation_failed 必须可被页面表达。 - -## 5. 数据模型总体原则 - -数据模型先覆盖完整 OPS-001 至 OPS-033,再按阶段实现: - -- P1:首期必须实现或迁移,用于验收核心闭环。 -- P2:上下文增强,先设计模型边界,后续按任务实现。 -- P3:运营治理和智能化,先预留统计口径。 - -统一规则: - -- 所有核心表包含 `id`、`tenant_id`、`created_at`、`updated_at`、`created_by`、`updated_by`、`deleted_at`、`version`。 -- 关键状态变化写 `audit_logs` 或对应 transition 表。 -- 敏感凭据不保存明文,只保存 `secret_ref` 和脱敏描述。 -- TDengine 样本不做 GORM 模型,只在 PostgreSQL 中保存指标定义、序列映射和保留策略。 -- 模型文件注释必须说明表职责、阶段和对应需求编号。 - -建议 `server/internal/models/base.go`: - -```go -// BaseModel 是 OPS 事务表的通用字段。 -// 所有需要审计、租户隔离或软删除的业务表都应嵌入该结构。 -type BaseModel struct { - ID string `gorm:"column:id;type:varchar(64);primaryKey" json:"id"` - TenantID string `gorm:"column:tenant_id;type:varchar(64);index" json:"tenantId"` - CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"` - UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"` - CreatedBy string `gorm:"column:created_by;type:varchar(64)" json:"createdBy"` - UpdatedBy string `gorm:"column:updated_by;type:varchar(64)" json:"updatedBy"` - DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index" json:"-"` - Version int `gorm:"column:version;default:1" json:"version"` -} -``` - -## 6. 资源与业务系统模型 - -```text -server/internal/models/resource/ - business_system.go - resource_type.go - resource.go - resource_relation.go - resource_group.go - credential.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `business_system.go` | `business_systems` | P1 | OPS-001、OPS-011、OPS-033 | HIS、LIS、PACS、EMR 等业务系统建模。 | -| `resource_type.go` | `resource_types` | P1 | OPS-002 至 OPS-012 | 主机、H3C 网络设备、数据库、虚拟化、URL/API 等资源类型。 | -| `resource.go` | `resources` | P1 | OPS-002 至 OPS-014、OPS-031 | 统一监控资源主表。 | -| `resource_relation.go` | `resource_relations` | P1/P2 | OPS-013、OPS-033 | 资源依赖、业务拓扑、基础拓扑关系。 | -| `resource_group.go` | `resource_groups`、`resource_group_members` | P2 | OPS-013、OPS-031 | 资源分组、多级分组、自动分组结果。 | -| `credential.go` | `credentials` | P1 | OPS-002 至 OPS-011、OPS-031 | 凭据引用和脱敏摘要。 | - -核心字段: - -- `business_systems`:`name`、`code`、`level`、`network_zone`、`owner_org_id`、`owner_user_id`、`health_status`、`description`。 -- `resource_types`:`code`、`name`、`category`、`vendor`、`default_metric_template_id`、`icon`。 -- `resources`:`name`、`resource_type_id`、`vendor`、`model`、`ip`、`hostname`、`business_system_id`、`owner_org_id`、`owner_user_id`、`asset_id`、`status`、`collect_status`、`highest_alert_severity`。 -- `resource_relations`:`source_resource_id`、`target_resource_id`、`relation_type`、`description`。 -- `credentials`:`name`、`type`、`secret_ref`、`masked_summary`、`owner_org_id`、`status`。 - -索引建议: - -- `resources(tenant_id, resource_type_id, status)`。 -- `resources(tenant_id, ip)`。 -- `resources(tenant_id, business_system_id)`。 -- `business_systems(tenant_id, code)` 唯一。 -- `resource_types(code)` 唯一。 - -## 7. 指标、模板与时序映射模型 - -```text -server/internal/models/metric/ - metric_template.go - metric_definition.go - metric_series.go - metric_retention_policy.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `metric_template.go` | `metric_templates` | P1 | OPS-002 至 OPS-011、OPS-031 | 资源类型、厂商、协议维度的指标模板。 | -| `metric_definition.go` | `metric_definitions` | P1 | OPS-002 至 OPS-014 | 指标编码、单位、类型、默认采集周期和阈值建议。 | -| `metric_series.go` | `metric_series` | P1 | OPS-002、OPS-004、OPS-007、OPS-011、OPS-027 | PostgreSQL 到 TDengine 时序序列的映射。 | -| `metric_retention_policy.go` | `metric_retention_policies` | P1 | OPS-015、OPS-027 | 原始样本保留、降采样、聚合保留策略。 | - -核心字段: - -- `metric_templates`:`name`、`resource_type_id`、`vendor`、`version`、`status`。 -- `metric_definitions`:`template_id`、`resource_type_id`、`metric_code`、`metric_name`、`unit`、`value_type`、`default_interval_seconds`、`threshold_hint`。 -- `metric_series`:`resource_id`、`metric_definition_id`、`metric_code`、`tsdb_name`、`series_key`、`labels_json`、`retention_policy_id`。 -- `metric_retention_policies`:`name`、`raw_retention_days`、`downsample_rule`、`status`。 - -TDengine 访问规则: - -- 业务代码只调用 `logic/metric/tsdb_adapter.go`。 -- 查询统一使用 `resource_id + metric_code + time_range`。 -- 不在资源、告警、报表逻辑中散落 TDengine SQL。 - -## 8. 采集、发现与探测模型 - -```text -server/internal/models/collector/ - collector_task.go - collector_run.go - discovery_task.go - discovery_result.go - probe_target.go - agent_node.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `collector_task.go` | `collector_tasks` | P1 | OPS-002 至 OPS-011、OPS-031 | 采集任务定义。 | -| `collector_run.go` | `collector_runs` | P1 | OPS-031 | 单次采集执行记录和失败原因。 | -| `discovery_task.go` | `discovery_tasks` | P1/P2 | OPS-004、OPS-016、OPS-017、OPS-031 | 自动发现任务。 | -| `discovery_result.go` | `discovery_results` | P2 | OPS-016、OPS-017、OPS-031 | 自动发现结果和匹配资源。 | -| `probe_target.go` | `probe_targets` | P1 | OPS-011 | URL/API/端口探测目标。 | -| `agent_node.go` | `agent_nodes` | P2 | OPS-032 | 跨网代理节点。 | - -核心字段: - -- `collector_tasks`:`resource_id`、`collector_type`、`protocol`、`credential_id`、`schedule_cron`、`interval_seconds`、`timeout_seconds`、`retry_limit`、`status`。 -- `collector_runs`:`task_id`、`started_at`、`finished_at`、`run_status`、`success_count`、`failed_count`、`error_code`、`error_message`、`trace_id`、`last_success_at`。 -- `discovery_tasks`:`name`、`scan_range`、`protocols_json`、`credential_id`、`schedule_cron`、`status`。 -- `probe_targets`:`resource_id`、`target_url`、`method`、`expected_status`、`timeout_seconds`、`status`。 -- `agent_nodes`:`name`、`region`、`network_zone`、`mode`、`last_heartbeat_at`、`status`。 - -救援要求: - -- 采集失败写 `collector_runs`。 -- 连续失败达到阈值后写平台内部 `raw_events`。 -- `COLLECT_UNREACHABLE`、`COLLECT_AUTH_FAILED`、`COLLECT_TIMEOUT` 必须可区分。 - -## 9. 事件、Syslog 与 Trap 模型 - -```text -server/internal/models/event/ - raw_event.go - syslog_rule.go - trap_dictionary.go - event_replay_job.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `raw_event.go` | `raw_events` | P1 | OPS-010、OPS-018、OPS-021 | 原始事件池,保留解析前后状态。 | -| `syslog_rule.go` | `syslog_rules` | P1 | OPS-010 | Syslog 匹配、字段提取和级别映射。 | -| `trap_dictionary.go` | `trap_dictionaries` | P1 | OPS-010 | Trap OID 字典、恢复 OID 和级别配置。 | -| `event_replay_job.go` | `event_replay_jobs` | P1 | OPS-010 | 补规则后的事件重放任务。 | - -核心字段: - -- `raw_events`:`source_type`、`source_id`、`resource_id`、`event_key`、`occurred_at`、`severity`、`title`、`message`、`payload_json`、`parse_status`、`matched_rule_id`、`suppressed_policy_id`。 -- `syslog_rules`:`name`、`match_expr`、`extract_expr`、`severity_mapping_json`、`status`。 -- `trap_dictionaries`:`vendor`、`oid`、`name`、`severity`、`recover_oid`、`description`、`status`。 -- `event_replay_jobs`:`name`、`scope_type`、`scope_id`、`status`、`result_summary_json`。 - -规则: - -- 未解析 Trap/Syslog 不删除。 -- 重放动作必须写审计。 -- 被抑制事件仍可查询,并记录命中的策略 ID。 - -## 10. 告警与事件治理模型 - -```text -server/internal/models/alert/ - alert_rule.go - alert.go - incident.go - incident_alert.go - silence_policy.go - dedup_rule.go - correlation_rule.go - escalation_policy.go - alert_quality_stat.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `alert_rule.go` | `alert_rules` | P1 | OPS-018、OPS-020 | 阈值、Trap、Syslog、可用性告警规则。 | -| `alert.go` | `alerts` | P1 | OPS-018 至 OPS-021 | 告警实例和生命周期。 | -| `incident.go` | `incidents` | P1 | OPS-021、OPS-022 | 多告警归并后的事件。 | -| `incident_alert.go` | `incident_alerts` | P1 | OPS-018、OPS-021 | 事件与告警关联。 | -| `silence_policy.go` | `silence_policies` | P1 | OPS-018 | 屏蔽和维护窗口。 | -| `dedup_rule.go` | `dedup_rules` | P1 | OPS-018 | 去重窗口和匹配表达式。 | -| `correlation_rule.go` | `correlation_rules` | P1/P2 | OPS-018、OPS-013 | 压缩、依赖、抑制规则。 | -| `escalation_policy.go` | `escalation_policies` | P1 | OPS-020 | 超时升级策略。 | -| `alert_quality_stat.go` | `alert_quality_stats` | P3 | OPS-018 后续优化 | 告警质量评分和规则优化依据。 | - -核心字段: - -- `alert_rules`:`name`、`scope_type`、`scope_id`、`metric_code`、`condition_expr`、`duration_seconds`、`recover_expr`、`severity`、`status`。 -- `alerts`:`alert_key`、`resource_id`、`rule_id`、`first_seen_at`、`last_seen_at`、`recovered_at`、`severity`、`status`、`summary`。 -- `incidents`:`incident_no`、`title`、`severity`、`status`、`owner_user_id`、`business_system_id`、`opened_at`、`closed_at`。 -- `silence_policies`:`name`、`scope_type`、`scope_id`、`start_at`、`end_at`、`reason`、`status`。 -- `alert_quality_stats`:`rule_id`、`noise_count`、`false_positive_count`、`avg_ack_seconds`、`avg_resolve_seconds`、`score`。 - -## 11. 通知与工单模型 - -```text -server/internal/models/notification/ - notification_policy.go - notification_template.go - notification_record.go - -server/internal/models/ticket/ - ticket.go - ticket_transition.go - ticket_comment.go - ticket_sla_record.go - ticket_dispatch_rule.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `notification_policy.go` | `notification_policies` | P1 | OPS-019、OPS-020 | 通知策略。 | -| `notification_template.go` | `notification_templates` | P1 | OPS-019、OPS-030 | 站内消息、短信、邮件模板。 | -| `notification_record.go` | `notification_records` | P1 | OPS-019、OPS-021 | 通知发送记录、失败原因和重试。 | -| `ticket.go` | `tickets` | P1 | OPS-022 | 工单主表。 | -| `ticket_transition.go` | `ticket_transitions` | P1 | OPS-022 | 工单状态流转记录。 | -| `ticket_comment.go` | `ticket_comments` | P1 | OPS-022、OPS-026 | 工单处理记录和附件。 | -| `ticket_sla_record.go` | `ticket_sla_records` | P1/P3 | OPS-022、运营治理 | 工单 SLA 和处理时长统计。 | -| `ticket_dispatch_rule.go` | `ticket_dispatch_rules` | P1 | OPS-019、OPS-022 | 自动派单规则。 | - -核心字段: - -- `notification_records`:`channel`、`alert_id`、`incident_id`、`receiver`、`send_status`、`retry_count`、`provider_code`、`error_message`、`sent_at`。 -- `tickets`:`ticket_no`、`title`、`source_type`、`source_id`、`alert_id`、`incident_id`、`resource_id`、`assignee_id`、`status`、`priority`、`closed_at`。 -- `ticket_transitions`:`ticket_id`、`from_status`、`to_status`、`operator_id`、`reason`、`trace_id`。 -- `ticket_dispatch_rules`:`name`、`match_expr`、`assignee_type`、`assignee_id`、`status`。 - -规则: - -- 通知失败不阻断告警确认和工单流转。 -- 同一告警不能重复自动创建多个未关闭工单。 -- 工单非法流转返回 `STATE_CONFLICT`。 - -## 12. 资产、机房与 3D 接口模型 - -```text -server/internal/models/asset/ - data_center.go - room.go - rack.go - rack_unit.go - asset.go - environment_device.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `data_center.go` | `data_centers` | P2,首期接口 | OPS-023 | 数据中心层级。 | -| `room.go` | `rooms` | P2,首期接口 | OPS-023 | 机房、楼层和状态。 | -| `rack.go` | `racks` | P2,首期接口 | OPS-024 | 机柜坐标、容量和状态。 | -| `rack_unit.go` | `rack_units` | P2,首期接口 | OPS-024 | U 位占用和资源/资产绑定。 | -| `asset.go` | `assets` | P2 | OPS-025 | 资产台账。 | -| `environment_device.go` | `environment_devices` | P2 | OPS-012、OPS-023 | 动环设备和机房关联。 | - -3D 机房接口规则: - -- `room3d` 返回聚合 DTO,不直接暴露内部 GORM 模型。 -- 必须返回数据更新时间。 -- 资产未绑定监控资源时,接口返回 `bindStatus=unbound`,不影响机柜结构展示。 -- 数据权限过滤在 `logic/room3d/service.go` 中执行。 - -## 13. 拓扑、IPAM、流量与知识库模型 - -```text -server/internal/models/topology/ - topology_map.go - topology_node.go - topology_link.go - -server/internal/models/ipam/ - ip_subnet.go - ip_address.go - ip_scan_task.go - ip_change_record.go - -server/internal/models/traffic/ - network_link.go - traffic_policy.go - traffic_anomaly.go - -server/internal/models/knowledge/ - knowledge_category.go - knowledge_article.go - knowledge_relation.go - knowledge_audit.go -``` - -这些模型主要属于 P2: - -- `topology_*`:OPS-013,网络拓扑、业务拓扑和资源关系视图。 -- `ip_*`:OPS-016、OPS-017,子网、IP、扫描、冲突和变更。 -- `traffic_*`:OPS-014、OPS-015,链路、应用/协议策略、流量异常。 -- `knowledge_*`:OPS-026,知识分类、条目、关联检测点和审核日志。 - -实现建议: - -- 首期可只使用 `resource_relations` 支撑基础拓扑和业务视图。 -- P2 再迁移完整拓扑、IPAM、流量和知识库表。 -- 未获现场授权前,不执行生产网段扫描。 - -## 14. 报表、大屏、权限与审计模型 - -```text -server/internal/models/report/ - report_template.go - report_job.go - report_export.go - dashboard.go - dashboard_widget.go - -server/internal/models/iam/ - organization.go - user.go - role.go - user_role.go - role_permission.go - data_scope.go - -server/internal/models/audit/ - audit_log.go - system_log.go -``` - -| 文件 | 表名 | 阶段 | 对应需求 | 职责 | -| --- | --- | --- | --- | --- | -| `report_template.go` | `report_templates` | P1 | OPS-027 | 报表模板和查询结构。 | -| `report_job.go` | `report_jobs` | P1 | OPS-027 | 报表生成任务。 | -| `report_export.go` | `report_exports` | P1 | OPS-027 | 导出文件记录。 | -| `dashboard.go` | `dashboards` | P1 | OPS-001、OPS-028 | 首页模块和大屏配置。 | -| `dashboard_widget.go` | `dashboard_widgets` | P1 | OPS-001、OPS-028 | 大屏组件数据源和布局。 | -| `organization.go` | `organizations` | P1 | OPS-029、OPS-030 | 组织部门。 | -| `user.go` | `users` | P1 | OPS-029、OPS-030 | 用户账号。 | -| `role.go` | `roles` | P1 | OPS-029 | 角色。 | -| `user_role.go` | `user_roles` | P1 | OPS-029 | 用户角色关联。 | -| `role_permission.go` | `role_permissions` | P1 | OPS-029 | 功能权限。 | -| `data_scope.go` | `data_scopes` | P1 | OPS-029 | 数据权限范围。 | -| `audit_log.go` | `audit_logs` | P1 | 全部关键操作 | 审计日志。 | -| `system_log.go` | `system_logs` | P1 | OPS-030 | 系统运行日志查询。 | - -审计必写动作: - -- 资源新增、修改、停用、退役。 -- 凭据引用变更。 -- 告警确认、忽略、恢复、失效、派单。 -- 屏蔽、抑制、升级、通知策略变更。 -- 工单接单、转交、撤回、挂起、重启、关闭。 -- 权限、角色、数据权限变更。 -- 报表导出和敏感数据查看。 - -## 15. Logic 文件设计 - -```text -server/internal/logic/ - response/ - response.go - errors.go - trace.go - statemachine/ - resource.go - collector.go - raw_event.go - alert.go - incident.go - notification.go - ticket.go - resource/ - dto.go - service.go - metric/ - dto.go - service.go - tsdb_adapter.go - collector/ - dto.go - service.go - rescue.go - event/ - dto.go - receiver.go - parser.go - replay.go - alert/ - dto.go - service.go - evaluator.go - dedup.go - silence.go - escalation.go - notification/ - dto.go - service.go - retry.go - channel.go - ticket/ - dto.go - service.go - transition.go - dispatch.go - asset/ - dto.go - service.go - report/ - dto.go - service.go - export.go - dashboard/ - dto.go - service.go - iam/ - dto.go - service.go - permission.go - data_scope.go - audit/ - dto.go - service.go - room3d/ - dto.go - service.go -``` - -规则: - -- `dto.go` 定义请求和响应结构,不直接向前端暴露 GORM 模型。 -- `service.go` 做业务编排、权限判断、状态机调用和审计记录。 -- `rescue.go` 处理失败救援,例如采集失败、通知失败、派单失败。 -- `tsdb_adapter.go` 是 TDengine 访问边界。 -- `statemachine/*.go` 只定义状态、合法迁移和校验方法。 - -## 16. Router 文件设计 - -统一前缀: - -```text -/{ServiceKey}/v1 -``` - -后续服务键建议从模板的 `Sample` 调整为 `OPS`。 - -```text -server/internal/routers/ - register.go - resource.go - metric.go - collector.go - event.go - alert.go - notification.go - ticket.go - asset.go - topology.go - ipam.go - traffic.go - knowledge.go - report.go - dashboard.go - iam.go - audit.go - room3d.go -``` - -Router 规则: - -- `register.go` 只负责调用各业务域注册函数。 -- 每个业务域一个 `RegisterXxxRoutes`。 -- 写操作挂鉴权中间件。 -- 只做参数绑定和基础校验,业务校验放到 `logic/`。 -- 不在 Router 中直接调用 `impl.DBService`。 - -## 17. REST API 设计 - -### 17.1 统一响应 - -成功响应: - -```json -{ - "code": "OK", - "message": "成功", - "traceId": "01HX...", - "suggestion": "", - "data": {} -} -``` - -错误响应: - -```json -{ - "code": "COLLECT_AUTH_FAILED", - "message": "凭据不可用,请检查凭据引用和设备权限", - "traceId": "01HX...", - "suggestion": "修改凭据后重新执行采集任务", - "data": { - "currentStatus": "failed" - } -} -``` - -分页响应: - -```json -{ - "code": "OK", - "message": "成功", - "traceId": "01HX...", - "data": { - "total": 100, - "page": 1, - "size": 20, - "list": [] - } -} -``` - -### 17.2 资源与业务系统 - -```text -GET /resources -POST /resources -GET /resources/:id -PUT /resources/:id -POST /resources/:id/enable -POST /resources/:id/disable -POST /resources/:id/maintenance -POST /resources/:id/decommission -GET /resources/:id/metrics -GET /resources/:id/alerts -GET /resources/:id/collector-runs - -GET /resource-types -POST /resource-types -GET /business-systems -POST /business-systems -GET /business-systems/:id/health -GET /business-systems/:id/resources -``` - -### 17.3 指标与时序 - -```text -GET /metric-templates -POST /metric-templates -GET /metric-definitions -POST /metric-definitions -GET /metric-series -POST /metrics/query -POST /metrics/aggregate -POST /metrics/topn -GET /metric-retention-policies -POST /metric-retention-policies -``` - -`TSDBAdapter` 接口: - -```go -// TSDBAdapter 定义 OPS 访问 TDengine 的唯一业务入口。 -// 业务逻辑只能通过该接口读写时序样本,不能散落 TDengine 专有 SQL。 -type TSDBAdapter interface { - WriteBatch(ctx context.Context, samples []MetricSample) error - QueryRange(ctx context.Context, req QueryRangeRequest) (QueryRangeReply, error) - Aggregate(ctx context.Context, req AggregateRequest) (AggregateReply, error) - TopN(ctx context.Context, req TopNRequest) (TopNReply, error) - CheckHealth(ctx context.Context) error -} -``` - -### 17.4 采集与发现 - -```text -GET /collector-tasks -POST /collector-tasks -GET /collector-tasks/:id -PUT /collector-tasks/:id -POST /collector-tasks/:id/enable -POST /collector-tasks/:id/disable -POST /collector-tasks/:id/run-now -GET /collector-tasks/:id/runs - -GET /collector-runs -GET /collector-runs/:id - -GET /discovery-tasks -POST /discovery-tasks -POST /discovery-tasks/:id/run-now -GET /discovery-results - -GET /probe-targets -POST /probe-targets -PUT /probe-targets/:id -``` - -### 17.5 事件、Syslog 与 Trap - -```text -POST /events/raw -GET /events/raw -GET /events/raw/:id -POST /events/raw/:id/replay -POST /events/replay-jobs - -GET /syslog-rules -POST /syslog-rules -PUT /syslog-rules/:id - -GET /trap-dictionaries -POST /trap-dictionaries -PUT /trap-dictionaries/:id -POST /trap-dictionaries/import -``` - -### 17.6 告警与事件治理 - -```text -GET /alerts -GET /alerts/:id -POST /alerts/:id/ack -POST /alerts/:id/ignore -POST /alerts/:id/recover -POST /alerts/:id/expire -POST /alerts/:id/dispatch-ticket -GET /alerts/:id/timeline -GET /alerts/:id/notifications -GET /alerts/:id/audits - -GET /alert-rules -POST /alert-rules -PUT /alert-rules/:id -POST /alert-rules/:id/enable -POST /alert-rules/:id/disable - -GET /silence-policies -POST /silence-policies -PUT /silence-policies/:id - -GET /dedup-rules -POST /dedup-rules - -GET /correlation-rules -POST /correlation-rules - -GET /escalation-policies -POST /escalation-policies - -GET /incidents -GET /incidents/:id -POST /incidents/:id/assign -POST /incidents/:id/start -POST /incidents/:id/suspend -POST /incidents/:id/resolve -POST /incidents/:id/close -``` - -### 17.7 通知与工单 - -```text -GET /notification-policies -POST /notification-policies -PUT /notification-policies/:id - -GET /notification-templates -POST /notification-templates -PUT /notification-templates/:id - -GET /notification-records -GET /notification-records/:id -POST /notification-records/:id/retry - -GET /tickets -POST /tickets -GET /tickets/:id -POST /tickets/:id/accept -POST /tickets/:id/start -POST /tickets/:id/transfer -POST /tickets/:id/suspend -POST /tickets/:id/restart -POST /tickets/:id/withdraw -POST /tickets/:id/close -GET /tickets/:id/transitions -GET /tickets/:id/comments -POST /tickets/:id/comments - -GET /ticket-dispatch-rules -POST /ticket-dispatch-rules -PUT /ticket-dispatch-rules/:id -``` - -### 17.8 资产、机房与 3D 接口 - -内部资产管理: - -```text -GET /data-centers -POST /data-centers -GET /rooms -POST /rooms -GET /racks -POST /racks -GET /rack-units -PUT /rack-units/:id -GET /assets -POST /assets -PUT /assets/:id -POST /assets/:id/bind-resource -``` - -外包 3D 前端专用接口: - -```text -GET /room3d/data-centers -GET /room3d/data-centers/:id/rooms -GET /room3d/rooms/:id/racks -GET /room3d/racks/:id/units -GET /room3d/resources/:id/status -GET /room3d/summary -``` - -### 17.9 P2 接口规划 - -拓扑: - -```text -GET /topologies -POST /topologies -GET /topologies/:id/nodes -GET /topologies/:id/links -``` - -IPAM: - -```text -GET /ipam/subnets -POST /ipam/subnets -GET /ipam/addresses -POST /ipam/scan-tasks -GET /ipam/change-records -``` - -流量: - -```text -GET /traffic/links -POST /traffic/links -GET /traffic/policies -POST /traffic/policies -GET /traffic/anomalies -``` - -知识库: - -```text -GET /knowledge/categories -POST /knowledge/categories -GET /knowledge/articles -POST /knowledge/articles -POST /knowledge/articles/:id/publish -POST /knowledge/articles/:id/review -``` - -### 17.10 报表、大屏、权限与审计 - -```text -GET /report-templates -POST /report-templates -POST /report-jobs -GET /report-jobs -GET /report-jobs/:id -POST /report-jobs/:id/export -GET /report-exports/:id/download - -GET /dashboards -POST /dashboards -PUT /dashboards/:id -GET /dashboards/:id/widgets -POST /dashboards/:id/widgets -PUT /dashboard-widgets/:id - -GET /iam/organizations -POST /iam/organizations -GET /iam/users -POST /iam/users -POST /iam/users/:id/enable -POST /iam/users/:id/disable -GET /iam/roles -POST /iam/roles -PUT /iam/roles/:id/permissions -PUT /iam/data-scopes/:id - -GET /audit-logs -GET /system-logs -``` - -## 18. 注释规范 - -后续生成 Go 文件时使用中文注释,注释要说明业务意图,不重复代码字面含义。 - -推荐注释位置: - -- 每个模型结构体顶部说明表职责、阶段和对应 OPS 编号。 -- 每个状态机文件顶部说明状态来源和禁止绕过规则。 -- 每个 Service 的公开方法说明业务动作和审计要求。 -- 每个错误码说明触发场景、用户提示和建议动作。 -- TDengine 适配器说明为什么不能在业务逻辑中直接写 TDengine SQL。 - -示例: - -```go -// Resource 是 OPS 的统一监控资源主表。 -// 覆盖 OPS-002 至 OPS-014、OPS-031,用于承载主机、网络设备、数据库、 -// 虚拟化、URL/API 等被监控对象。状态流转必须通过 statemachine 校验。 -type Resource struct { - models.BaseModel -} -``` - -不建议的注释: - -```go -// Name 是名称 -Name string -``` - -## 19. 实施顺序建议 - -第一批实现: - -```text -models/base.go -models/resource/ -models/metric/ -models/collector/ -models/event/ -models/alert/ -models/notification/ -models/ticket/ -models/iam/ -models/audit/ -logic/response/ -logic/statemachine/ -routers/register.go -``` - -第二批实现: - -```text -models/report/ -models/asset/ -logic/report/ -logic/dashboard/ -logic/room3d/ -routers/report.go -routers/dashboard.go -routers/room3d.go -``` - -第三批实现: - -```text -models/topology/ -models/ipam/ -models/traffic/ -models/knowledge/ -logic/topology/ -logic/ipam/ -logic/traffic/ -logic/knowledge/ -``` - -## 20. 自审结论 - -- 本设计覆盖 OPS-001 至 OPS-033 的模型和接口边界。 -- 首期闭环与 P2/P3 预留已分离。 -- 未引入旧项目名。 -- 未要求修改 `templates/`。 -- 未使用 Linux 命令示例。 -- 状态机、统一响应、TDengine 适配层、故障救援和审计边界均有明确落点。 diff --git a/docs/本地开发与验收部署说明.md b/docs/本地开发与验收部署说明.md index d9e86c6..8da1542 100644 --- a/docs/本地开发与验收部署说明.md +++ b/docs/本地开发与验收部署说明.md @@ -4,7 +4,7 @@ 本文区分本地开发、联调验收和 Linux/麒麟部署三类场景,避免把模板 README 直接作为交付部署手册。 -当前仓库尚未初始化 `server/` 和 `web/`。后续实际工程创建后,应在对应目录补充更细的运行说明。 +当前仓库尚未保留实际 `server/` 和 `web/` 工程。后续实际工程创建后,应在对应目录补充更细的运行说明。 ## 2. 场景边界 @@ -18,16 +18,16 @@ | 目录 | 职责 | 状态 | | --- | --- | --- | -| `server/` | 实际后端工程,基于 `templates/server_sample/` 初始化 | 尚未创建 | +| `server/` | 实际后端工程,基于 `templates/server_sample/` 初始化后继续改造 | 尚未创建 | | `web/` | 实际前端工程,基于 `templates/front_sample/standard` 初始化 | 尚未创建 | -| `deploy/` | 部署、迁移、回滚、烟测说明和配置示例 | 已规划 | +| `deploy/` | 部署、迁移、回滚、烟测说明和配置示例 | 已创建 | | `docs/` | 需求、架构、验收和测试文档 | 已存在 | 模板目录默认只读,不作为最终交付目录。 ## 4. 初始化实际工程 -后端初始化: +后端已初始化。若在干净仓库中重新初始化,可参考: ```powershell Copy-Item -LiteralPath .\templates\server_sample -Destination .\server -Recurse @@ -43,7 +43,7 @@ Copy-Item -LiteralPath .\templates\front_sample\standard -Destination .\web -Rec | 检查项 | 要求 | | --- | --- | -| 配置示例 | 只提交 `etc/*.example.yaml` 或 `.env.example`,不提交真实密码。 | +| 配置示例 | 只提交 `etc/*.example.yaml`、`*.example.yaml` 或 `.env.example`,不提交真实密码。 | | 目录结构 | 后端延续 `cmd/`、`internal/config/`、`internal/logic/`、`internal/models/`、`internal/routers/`。 | | 前端结构 | API 放入 `src/api/`,页面放入 `src/views/`,状态放入 Pinia。 | | 模板引用 | 业务代码不直接写回 `templates/`。 | @@ -68,6 +68,8 @@ Set-Location .\server go run .\cmd\cli\main.go migrate ``` +后端重新初始化后,应只提交 `server/etc/*.example.yaml` 或等价 `.example` 配置文件。本地真实配置应复制为 `server/etc/ops_dev.yaml` 等文件后再填写,并在 `server/.gitignore` 中排除。 + 后端本地配置要求: | 配置 | 要求 | diff --git a/server/.gitea/workflows/cicd.yaml b/server/.gitea/workflows/cicd.yaml deleted file mode 100644 index 0e623f2..0000000 --- a/server/.gitea/workflows/cicd.yaml +++ /dev/null @@ -1,113 +0,0 @@ -name: Actions -run-name: ${{ gitea.actor }} 🚀 -on: - push: - tags: - - 'v*' - - -jobs: - Explore-Gitea-Actions: - runs-on: ubuntu-latest - steps: - - name: Clean temp directory - run: rm -rf * - # 设置 Go 环境 - - name: 设置 Go - uses: https://git.apinb.com/github/setup-go@v5 - with: - go-version: '1.24.6' - tag_name: ${{ gitea.ref }} - release_name: ${{ gitea.ref }} - - - run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event." - - run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository_owner }}." - - name: Extract repository name - id: extract_repo - run: | - repo_name=$(echo ${{ gitea.repository }} | cut -d'/' -f2) - echo "Repository name: $repo_name" - echo "::set-output name=repo_name::$repo_name" - - # 提取tag标签名称 - - name: Extract tag name - id: extract_tag - run: echo "::set-output name=tag_name::$(echo ${{ gitea.ref }} | sed 's/^refs\/tags\///')" - - run: echo "🏷 The tag name is ${{ steps.extract_tag.outputs.tag_name }}." - - # 检查出代码 - - name: Check out repository code - uses: https://git.apinb.com/github/checkout@v4 - - # 缓存 Go 依赖项 - - name: Cache Go modules - uses: https://git.apinb.com/github/cache@v4 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - - - name: set last version - run: | - echo "export srv_version='${{ steps.extract_tag.outputs.tag_name }}';export srv_name='${{ steps.extract_repo.outputs.repo_name }}'" > ${{ gitea.repository_owner }}-${{ steps.extract_repo.outputs.repo_name }}_last_version.sh - - run: go env -w GOPROXY=https://goproxy.cn - - run: go env -w GOPRIVATE=git.apinb.com/* - - run: go env -w GONOPROXY=git.apinb.com/* - - run: go env -w GOINSECURE=git.apinb.com/* - - run: go env -w GONOSUMDB=git.apinb.com/* - - run: go env -w GOEXPERIMENT=jsonv2 - - run: go build -o ${{ gitea.repository_owner }}-${{ steps.extract_repo.outputs.repo_name }} ./cmd/main/main.go - - run: echo "🍏 This job's status is ${{ job.status }}." - - name: upload version.sh to minio oss - 1 - uses: https://git.apinb.com/github/minio-upload@main - with: - endpoint: http://172.24.0.20:9000 - access-key-id: 9jtPPB7wwJpe5R2164bS - access-key-secret: ho9LYavUIGdkf0b50aaOduIA4zdx8FQFWpUYx30p - bucket: reles - source: ./${{ gitea.repository_owner }}-${{ steps.extract_repo.outputs.repo_name }}_last_version.sh - insecure: true - recursive: true - - - name: upload bin to minio oss - 2 - uses: https://git.apinb.com/github/minio-upload@main - with: - endpoint: http://172.24.0.20:9000 - access-key-id: 9jtPPB7wwJpe5R2164bS - access-key-secret: ho9LYavUIGdkf0b50aaOduIA4zdx8FQFWpUYx30p - bucket: reles - source: ./${{ gitea.repository_owner }}-${{ steps.extract_repo.outputs.repo_name }} - target: /${{ gitea.repository_owner }}-${{ steps.extract_repo.outputs.repo_name }}@${{ steps.extract_tag.outputs.tag_name }}/ - insecure: true - recursive: false - - - name: upload etc/ to minio oss - 3 - uses: https://git.apinb.com/github/minio-upload@main - with: - endpoint: http://172.24.0.20:9000 - access-key-id: 9jtPPB7wwJpe5R2164bS - access-key-secret: ho9LYavUIGdkf0b50aaOduIA4zdx8FQFWpUYx30p - bucket: reles - source: ./etc - target: /${{ gitea.repository_owner }}-${{ steps.extract_repo.outputs.repo_name }}@${{ steps.extract_tag.outputs.tag_name }}/ - insecure: true - recursive: true - - - name: upload swagger to minio oss - 4 - uses: https://git.apinb.com/github/minio-upload@main - with: - endpoint: http://172.24.0.20:9000 - access-key-id: 9jtPPB7wwJpe5R2164bS - access-key-secret: ho9LYavUIGdkf0b50aaOduIA4zdx8FQFWpUYx30p - bucket: reles - source: ./swagger - target: /${{ gitea.repository_owner }}-${{ steps.extract_repo.outputs.repo_name }}@${{ steps.extract_tag.outputs.tag_name }}/ - insecure: true - recursive: true - - - name: upload success - run: echo "build&upload success." \ No newline at end of file diff --git a/server/.gitignore b/server/.gitignore deleted file mode 100644 index 6e2d8f9..0000000 --- a/server/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -# ---> Go -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ -builds/ -build/ -logs/ -pkg/ -cache/ -tmp/ -.builds/ -.build/ -.logs/ -.pkg/ -.cache/ -.tmp/ - -# Go workspace file -go.work - diff --git a/server/Makefile b/server/Makefile deleted file mode 100644 index 7241e00..0000000 --- a/server/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -.PHONY: build run cli migrate lint tidy clean - -BINARY_NAME=sample -CLI_NAME=sample-cli - -build: - go build -o build/$(BINARY_NAME) ./cmd/main/main.go - go build -o build/$(CLI_NAME) ./cmd/cli/main.go - -run: - go run ./cmd/main/main.go - -cli: - go run ./cmd/cli/main.go $(ARGS) - -migrate: - go run ./cmd/cli/main.go migrate - -lint: - go vet ./... - go fmt ./... - -tidy: - go mod tidy - -clean: - rm -rf build/ diff --git a/server/README.md b/server/README.md deleted file mode 100644 index c80d21f..0000000 --- a/server/README.md +++ /dev/null @@ -1,183 +0,0 @@ -# Sample - -基于 [BSM-SDK Core](https://git.apinb.com/bsm-sdk/core) 的 OPS 微服务样板项目,演示 Gin HTTP 服务、配置管理、数据库(GORM)、Redis 缓存、JWT 鉴权与标准分层架构,可作为新服务的起始模板。 - -## 功能概览 - -| 模块 | 说明 | -|------|------| -| 健康检查 | `HEAD /` 与 `GET /Sample/v1/ping/hello` | -| 示例 CRUD | `Sample/v1/sample/demo` 完整增删改查(JWT 鉴权) | -| 数据模型 | `sample_demo` 表,启动时自动迁移 | -| CLI | `migrate` 数据库迁移、`version` 版本查看 | - -## 项目结构 - -``` -sample/ -├── cmd/ -│ ├── main/ # HTTP 服务入口 -│ └── cli/ # 命令行工具 -├── internal/ -│ ├── config/ # 配置加载与校验 -│ ├── impl/ # 基础设施实例(DB、Redis、缓存、日志) -│ ├── logic/ # 业务逻辑层 -│ │ ├── ping/ # 健康检查 -│ │ └── demo/ # 示例 CRUD -│ ├── models/ # 数据模型与数据库操作 -│ └── routers/ # 路由注册 -├── etc/ # 配置文件(按环境区分) -├── scripts/ # 构建与工具脚本 -├── test/ # HTTP 接口测试文件 -└── Makefile -``` - -## 环境要求 - -- Go 1.26+ -- PostgreSQL(或修改配置使用 MySQL) -- Redis -- 可访问 `git.apinb.com` 私有仓库 - -## 快速开始 - -### 1. 配置 Go 私有仓库 - -```bash -go env -w GOPRIVATE=git.apinb.com/* -go env -w GONOPROXY=git.apinb.com/* -go env -w GOINSECURE=git.apinb.com/* -go env -w GONOSUMDB=git.apinb.com/* -``` - -### 2. 准备配置文件 - -配置文件命名规则:`{服务键}_{运行模式}.yaml`,本项目服务键为 `Sample`,开发模式对应 `etc/sample_dev.yaml`。 - -```bash -cp etc/sample_dev.yaml.example etc/sample_dev.yaml -# 编辑 etc/sample_dev.yaml,填入数据库与 Redis 连接信息 -``` - -### 3. 设置环境变量 - -```bash -# Linux / macOS -export BSM_RuntimeMode=dev -export BSM_Prefix=$(pwd)/etc -export BSM_JwtSecretKey=your-secret-key - -# Windows PowerShell -$env:BSM_RuntimeMode="dev" -$env:BSM_Prefix="$(pwd)/etc" -$env:BSM_JwtSecretKey="your-secret-key" -``` - -| 变量 | 说明 | 默认值 | -|------|------|--------| -| `BSM_RuntimeMode` | 运行模式:`dev` / `test` / `prod` | `dev` | -| `BSM_Prefix` | 配置文件目录 | 开发模式为当前路径 | -| `BSM_JwtSecretKey` | JWT 签名密钥 | SDK 内置默认值 | -| `BSM_Workspace` | 工作空间标识 | `default` | - -### 4. 安装依赖并启动 - -```bash -go mod tidy -make build # 或 go run ./cmd/main/main.go -make run -``` - -服务默认监听 `12426` 端口,启动成功后访问: - -```bash -curl http://127.0.0.1:12426/Sample/v1/ping/hello -``` - -## API 接口 - -### 统一响应格式 - -```json -{ - "code": 0, - "message": "", - "details": {}, - "timeseq": 1710000000000 -} -``` - -### 匿名接口 - -| 方法 | 路径 | 说明 | -|------|------|------| -| `HEAD` | `/` | 健康检查 | -| `GET` | `/Sample/v1/ping/hello` | Ping 测试 | - -### 鉴权接口(JWT) - -路由组:`/Sample/v1/sample`,请求头需携带 `Authorization: Bearer `。 - -| 方法 | 路径 | 说明 | -|------|------|------| -| `POST` | `/Sample/v1/demo` | 创建示例数据 | -| `GET` | `/Sample/v1/demo` | 分页列表(`page`、`size`) | -| `GET` | `/Sample/v1/demo/:identity` | 按 identity 查询 | -| `PUT` | `/Sample/v1/demo/:identity` | 更新 | -| `DELETE` | `/Sample/v1/demo/:identity` | 删除 | - -**创建请求示例:** - -```json -{ - "name": "Alice", - "age": 25 -} -``` - -## CLI 工具 - -```bash -# 查看版本 -go run ./cmd/cli/main.go version - -# 执行数据库自动迁移(模型定义见 internal/models) -go run ./cmd/cli/main.go migrate -``` - -也可使用 Makefile: - -```bash -make migrate -make cli ARGS="version" -``` - -## 开发与测试 - -```bash -make lint # go vet + go fmt -make tidy # go mod tidy -``` - -接口测试文件位于 `test/` 目录,可使用 VS Code REST Client 或 IntelliJ HTTP Client 直接运行。 - -## 生产部署 - -### 构建 - -```bash -./scripts/build.sh -# 产物:build/sample、build/sample-cli -``` - -### systemd - -```bash -cp etc/sample.service /etc/systemd/system/ -cp etc/sample.env.example /data/app/etc/sample.env -# 编辑环境变量后 -systemctl enable sample -systemctl start sample -``` - - diff --git a/server/cmd/cli/main.go b/server/cmd/cli/main.go deleted file mode 100644 index 4b08dcf..0000000 --- a/server/cmd/cli/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "git.apinb.com/ops/sample/internal/config" - "git.apinb.com/ops/sample/internal/impl" - _ "git.apinb.com/ops/sample/internal/models" -) - -const ( - serviceKey = "Sample" - version = "1.0.0" -) - -func main() { - if len(os.Args) < 2 { - printUsage() - return - } - - switch os.Args[1] { - case "version": - fmt.Println("sample-cli", version) - case "migrate": - config.New(serviceKey) - impl.NewImpl() - fmt.Println("database migrate completed") - default: - fmt.Fprintf(os.Stderr, "unknown command: %s\n", os.Args[1]) - printUsage() - os.Exit(1) - } -} - -func printUsage() { - fmt.Println("usage: sample-cli ") - fmt.Println("commands:") - fmt.Println(" version show cli version") - fmt.Println(" migrate run database auto migrate") -} diff --git a/server/cmd/main/main.go b/server/cmd/main/main.go deleted file mode 100644 index 54e39e2..0000000 --- a/server/cmd/main/main.go +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @Author: david.yan(david.yan@qq.com) - * @Date: 2021-11-26 15:25:03 - */ -package main - -import ( - "context" - "fmt" - "net/http" - "os" - "os/signal" - "syscall" - "time" - - "git.apinb.com/bsm-sdk/core/infra" - "git.apinb.com/bsm-sdk/core/middleware" - "git.apinb.com/bsm-sdk/core/printer" - "git.apinb.com/ops/sample/internal/config" - "git.apinb.com/ops/sample/internal/impl" - "git.apinb.com/ops/sample/internal/routers" - "github.com/gin-gonic/gin" -) - -var ( - ServiceKey = "Sample" -) - -func main() { - // 配置初始化 - config.New(ServiceKey) - - // 创建实现层 - impl.NewImpl() - - // 初始化Gin引擎 - app := gin.Default() - - // 使用中间件 - middleware.Mode(app) - app.Use(middleware.Cors()) - app.Use(gin.Recovery()) - - // 注册健康检查路由 - app.HEAD("/", infra.Health) - - // 注册应用路由 - routers.Register(ServiceKey, app) - - addr := fmt.Sprintf(":%s", config.Spec.Port) - srv := &http.Server{Addr: addr, Handler: app} - - go func() { - if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { - panic(err) - } - }() - - printer.Success("[BSM - %s] Service Started At: %s", ServiceKey, addr) - - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit - - printer.Info("[BSM - %s] Shutting down...", ServiceKey) - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - if err := srv.Shutdown(ctx); err != nil { - panic(err) - } - - printer.Success("[BSM - %s] Service stopped", ServiceKey) -} diff --git a/server/etc/sample.env b/server/etc/sample.env deleted file mode 100644 index 190efed..0000000 --- a/server/etc/sample.env +++ /dev/null @@ -1,5 +0,0 @@ -# systemd EnvironmentFile 示例,复制为 /data/app/etc/sample.env 后按需修改 -BSM_Workspace=default -BSM_RuntimeMode=prod -BSM_Prefix=/data/app -BSM_JwtSecretKey=change-me-to-a-random-string diff --git a/server/etc/sample.service b/server/etc/sample.service deleted file mode 100644 index 14932f0..0000000 --- a/server/etc/sample.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Sample Service - -[Service] -Type=simple -Restart=always -RestartSec=5s -EnvironmentFile=/data/app/etc/sample.env -ExecStart=/data/app/sample -WorkingDirectory=/data/app/ -StandardOutput=file:/data/app/logs/sample.log -StandardError=file:/data/app/logs/sample.error.log - - -[Install] -WantedBy=multi-user.target \ No newline at end of file diff --git a/server/etc/sample_dev.yaml b/server/etc/sample_dev.yaml deleted file mode 100644 index 2946bdc..0000000 --- a/server/etc/sample_dev.yaml +++ /dev/null @@ -1,27 +0,0 @@ -Service: sample -Port: 12426 - -Databases: - Driver: postgres - Source: - - host=8.137.107.29 user=postgres password=Weidong2023~! dbname=sample_dev port=19432 sslmode=disable TimeZone=Asia/Shanghai - -# cache DB的选择请在后面直接带参数,不带会自动HASH计算选择DB库。 -Cache: redis://null:Weidong2023~!@8.137.107.29:19379/0 - -# 是否启用微服务模式 -OnMicroService: false - -# 微服务调用密钥 -SecretKey: 6ad9529688041483f458f8de11ed16ff - -# Rpc: -# fts: -# Endpoint: https://api-v2.traingo.cn/fts/v2 -# SecretKey: 4ef05311358cd1c8f787281f08b38b1c - - -# 链路追踪,性能监控,日志收集 -# APM: -# Platform: elasticAPM -# Endpoint: http://127.0.0.1:14268/api/traces diff --git a/server/etc/sample_prod.yaml b/server/etc/sample_prod.yaml deleted file mode 100644 index 43e53ac..0000000 --- a/server/etc/sample_prod.yaml +++ /dev/null @@ -1,27 +0,0 @@ -Service: sample -Port: 12426 - -Databases: - Driver: postgres - Source: - - host=8.137.107.29 user=postgres password=Weidong2023~! dbname=sample_prod port=19432 sslmode=disable TimeZone=Asia/Shanghai - -# cache DB的选择请在后面直接带参数,不带会自动HASH计算选择DB库。 -Cache: redis://null:Weidong2023~!@8.137.107.29:19379/0 - -# 是否启用微服务模式 -OnMicroService: false - -# 微服务调用密钥 -SecretKey: 6ad9529688041483f458f8de11ed16ff - -# Rpc: -# fts: -# Endpoint: https://api-v2.traingo.cn/fts/v2 -# SecretKey: 4ef05311358cd1c8f787281f08b38b1c - - -# 链路追踪,性能监控,日志收集 -# APM: -# Platform: elasticAPM -# Endpoint: http://127.0.0.1:14268/api/traces \ No newline at end of file diff --git a/server/etc/sample_test.yaml b/server/etc/sample_test.yaml deleted file mode 100644 index 4ab8e40..0000000 --- a/server/etc/sample_test.yaml +++ /dev/null @@ -1,27 +0,0 @@ -Service: sample -Port: 12426 - -Databases: - Driver: postgres - Source: - - host=8.137.107.29 user=postgres password=Weidong2023~! dbname=sample_test port=19432 sslmode=disable TimeZone=Asia/Shanghai - -# cache DB的选择请在后面直接带参数,不带会自动HASH计算选择DB库。 -Cache: redis://null:Weidong2023~!@8.137.107.29:19379/0 - -# 是否启用微服务模式 -OnMicroService: false - -# 微服务调用密钥 -SecretKey: 6ad9529688041483f458f8de11ed16ff - -# Rpc: -# fts: -# Endpoint: https://api-v2.traingo.cn/fts/v2 -# SecretKey: 4ef05311358cd1c8f787281f08b38b1c - - -# 链路追踪,性能监控,日志收集 -# APM: -# Platform: elasticAPM -# Endpoint: http://127.0.0.1:14268/api/traces \ No newline at end of file diff --git a/server/go.mod b/server/go.mod deleted file mode 100644 index c6d5203..0000000 --- a/server/go.mod +++ /dev/null @@ -1,80 +0,0 @@ -module git.apinb.com/ops/sample - -go 1.26.1 - -require ( - github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect - gorm.io/driver/mysql v1.6.0 // indirect -) - -require github.com/gin-gonic/gin v1.12.0 - -require github.com/patrickmn/go-cache v2.1.0+incompatible - -require ( - filippo.io/edwards25519 v1.2.0 // indirect - github.com/bytedance/gopkg v0.1.4 // indirect - github.com/bytedance/sonic v1.15.2 // indirect - github.com/bytedance/sonic/loader v0.5.1 // indirect - github.com/cloudwego/base64x v0.1.7 // indirect - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.13 // indirect - github.com/gin-contrib/cors v1.7.7 // indirect - github.com/gin-contrib/sse v1.1.1 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.30.3 // indirect - github.com/goccy/go-json v0.10.6 // indirect - github.com/goccy/go-yaml v1.19.2 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v5 v5.3.1 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mattn/go-isatty v0.0.22 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.4.0 // indirect - github.com/quic-go/qpack v0.6.0 // indirect - github.com/quic-go/quic-go v0.60.0 // indirect - github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.3.1 // indirect - go.etcd.io/etcd/api/v3 v3.6.12 // indirect - go.mongodb.org/mongo-driver/v2 v2.7.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.28.0 // indirect - golang.org/x/arch v0.28.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260618152121-87f3d3e198d3 // indirect -) - -require ( - git.apinb.com/bsm-sdk/core v0.2.0 - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-sql-driver/mysql v1.10.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.10.0 // indirect - github.com/jackc/puddle/v2 v2.2.2 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect - github.com/oklog/ulid/v2 v2.1.1 // indirect - github.com/redis/go-redis/v9 v9.20.1 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.12 // indirect - go.etcd.io/etcd/client/v3 v3.6.12 // indirect - golang.org/x/crypto v0.53.0 // indirect - golang.org/x/net v0.56.0 // indirect - golang.org/x/sync v0.21.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/text v0.38.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3 // indirect - google.golang.org/grpc v1.81.1 // indirect - google.golang.org/protobuf v1.36.11 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - gorm.io/driver/postgres v1.6.0 // indirect - gorm.io/gorm v1.31.1 -) diff --git a/server/go.sum b/server/go.sum deleted file mode 100644 index 84a603a..0000000 --- a/server/go.sum +++ /dev/null @@ -1,227 +0,0 @@ -filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= -filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= -git.apinb.com/bsm-sdk/core v0.2.0 h1:/e9yqpsbKBrRgMiGpS3KX2O4qDLxo5V5GpPSLNGxEKw= -git.apinb.com/bsm-sdk/core v0.2.0/go.mod h1:E9T6Eboo/0Zb36BjkKbIgvFzq4fQ2Q8P/7y5zmYTI6Y= -github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= -github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= -github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= -github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= -github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= -github.com/bytedance/sonic v1.15.2 h1:90H+rcF/FwLXwfB1cudOLq/je83n683Utf4Cbp0xHCo= -github.com/bytedance/sonic v1.15.2/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA= -github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI= -github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cloudwego/base64x v0.1.7 h1:NppS+Fgzg5ovhn4NkUXaDT3x9jldgH5ToMCqzBSi2zI= -github.com/cloudwego/base64x v0.1.7/go.mod h1:Cu1PV9zfrSf7ET2tIbWbbEy7jO7HHJ13q4X2SQ8aWYg= -github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= -github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= -github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= -github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= -github.com/gin-contrib/cors v1.7.7 h1:Oh9joP463x7Mw72vhvJ61YQm8ODh9b04YR7vsOErD0Q= -github.com/gin-contrib/cors v1.7.7/go.mod h1:K5tW0RkzJtWSiOdikXloy8VEZlgdVNpHNw8FpjUPNrE= -github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko= -github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s= -github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= -github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJLJuaYTeAH0DYy8= -github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc= -github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw= -github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk= -github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= -github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= -github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= -github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0= -github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= -github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= -github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= -github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= -github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= -github.com/pelletier/go-toml/v2 v2.4.0 h1:Mwu0mAkUKbittDs3/ADDWXqMmq3EOK2VHiuCkV00Row= -github.com/pelletier/go-toml/v2 v2.4.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0= -github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk= -github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= -github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= -github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0= -github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk= -github.com/redis/go-redis/v9 v9.20.1 h1:sfCU6A8P3dXbKyWes02uxA2baehGux9dZHfEKtsTB1w= -github.com/redis/go-redis/v9 v9.20.1/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= -github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= -github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= -github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= -go.etcd.io/etcd/api/v3 v3.6.12 h1:OLOZUKEuAA36TR48F0cIaa8FdzrWygjyfrJxXg4iDgs= -go.etcd.io/etcd/api/v3 v3.6.12/go.mod h1:p14EIQXHbuOQbVvL/WEes5uqKnxP9AgKJgpjbMVvzvE= -go.etcd.io/etcd/client/pkg/v3 v3.6.12 h1:36zzB+pQOdHbhN+kH2iJz/K8bJn0ZLtLfPPO7jozTDo= -go.etcd.io/etcd/client/pkg/v3 v3.6.12/go.mod h1:hh2+ZXtfLzs3o6mn92ntgNPBrTJJOvXqICM5g3L3DMY= -go.etcd.io/etcd/client/v3 v3.6.12 h1:kMSP6JcPZMqSJiX+TXdUIBU/4eXEZWBAaui4VihMbIc= -go.etcd.io/etcd/client/v3 v3.6.12/go.mod h1:CMs6fJWYiZQk4ytFjd4lE1diOvvRMmtbbn/alZXd3dQ= -go.mongodb.org/mongo-driver/v2 v2.7.0 h1:RO+zqavD2/GCL3cxOMyZhx6R9Irzr8/6gsoqx5tcY/c= -go.mongodb.org/mongo-driver/v2 v2.7.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= -go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= -go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= -go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= -go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.28.0 h1:wVwVdqsTuUbJvhYVCspQYwZXHNYeLSoZnmHD+ggddpQ= -golang.org/x/arch v0.28.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= -gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260618152121-87f3d3e198d3 h1:ctPmKL12ZsoKAlmPUsoW70zEDiYF+/H6aLieXxgAU0k= -google.golang.org/genproto/googleapis/api v0.0.0-20260618152121-87f3d3e198d3/go.mod h1:Z4WJ5pJOYWFWcHEQUelD5QaZDknIQkpIL/+fyJOT9+A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3 h1:phvBWCAQMGN1945mp5fjCXP6jEF0+a0+4TjokS4sxNY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260618152121-87f3d3e198d3/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= -google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= -google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= -google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= -gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= -gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= -gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= -gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= -gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/server/internal/config/config.go b/server/internal/config/config.go deleted file mode 100644 index d1b5cef..0000000 --- a/server/internal/config/config.go +++ /dev/null @@ -1,33 +0,0 @@ -package config - -import ( - "net" - - "git.apinb.com/bsm-sdk/core/conf" -) - -var ( - Spec SrvConfig -) - -type SrvConfig struct { - conf.Base `yaml:",inline"` - Databases *conf.DBConf `yaml:"Databases"` - Rpc map[string]conf.RpcConf `yaml:"Rpc"` - Apm *conf.ApmConf `yaml:"APM"` -} - -func New(srvKey string) { - // 初始化配置 创建一个新的配置实例,用于服务配置 - conf.New(srvKey, &Spec) - - // 配置校验 服务IP,端口; 端口如果不合规,则随机分配端口 - Spec.Port = conf.CheckPort(Spec.Port) - Spec.BindIP = conf.CheckIP(Spec.BindIP) - Spec.Addr = net.JoinHostPort(Spec.BindIP, Spec.Port) - - // 配置校验 服务名称地址及监听地址不能为空 - conf.NotNil(Spec.Service, Spec.Cache) - - conf.PrintInfo(Spec.Addr) -} diff --git a/server/internal/impl/new.go b/server/internal/impl/new.go deleted file mode 100644 index a1e2e32..0000000 --- a/server/internal/impl/new.go +++ /dev/null @@ -1,29 +0,0 @@ -package impl - -import ( - "git.apinb.com/bsm-sdk/core/cache/redis" - "git.apinb.com/bsm-sdk/core/logger" - "git.apinb.com/bsm-sdk/core/with" - "git.apinb.com/ops/sample/internal/config" - "github.com/patrickmn/go-cache" - "gorm.io/gorm" -) - -var ( - RedisService *redis.RedisClient // Redis 客户端服务 - DBService *gorm.DB // 数据库服务 - MemoryService *cache.Cache // 内存缓存服务 - Logger *logger.Logger -) - -// NewImpl 初始化各类服务实例 -func NewImpl() { - // 初始化内存缓存 - MemoryService = with.Memory(nil) - // 初始化 Redis 缓存 - RedisService = with.RedisCache(config.Spec.Cache) - // 初始化数据库服务 - DBService = with.Databases(config.Spec.Databases, nil) - // 初始化 日志服务 - logger.New(nil) -} diff --git a/server/internal/logic/demo/demo.go b/server/internal/logic/demo/demo.go deleted file mode 100644 index c884ffd..0000000 --- a/server/internal/logic/demo/demo.go +++ /dev/null @@ -1,125 +0,0 @@ -package demo - -import ( - "git.apinb.com/bsm-sdk/core/errcode" - "git.apinb.com/bsm-sdk/core/infra" - "git.apinb.com/bsm-sdk/core/utils" - "git.apinb.com/ops/sample/internal/models" - "github.com/gin-gonic/gin" -) - -type CreateRequest struct { - Name string `json:"name" binding:"required,max=255"` - Age int `json:"age"` -} - -type UpdateRequest struct { - Name string `json:"name" binding:"required,max=255"` - Age int `json:"age"` -} - -type ListReply struct { - Total int64 `json:"total"` - List []models.SampleDemo `json:"list"` -} - -func Create(ctx *gin.Context) { - var req CreateRequest - if err := ctx.ShouldBindJSON(&req); err != nil { - infra.Response.Error(ctx, errcode.ErrInvalidArgument) - return - } - - data := models.SampleDemo{ - Name: req.Name, - Age: req.Age, - } - data.Identity = utils.UUID() - data.Status = 1 - if err := models.CreateSampleDemo(&data); err != nil { - infra.Response.Error(ctx, err) - return - } - infra.Response.Success(ctx, data) -} - -func List(ctx *gin.Context) { - page := utils.String2Int(ctx.DefaultQuery("page", "1")) - size := utils.String2Int(ctx.DefaultQuery("size", "20")) - if page < 1 { - page = 1 - } - if size < 1 || size > 100 { - size = 20 - } - - list, total, err := models.ListSampleDemos(page, size) - if err != nil { - infra.Response.Error(ctx, err) - return - } - infra.Response.Success(ctx, ListReply{Total: total, List: list}) -} - -func Get(ctx *gin.Context) { - identity := ctx.Param("identity") - if identity == "" { - infra.Response.Error(ctx, errcode.ErrInvalidArgument) - return - } - - data, err := models.GetSampleDemoByField("identity", identity) - if err != nil { - infra.Response.Error(ctx, err) - return - } - infra.Response.Success(ctx, data) -} - -func Update(ctx *gin.Context) { - identity := ctx.Param("identity") - if identity == "" { - infra.Response.Error(ctx, errcode.ErrInvalidArgument) - return - } - - var req UpdateRequest - if err := ctx.ShouldBindJSON(&req); err != nil { - infra.Response.Error(ctx, errcode.ErrInvalidArgument) - return - } - - data, err := models.GetSampleDemoByField("identity", identity) - if err != nil { - infra.Response.Error(ctx, err) - return - } - - data.Name = req.Name - data.Age = req.Age - if err := models.UpdateSampleDemo(data); err != nil { - infra.Response.Error(ctx, err) - return - } - infra.Response.Success(ctx, data) -} - -func Delete(ctx *gin.Context) { - identity := ctx.Param("identity") - if identity == "" { - infra.Response.Error(ctx, errcode.ErrInvalidArgument) - return - } - - data, err := models.GetSampleDemoByField("identity", identity) - if err != nil { - infra.Response.Error(ctx, err) - return - } - - if err := models.DeleteSampleDemo(data); err != nil { - infra.Response.Error(ctx, err) - return - } - infra.Response.Success(ctx, identity) -} diff --git a/server/internal/logic/ping/hello.go b/server/internal/logic/ping/hello.go deleted file mode 100644 index 0066af7..0000000 --- a/server/internal/logic/ping/hello.go +++ /dev/null @@ -1,10 +0,0 @@ -package ping - -import ( - "git.apinb.com/bsm-sdk/core/infra" - "github.com/gin-gonic/gin" -) - -func Hello(ctx *gin.Context) { - infra.Response.Success(ctx, "OK") -} diff --git a/server/internal/models/query.go b/server/internal/models/query.go deleted file mode 100644 index a9eb81b..0000000 --- a/server/internal/models/query.go +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @Author: David Yan(david.yan@qq.com) - * @Description: 自定义查询方法 - */ - -package models diff --git a/server/internal/models/sample_demo.go b/server/internal/models/sample_demo.go deleted file mode 100644 index e3ef4aa..0000000 --- a/server/internal/models/sample_demo.go +++ /dev/null @@ -1,86 +0,0 @@ -package models - -import ( - "errors" - - "git.apinb.com/bsm-sdk/core/database" - "git.apinb.com/bsm-sdk/core/errcode" - "git.apinb.com/bsm-sdk/core/types" - "git.apinb.com/ops/sample/internal/impl" - "gorm.io/gorm" -) - -/* - * SampleDemo - * Comment: 示例数据表 - * Version: 10 - * Created: 2022-04-12 10:44:51 , Updated:0001-01-01 00:00:00 - */ -type SampleDemo struct { - types.Std_IICUDS - Name string `gorm:"column:name;type:varchar(255);default:'';" json:"name"` // 名称 - Age int `gorm:"column:age;type:int;default:0;" json:"age"` // 年龄 -} - -func init() { - database.AppendMigrate(&SampleDemo{}) -} - -// TableName . -func (table *SampleDemo) TableName() string { - return "sample_demo" //对应数据库表名 -} - -// GetSampleDemoByField 根据特定字段值获取 SampleDemo 对象 -func GetSampleDemoByField(field string, value any) (*SampleDemo, error) { - var ( - data SampleDemo - condition = map[string]any{field: value} - ) - err := impl.DBService.Where(condition).First(&data).Error - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, errcode.ErrRecordNotFound - } - return nil, errcode.ErrDB - } - - return &data, nil -} - -func CreateSampleDemo(data *SampleDemo) error { - if err := impl.DBService.Create(data).Error; err != nil { - return errcode.ErrDB - } - return nil -} - -func ListSampleDemos(page, size int) ([]SampleDemo, int64, error) { - var ( - list []SampleDemo - total int64 - ) - db := impl.DBService.Model(&SampleDemo{}) - if err := db.Count(&total).Error; err != nil { - return nil, 0, errcode.ErrDB - } - offset := (page - 1) * size - if err := db.Order("id desc").Offset(offset).Limit(size).Find(&list).Error; err != nil { - return nil, 0, errcode.ErrDB - } - return list, total, nil -} - -func UpdateSampleDemo(data *SampleDemo) error { - if err := impl.DBService.Save(data).Error; err != nil { - return errcode.ErrDB - } - return nil -} - -func DeleteSampleDemo(data *SampleDemo) error { - if err := impl.DBService.Delete(data).Error; err != nil { - return errcode.ErrDB - } - return nil -} diff --git a/server/internal/routers/register.go b/server/internal/routers/register.go deleted file mode 100644 index 8a680a9..0000000 --- a/server/internal/routers/register.go +++ /dev/null @@ -1,36 +0,0 @@ -package routers - -import ( - "fmt" - - "git.apinb.com/bsm-sdk/core/middleware" - "git.apinb.com/ops/sample/internal/logic/demo" - "git.apinb.com/ops/sample/internal/logic/ping" - "github.com/gin-gonic/gin" -) - -// Register 注册路由,请求地址格式: ip:port/{srvKey}/v1/{group}/{action} -func Register(srvKey string, engine *gin.Engine) { - v1Key := fmt.Sprintf("/%s/%s", srvKey, "v1") - registerAnonymous(v1Key, engine) - registerRouters(v1Key, engine) -} - -func registerAnonymous(v1Key string, engine *gin.Engine) { - anonymous := engine.Group(v1Key) - { - anonymous.GET("/ping/hello", ping.Hello) - } -} - -func registerRouters(v1Key string, engine *gin.Engine) { - demoGroup := engine.Group(fmt.Sprintf("/%s/%s", v1Key, "demo")) - demoGroup.Use(middleware.JwtAuth(true)) - { - demoGroup.POST("", demo.Create) - demoGroup.GET("", demo.List) - demoGroup.GET("/:identity", demo.Get) - demoGroup.PUT("/:identity", demo.Update) - demoGroup.DELETE("/:identity", demo.Delete) - } -} diff --git a/server/scripts/build.sh b/server/scripts/build.sh deleted file mode 100644 index e714655..0000000 --- a/server/scripts/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -euo pipefail - -mkdir -p build - -GOARCH=amd64 GOOS=linux go build -o ./build/sample ./cmd/main/main.go -GOARCH=amd64 GOOS=linux go build -o ./build/sample-cli ./cmd/cli/main.go - -echo "build completed: ./build/sample, ./build/sample-cli" diff --git a/server/scripts/lint.sh b/server/scripts/lint.sh deleted file mode 100644 index 04c3eea..0000000 --- a/server/scripts/lint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -euo pipefail - -go vet ./... -go fmt ./... diff --git a/server/scripts/update.sh b/server/scripts/update.sh deleted file mode 100644 index 3fc9e12..0000000 --- a/server/scripts/update.sh +++ /dev/null @@ -1,7 +0,0 @@ -git pull -go get all -go get -u ./... -go mod tidy -git add . -git commit -m 'run ./scripts/update.sh' -git push \ No newline at end of file diff --git a/server/test/demo/crud.http b/server/test/demo/crud.http deleted file mode 100644 index a11b09f..0000000 --- a/server/test/demo/crud.http +++ /dev/null @@ -1,31 +0,0 @@ -### 创建示例数据(需要 JWT) -POST http://127.0.0.1:12426/Sample/v1/sample/demo -Content-Type: application/json -Authorization: Bearer {{token}} - -{ - "name": "Alice", - "age": 25 -} - -### 列表查询 -GET http://127.0.0.1:12426/Sample/v1/sample/demo?page=1&size=20 -Authorization: Bearer {{token}} - -### 详情查询 -GET http://127.0.0.1:12426/Sample/v1/sample/demo/{{identity}} -Authorization: Bearer {{token}} - -### 更新 -PUT http://127.0.0.1:12426/Sample/v1/sample/demo/{{identity}} -Content-Type: application/json -Authorization: Bearer {{token}} - -{ - "name": "Alice Updated", - "age": 26 -} - -### 删除 -DELETE http://127.0.0.1:12426/Sample/v1/sample/demo/{{identity}} -Authorization: Bearer {{token}} diff --git a/server/test/ping/hello.http b/server/test/ping/hello.http deleted file mode 100644 index 8ce1970..0000000 --- a/server/test/ping/hello.http +++ /dev/null @@ -1,2 +0,0 @@ -GET http://127.0.0.1:12426/Sample/v1/ping/hello -Content-Type: application/json diff --git a/server/test/readme.md b/server/test/readme.md deleted file mode 100644 index 84209b9..0000000 --- a/server/test/readme.md +++ /dev/null @@ -1,2 +0,0 @@ -# HTTP 接口测试文件,使用 VS Code REST Client 或 IntelliJ HTTP Client 运行。 -# 将 {{token}}、{{identity}} 替换为实际值。