11 KiB
11 KiB
Architecture
Analysis Date: 2026-03-27
Pattern Overview
Overall: 双进程分层单体(API + Worker),核心代码按 Handler → Service → Store → Model 组织。
Key Characteristics:
- HTTP 入口与异步任务入口分离:
cmd/api/main.go负责 Fiber API,cmd/worker/main.go负责 Asynq Worker 与轮询调度。 - 依赖集中在
internal/bootstrap/组装,再分发给internal/routes/、internal/handler/、internal/task/。 - 数据访问主要走
internal/store/postgres/*.go,模型与 DTO 分别位于internal/model/*.go与internal/model/dto/*.go。 - 路由注册统一经过
internal/routes/registry.go的Register(),同时驱动 Fiber 路由与 OpenAPI 元数据。 - 多租户与权限控制主要依赖认证上下文 + Store 层显式过滤函数,而不是数据库外键或 ORM 关联。
Layers
Entrypoint / Composition Layer:
- Purpose: 进程启动、基础设施初始化、依赖装配、生命周期管理。
- Location:
cmd/api/main.go,cmd/worker/main.go,internal/bootstrap/*.go - Contains: 配置加载、日志、数据库、Redis、队列、对象存储、Gateway 客户端、Bootstrap 编排。
- Depends on:
pkg/config,pkg/database,pkg/logger,pkg/queue,pkg/storage,internal/bootstrap - Used by: 整个应用进程。
Routing / Transport Layer:
- Purpose: 路由域划分、认证挂载、HTTP 入参与响应封装、OpenAPI 文档注册。
- Location:
internal/routes/*.go,internal/handler/**/*.go - Contains:
RegisterRoutesWithDoc()总入口、Admin/Auth/Personal 域路由、Fiber Handler。 - Depends on:
internal/bootstrap.Handlers,internal/bootstrap.Middlewares,pkg/openapi,pkg/response - Used by:
cmd/api/main.go
Service Layer:
- Purpose: 业务规则、权限判断、事务编排、幂等、异步任务提交、跨模块协作。
- Location:
internal/service/**/*.go - Contains: 账号、订单、套餐、轮询、设备、卡、认证、充值、佣金等服务。
- Depends on:
internal/store/postgres,pkg/errors,pkg/middleware,pkg/queue,pkg/wechat,gorm.DB,redis.Client - Used by: Handler 层、Worker Bootstrap、Task Handler。
Store Layer:
- Purpose: SQL 查询、分页、显式数据权限过滤、缓存辅助、事务基础能力。
- Location:
internal/store/store.go,internal/store/options.go,internal/store/postgres/*.go - Contains: 每个聚合的 PostgreSQL Store,例如
internal/store/postgres/account_store.go,internal/store/postgres/order_store.go。 - Depends on:
gorm,redis,pkg/middleware/data_scope.go - Used by: Service 层、部分 Handler 组装期专用读模型。
Model Layer:
- Purpose: 持久化模型、DTO、常量化状态值、表名映射。
- Location:
internal/model/*.go,internal/model/dto/*.go - Contains:
model.Account,model.Order,model.Shop,model.PollingConfig以及请求/响应 DTO。 - Depends on: GORM tags、标准库类型。
- Used by: Store、Service、Handler、OpenAPI 生成。
Task / Worker Layer:
- Purpose: Asynq 任务处理、轮询调度、定时任务、批处理导入。
- Location:
internal/task/*.go,internal/polling/*.go,pkg/queue/*.go - Contains:
pkg/queue/handler.go任务注册器、internal/task/polling_handler.go、internal/task/order_expire.go、internal/polling/scheduler.go。 - Depends on: Worker bootstrap 产出的 stores/services、Redis、Asynq、Gateway。
- Used by:
cmd/worker/main.go
Data Flow
API Request Flow:
cmd/api/main.go创建 Fiber 应用并注册 Recover、RequestID、访问日志、压缩中间件。internal/routes/routes.go将请求分发到/api/auth、/api/admin、/api/c/v1、/api/callback四个域。pkg/middleware/auth.go或internal/middleware/personal_auth将用户信息写入 FiberLocals和标准context.Context。- Handler 解析 DTO 并调用 Service,例如
internal/handler/admin/account.go→internal/service/account/service.go。 - Service 调用一个或多个 Store,必要时使用
db.WithContext(ctx).Transaction(...)编排事务,例如internal/service/order/service.go。 - Store 在查询中显式调用
pkg/middleware/data_scope.go的过滤函数,例如internal/store/postgres/account_store.go、internal/store/postgres/order_store.go。 - Handler 通过
pkg/response/response.go返回统一响应;异常交由internal/middleware.ErrorHandler处理。
Worker Flow:
cmd/worker/main.go初始化 PostgreSQL、Redis、Asynq Client、对象存储、Gateway。internal/bootstrap/worker.go调用initWorkerStores()与initWorkerServices(),生成queue.WorkerBootstrapResult。pkg/queue/handler.go基于 Bootstrap 结果注册导入、轮询、佣金、超时取消、告警、清理等任务处理器。internal/polling/scheduler.go独立运行轮询调度循环:从 Redis Sorted Set / List 取卡片,再投递到 Asynq。cmd/worker/main.go还额外创建 Asynq Scheduler,注册TaskTypeOrderExpire、TaskTypeAlertCheck、TaskTypeDataCleanup。- 具体任务处理器调用 Service 或直接使用 Store/DB 更新状态,例如
internal/task/order_expire.go→order.Service.CancelExpiredOrders()。
State Management:
- HTTP 侧状态主要放在 PostgreSQL;请求态身份与数据权限范围放在
context.Context。 - 高速状态、Token、轮询队列、并发信号量、下级店铺缓存放在 Redis,如
pkg/auth/token.go、internal/polling/scheduler.go、internal/store/postgres/shop_store.go。 - 异步处理采用 Redis-backed Asynq 队列,由
pkg/queue/client.go提交、pkg/queue/server.go消费。
Key Abstractions
BootstrapResult / WorkerBootstrapResult:
- Purpose: 启动期依赖编排结果。
- Examples:
internal/bootstrap/bootstrap.go,internal/bootstrap/worker.go - Pattern: 显式依赖注入,不使用外部 DI 框架。
Handlers / Middlewares 容器:
- Purpose: 路由注册时的装配清单。
- Examples:
internal/bootstrap/types.go,internal/bootstrap/handlers.go,internal/bootstrap/middlewares.go - Pattern: 结构体聚合所有已构造的 Handler 与 Middleware。
RouteSpec + Register():
- Purpose: 单次声明同时完成真实路由注册和 OpenAPI 元数据注册。
- Examples:
internal/routes/registry.go,internal/routes/account.go,internal/routes/personal.go - Pattern: 代码即文档,DTO 驱动文档生成。
QueryOptions:
- Purpose: Store 通用分页与排序选项。
- Examples:
internal/store/options.go,internal/service/account/service.go,internal/service/order/service.go - Pattern: Service 先构造查询选项,再下传到 Store。
UserContextInfo + Data Scope Filters:
- Purpose: 承载用户身份与可管理店铺范围,并在 Store 查询时执行过滤。
- Examples:
pkg/middleware/auth.go,pkg/middleware/data_scope.go,internal/store/postgres/shop_store.go - Pattern: 中间件预计算
SubordinateShopIDs,Store 按字段类型显式调用ApplyShopFilter/ApplyEnterpriseFilter/ApplySellerShopFilter。
Entry Points
API Main:
- Location:
cmd/api/main.go - Triggers:
go run cmd/api/main.go、API 容器启动。 - Responsibilities: 加载配置、初始化基础设施、执行
bootstrap.Bootstrap()、创建 Fiber、注册中间件和路由、生成运行时 OpenAPI 文件logs/openapi.yaml。
Worker Main:
- Location:
cmd/worker/main.go - Triggers:
go run cmd/worker/main.go、Worker 容器启动。 - Responsibilities: 初始化 Worker 依赖、执行
bootstrap.BootstrapWorker()、启动 Asynq Worker、启动轮询调度器和 Asynq Scheduler、优雅关闭。
OpenAPI Generation CLI:
- Location:
cmd/gendocs/main.go - Triggers: 手动执行文档生成。
- Responsibilities: 通过
openapi.BuildDocHandlers()+routes.RegisterRoutesWithDoc()输出docs/admin-openapi.yaml。
Routing Strategy
Domain Split:
/api/auth:统一后台/H5 认证,见internal/routes/auth.go/api/admin:管理后台业务域,见internal/routes/admin.go/api/c/v1:个人客户端域,见internal/routes/personal.go/api/callback:支付回调,无认证,见internal/routes/order.go与internal/handler/callback/payment.go
Registration Style:
- 所有 HTTP 接口使用
internal/routes/registry.go的Register(),文档规范见docs/api-documentation-guide.md。 internal/routes/admin.go以 handler 是否为nil决定是否挂载模块,便于文档生成和裁剪。internal/routes/personal.go明确区分公开路由与认证路由,并依赖注册顺序确保公开接口不被Use()拦截。
Error Handling
Strategy: 统一错误码 + 全局 Fiber ErrorHandler。
Patterns:
- Handler 层只做参数解析与转发,返回
pkg/errors中的AppError,如internal/handler/admin/account.go。 - Service 层封装业务错误,不直接向外泄露底层错误文本,如
internal/service/account/service.go、internal/service/order/service.go。 - Worker 任务记录结构化日志,并将可重试与不可重试逻辑写在处理器内部,如
internal/task/order_expire.go、internal/task/polling_handler.go。
Cross-Cutting Concerns
Logging:
pkg/logger/logger.go初始化 App/Access 日志;pkg/logger/middleware.go记录完整请求/响应摘要。
Validation:
- Fiber
BodyParser/QueryParser+validator.v10,示例见internal/handler/auth/handler.go。
Authentication:
- 后台/H5 使用 Redis Token +
pkg/middleware/auth.go;个人客户使用单独中间件,由internal/bootstrap/middlewares.go创建。
OpenAPI:
- 路由元数据写在
RouteSpec;文档生成器依赖cmd/api/docs.go、cmd/gendocs/main.go、pkg/openapi/handlers.go三处手工维护 Handler 清单。
Persistence Rules:
- 模型显式声明
TableName()与字段列名,如internal/model/account.go,internal/model/order.go,internal/model/shop.go。 - 数据库结构通过
migrations/*.sql管理,pkg/database/postgres.go明确禁用自动建表。
Architectural Deviations
README / 规范与当前实现存在的偏差:
README.md与openspec/config.yaml多处描述“GORM Callback 自动注入数据权限过滤”,但当前internal/bootstrap/bootstrap.go第 67 行明确写明“数据权限过滤已移至 Store 层显式调用 ApplyXxxFilter 函数”。当前保留的 GORM Callback 只有pkg/gorm/callback.go中的创建人/更新人自动填充。internal/bootstrap/handlers.go为客户端场景直接新建多个 Store 和一个client_orderService,而不是完全只消费services聚合;这说明 Handler 装配阶段存在读模型/适配层级的额外拼装。internal/task/polling_handler.go在首次实名激活流程中先构造 Asynq 任务,但实际通过 Redis ListRPush提交,文件内注释明确写出“实际应该通过依赖注入 asynq.Client”;这是 Worker 流程中的特殊机制与待收敛点。
Architecture analysis: 2026-03-27