material_manage_system/docs/项目后端结构说明.md
文睿 张 2a6a3c6bba docs: 补充后端结构说明并更新公司隔离进度
- 新增《项目后端结构说明》,梳理仓库布局、internal 分层与请求链路
- 《数据库表结构与关系说明》新增第 11 节,记录公司隔离发布后的表、约束与升级阻断规则
- 公司隔离计划补充精简版测试策略,并勾选 Task 2、Task 8 完成项与验收记录
2026-10-09 15:55:52 +08:00

87 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 项目后端结构说明
本文介绍仓库的整体布局,重点是后端 `internal/` 的分层职责:每个文件负责什么、一次请求经过哪些环节。配套阅读:《[数据库表结构与关系说明](数据库表结构与关系说明.md)》《[API 文档](api.md)》。
## 仓库顶层布局
| 目录/文件 | 说明 |
| --- | --- |
| `cmd/server/` | 后端入口 `main.go`:读 DSN、连库、建默认用户、校验 schema、注册路由并启动 |
| `internal/` | 后端内核,见下文分层说明 |
| `pkg/` | 通用基础包:`database`(连接与 DSN 规范化)、`response`(统一响应格式与状态码封装) |
| `frontend/` | 前端源码与构建产物(`frontend/dist` 为后端静态托管的目录) |
| `scripts/` | `init.sql`、增量升级 SQL 与校验脚本 |
| `docs/` | 项目文档 |
## 整体
`cmd/server/main.go` 是入口(注册路由、连库、校验 schema),`internal/` 只是内核。一次请求的链路是:
```
middleware(认证/公司校验)→ handler(绑参、回响应)→ service(业务规则、校验、组装)→ repository(纯 SQL)→ model(结构体)
```
响应统一走 `pkg/response`,连库在 `pkg/database`。
## handler/(HTTP 层)
`api.go` 是大头(1604 行)。
| 文件 | 职责 |
| --- | --- |
| [api.go](../internal/handler/api.go) | `Handler` 聚合全部 service;`RegisterRoutes` 定义所有路由与中间件挂载;物料、出入库、库存、用户、申请等主体 handler |
| [admin_master.go](../internal/handler/admin_master.go) | 管理端:公司、角色、权限、物料分类、单位、编码规则、往来单位、仓库/库位,另含 `organizationID` / `pathID` / `bind` 三个公共小工具 |
| [organization_context.go](../internal/handler/organization_context.go) | 公司切换器:列出可访问公司、切换当前公司上下文 |
| [upload.go](../internal/handler/upload.go) | 图片上传 |
| [websocket.go](../internal/handler/websocket.go) | 库存变更实时推送的 Hub、Client、广播,以及 `/ws` 握手(凭一次性票据 + 实时复核授权) |
## middleware/(3 个)
| 文件 | 职责 |
| --- | --- |
| [auth.go](../internal/middleware/auth.go) | JWT 解析、`AdminOnly`、`OptionalAuth`,以及取 userID / username / roles 的辅助函数 |
| [organization.go](../internal/middleware/organization.go) | 校验 `X-Organization-ID` 头并确认该用户能访问这家公司,通过后写进 context |
| [rate_limiter.go](../internal/middleware/rate_limiter.go) | 登录失败次数限流 + 定期清理 |
## service/(业务规则)
| 文件 | 职责 |
| --- | --- |
| [material.go](../internal/service/material.go) | 物料增改查、作废/恢复 |
| [inbound.go](../internal/service/inbound.go) / [outbound.go](../internal/service/outbound.go) | 出入库单的业务校验与库存联动 |
| [stock.go](../internal/service/stock.go) | 库存查询、预警分类、变动量计算 |
| [inventory_scope.go](../internal/service/inventory_scope.go) | 公司维度的仓库/库位解析:库存读写一律由服务端从库里推导,不收前端传的 ID;写操作要求启用状态 |
| [material_log.go](../internal/service/material_log.go) | 物料变更日志的 diff 生成与中文描述 |
| [application.go](../internal/service/application.go) | 物料申请单的提交/审批/驳回/撤销 |
| [auth.go](../internal/service/auth.go) | 登录、签发与校验 token session、密码哈希 |
| [admin_master.go](../internal/service/admin_master.go) | 公司、主数据(分类/单位/编码规则)、往来单位、仓库四组服务 |
| [organization_access.go](../internal/service/organization_access.go) | 公司可访问范围与切换 |
| [websocket_ticket.go](../internal/service/websocket_ticket.go) | WebSocket 一次性票据的签发/消费 |
| [errors.go](../internal/service/errors.go) | 共享哨兵错误(库存不足、公司维度不可用等),供 handler 映射状态码 |
## repository/(纯 SQL)
| 文件 | 职责 |
| --- | --- |
| [material.go](../internal/repository/material.go) | 物料,含事务版新增(锁编码规则、判重)/更新/作废/恢复 |
| [inbound.go](../internal/repository/inbound.go) / [outbound.go](../internal/repository/outbound.go) | 出入库单及明细读写,共用 `orderQuerier` 接口 |
| [stock.go](../internal/repository/stock.go) | 库存余额、流水、预警规则,含 upsert |
| [master_data.go](../internal/repository/master_data.go) | 分类/单位/编码规则 |
| [material_log.go](../internal/repository/material_log.go) | 物料日志落库与查询 |
| [warehouse.go](../internal/repository/warehouse.go) | 仓库/库位,含 `Summary`(按公司取唯一仓库 + 库位) |
| [partner.go](../internal/repository/partner.go) | 往来单位 |
| [user.go](../internal/repository/user.go) | 用户与角色,含保护最后一个超管、建默认用户/表 |
| [user_organization.go](../internal/repository/user_organization.go) | 用户-公司关联的替换与批量加载 |
| [organization.go](../internal/repository/organization.go) / [organization_access.go](../internal/repository/organization_access.go) | 公司基础 CRUD;`ListAccessible` / `CanAccess` 的授权判定(每次查库,不依赖 JWT 里的角色快照) |
| [organization_audit.go](../internal/repository/organization_audit.go) | 公司相关操作的审计日志写入 |
| [application.go](../internal/repository/application.go) | 申请单及明细 |
| [update.go](../internal/repository/update.go) | `execExpectingRow`:UPDATE 后校验影响行数,避免"0 行也当成功" |
## model/(数据结构,无逻辑)
[model.go](../internal/model/model.go) 集中了大部分结构体(物料、出入库单与明细、库存与流水、用户、申请单,以及各类 Request/Response);后来又按业务域另拆出 `inventory.go`、`master_data.go`、`organization.go`、`partner.go`、`warehouse.go` 五个文件。
## testutil/
`fixtures.go`、`isolation.go`、`testdb.go` 是测试辅助包,不属于业务代码。