Files
junhong_cmp_fiber/ARCHITECTURE.md
break e134552ec5
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m35s
更新
2026-08-13 12:31:47 +08:00

12 KiB
Raw Blame History

系统架构地图

系统职责与非职责

本系统保存物联网卡、设备、套餐、订单、钱包、分佣、审批、通知和审计的本地业务事实并协调支付、运营商、Gateway、企业微信、短信和对象存储。第三方内部状态、审批流配置、支付清算和运营商网络行为不是本系统事实外部契约见 docs/integrations/

Composition Roots 与运行单元

单元 入口 启动链与外部依赖 验证
HTTP API cmd/api/main.go Viper 配置 → 日志目录 → PostgreSQL → Redis/Asynq Client → JWT/验证码 → Storage/Gateway → internal/bootstrap.Bootstrap → Fiber 中间件与路由;启动时写 logs/openapi.yaml go build ./cmd/api;启动后请求 /health/ready
Worker cmd/worker/main.go PostgreSQL、Redis、Storage、Gateway → internal/bootstrap.BootstrapWorker → Task Handler、Outbox Relay、任务救援角色决定单例调度模块 go build ./cmd/worker;从应用日志核对角色、模块和任务注册
OpenAPI 生成 cmd/gendocs/main.go 使用占位 Handler 复用 internal/routes.RegisterRoutesWithDoc,生成接口文档 go run cmd/gendocs/main.go;它证明路由元数据,不单独证明真实 Bootstrap 可达性
治理 CLI cmd/foundation-checkcmd/audit-coveragecmd/migration-finalizecmd/audit-retention-simulate 读取源码、迁移或数据库状态并输出门禁/模拟结果 逐命令检查输入;audit-coverage 当前仍依赖已删除路径,见工程约束 BLOCKED 项

启动、隔离数据库、smoke 与日志命令见 README.md。生产为独立的 systemd 手工二进制发布拓扑,不以 Docker Compose 或 CI 工作流为准;运行事实与人工发布边界见 docs/deployment/production-runbook.md

Worker 角色

pkg/config/config.go 接受 allleaderconsumer

  • 三种角色都启动 Asynq 消费服务、Outbox Relay 和未完成导入任务救援。
  • leaderall 额外启动轮询初始化器、轮询调度器和 Asynq Scheduler。
  • consumer 不运行单例调度模块,适合横向扩展消费能力。
  • 实际启停判断位于 cmd/worker/main.gobuildWorkerModuleStatusrunsSingletonModules

HTTP 路由与信任边界

总入口是 internal/routes/routes.go

路由域 认证/信任边界 主要入口 当前 Spec 索引
/health/ready 公开,只返回进程健康/就绪状态 internal/routes/health.go openspec/specs/operations-audit/spec.md
/api/auth 后台账号登录、刷新、登出与当前身份;认证中间件在路由组装配 internal/routes/auth.go openspec/specs/identity-access/spec.md
/api/admin 后台认证、角色权限、店铺/企业数据范围;业务层仍需资源级校验 internal/routes/admin.go identity-accessasset-devicepackage-lifecycleorder-payment-walletoperations-audit
/api/c/v1 个人客户 Token 与资产归属边界 internal/routes/personal.go openspec/specs/personal-customer/spec.md
/api/open/v1 代理 Open API 独立认证/签名,不复用后台账号权限 internal/routes/open.go openspec/specs/agent-open-api/spec.md
/api/callback 无登录认证;每类渠道必须在 Handler/Adapter 内验签、解密、校验金额或事件身份 internal/routes/order.gowecom_callback.go 及运营商回调注册 openspec/specs/external-integration/spec.mdorder-payment-wallet

HTTP 入参、回调 Body/Header、上传文件和代理签名材料均是不可信输入。Handler 只做绑定、边界校验与响应;状态和金额不变量必须由业务用例重新判断。

分层与实际共存结构

  • internal/routes:可达 HTTP 入口与 RouteSpec。
  • internal/handlerFiber 信任边界、参数绑定和统一响应。
  • internal/application新用例编排、事务脚本、Port 和可靠副作用边界。
  • internal/domain:状态、金额与并发不变量;不依赖 Fiber、GORM、Redis、Asynq 或外部 SDK。
  • internal/query:只读权限、联表、分页和 DTO 投影。
  • internal/service:旧用例;允许直接使用 Store/GORM按完整用例渐进迁移。
  • internal/infrastructurePort Adapter、GORM Repository、Outbox、审计与外部交互。
  • internal/store/postgresinternal/model:旧持久化模型与显式查询。
  • internal/bootstrapAPI/Worker 依赖装配,不承载业务规则。
  • pkg:跨模块基础能力和第三方客户端。
  • migrationsSchema 演进事实。

允许方向Handler → Application/Query/旧 ServiceApplication → Domain + PortInfrastructure → Application/Domain Port旧 Service → Store/GORM。禁止 Domain 依赖框架或基础设施、Query 修改状态、Handler 拼装领域规则、Infrastructure 定义业务状态机。

! grep -RIlE 'gofiber|gorm.io|go-redis|hibiken/asynq' internal/domain --include='*.go'

关键业务模块导航

以下表是入口地图,不替代业务 Specs事务与副作用必须按具体调用链证明。

业务能力 HTTP/异步入口 用例与领域 持久化/外部边界 Spec
后台身份、账号、角色、权限、店铺 routes/auth.goaccount.gorole.gopermission.goshop.go `handler/auth admin;旧 service/auth account
卡、设备、资产与企业授权 iot_card.godevice.goasset*.goenterprise_card.goenterprise_device.go;导入/轮询任务 旧 `service/iot_card device asset
套餐、系列、授权、订购与到期 package*.go、批量分配/调价/订购路由;激活、到期和失效任务 旧 `service/package package_series shop_*domain/packageapplication/packageexpiry`
订单、支付、充值、钱包、退款、分佣与换货 order.goagent_recharge.gorefund.gocommission.goexchange.go、支付回调 旧 `service/order recharge refund
个人客户 routes/personal.go 及 C 端子路由 handler/app`service/client_* personal_customer customer_binding`;通知 Application/Query
代理 Open API routes/open.go handler/openapiservice/agent_open_api 独立认证、店铺数据范围、卡/套餐/钱包 Store agent-open-api
轮询、通知、导出、配置与审计调查 polling_*.gonotification.goexport_task.gosystem_config.goaudit.goScheduler/Task/Outbox `application/notification systemconfig auditarchive
外部集成接点 支付/运营商/企微回调Gateway 调用,对象存储、短信 internal/gateway、`internal/infrastructure/wecom payment carriercallback

任务 7 会把当前过大的 Spec 索引拆成完整业务能力;拆分后必须同步本表链接。

同步数据流

HTTP Route
→ 认证/数据范围中间件
→ Handler绑定与信任边界
→ Application / Query / 旧 Service
→ Domain仅适用于已迁移复杂写
→ Repository / Store / GORM
→ pkg/response 或全局 ErrorHandler

并非所有写操作都在统一事务中:旧 Service 可能直接写 Store新 Application 可能使用事务脚本,复杂写可能通过 Domain + Port。审计、状态条件和事务范围必须从具体用例证明不能由这张地图推断。

异步与可靠事件

Asynq Task

Worker 当前处理的任务族包括:卡/设备导入、导出分片与收尾、资产批量购包、订单套餐失效、自动充值后购包、佣金、订单过期、五类轮询、告警、数据/通知清理、套餐到期提醒、每日流量落盘、企微审批同步/恢复、代理充值恢复、审计/集成归档和 Outbox 投递。

发现真实注册与生产位置:

rg -o 'constants\.TaskType[A-Za-z0-9_]+' cmd/worker/main.go internal/task internal/bootstrap/worker.go internal/infrastructure | sort -u

直接 EnqueueTask 只证明已提交,不等于业务终态成功;最终状态由 Task Handler 的条件更新、记录或补偿决定。

Outbox

当前事件族覆盖审批提交/终态、卡实名/流量/网络/系列、代理充值支付确认、代理主钱包扣款/预留/入账/退款,以及后台/个人通知。

rg -o 'constants\.OutboxEventType[A-Za-z0-9_]+' cmd/worker/main.go internal | sort -u

需要业务事实与可靠异步副作用原子提交的用例应同事务写 Outbox是否已经做到必须逐调用链核对。Relay 和消费者按至少一次投递设计,消费者必须容忍重复。

外部调用与回调

  • 支付:创建本地支付事实后调用渠道;回调需要验签、金额/业务号/状态校验,重复回调不得重复入账。
  • 企业微信:本地审批实例 → Outbox 提交 → 渠道审批;加密回调、轮询和人工同步进入统一状态同步语义。
  • Gateway/运营商:查询与控制结果来自外部;超时或未知结果不得理想化为成功。
  • 对象存储:上传/预签名 URL 是外部副作用,数据库只保存对象引用。
  • SMS发送结果是外部通知结果不等同业务事务成功。

外部网络调用不应持有长数据库事务;确需提交后可靠执行时使用 Outbox/Task。实际例外按 As-Is Spec 记录。

事务、审计与日志边界

  • Access LogHTTP 调试事实。
  • Audit Event操作者、资源、动作、前后值和结果。
  • Domain Ledger/钱包交易:金额与状态领域事实。
  • Integration Log外部调用尝试和脱敏结果。
  • Outbox提交后可靠副作用不替代前三者。

成功高风险操作是否与审计同事务必须逐用例核对。业务已回滚后的 failed/denied 审计使用独立短事务。不得用 Access Log 证明资金或状态事实。

结构与生成验证

go build ./cmd/api ./cmd/worker
go run cmd/gendocs/main.go
openspec doctor --json
openspec validate --all
./scripts/context-health.sh
! grep -RIlE 'gofiber|gorm.io|go-redis|hibiken/asynq' internal/domain --include='*.go'
rg 'Register[A-Za-z]*Routes|register[A-Za-z]*Routes' internal/routes

OpenAPI 生成器使用占位 Handler因此还要对照 internal/bootstrap 与真实路由装配。Schema 事实以 migrations/ 和隔离数据库为准,禁止使用 Makefile 中的历史连接信息。