项目:nestjs-admin | 版本:v1.2 | 生成日期:2026-10-06 | 依据:源码分析
本文是文档集的收官之作,承担三件事:其一,把散落在 00-19 各篇中的领域术语收拢为一张自洽的术语表,每个术语给出"本项目语境下的准确含义 + 一手源码锚点",供新接手者建立统一词汇;其二,提供源码文件 ↔ 篇目的反向索引——在代码里读到任何文件时,能立刻查到"哪几篇文档详细讲过它";其三,按四类典型任务给出阅读路径(新增微服务、修 403 问题、上线检查、排查注册失败),每条路径列出"先读什么、再读什么、动手时查什么"的顺序与配套验证命令。本文自身不展开任何机制细节,一律以"见《0X-xxx》"的方式引用既有篇目——它更像文档集的目录卡与词汇对齐表,读本文的最佳时机是通读全文档集一遍之后:术语表用于校准理解,索引用于回查,路径用于排班接活。
微服务(Microservice):本项目中指 nestjs-microservice-app/ 下按 workspace 包拆分的独立进程——user(:40001)、system(:40010)、health(:3030)、gateway(:3040),每个进程独立构建、独立启动、独立注册。本项目微服务拆分的准则与边界见《01-系统架构》§2,拆分动机的决策考古见《16-决策记录ADR》ADR-001。
网关(Gateway):即 gateway 服务,前端唯一可见的 HTTP 入口(:3040,全局前缀 /api)。它做五类事:认证鉴权(JWT + CASL)、限流、协议转换(HTTP↔gRPC)、三级日志采集、异常映射。业务规则刻意不落在网关(薄网关/BFF 取向,ADR-011),内部结构见《01-系统架构》§4 与《07-模块详解》§1。
gRPC:网关与业务服务之间的内部通信协议(Unary 调用),基于 HTTP/2 与 protobuf 序列化。NestJS 经 @nestjs/microservices 的 Transport.GRPC 提供一等支持。传输层证据在 user/src/main.ts(服务端)与 gateway/src/consul/consul.service.ts(客户端),协议选型理由见 ADR-002,接口示例见《19-数据契约与示例集》附节。
proto / proto 契约:.proto 文件定义的接口契约,是网关与业务服务之间的唯一接口事实源,集中在 proto-pkg/proto/(user.proto 26 个业务 rpc、system.proto 31 个、health.proto)。改契约的固定动作是"改 proto → 重生成 → 两端实现",见《11-扩展开发指南》SOP-2。
proto-pkg:workspace 共享包 @toimc/proto-pkg,打包了 proto 契约、loadProto/promisifyServiceMethods/ConsulHttpClient/loadGrpcTls 四件工具与 HealthModule。它是所有服务共享的"类型宇宙",详细构成见《07-模块详解》§5,作为决策的考古见 ADR-008。
keepCase:loadProto(proto-pkg/src/utils/proto-utils.ts)对 @grpc/proto-loader 的加载选项,使 gRPC 运行时对象的键保持 proto 原名(如 UserRole)而 ts-proto 生成类型是 camelCase。这是 HANDOFF 陷阱 4 的根源,代码里两处活化石在 gateway/src/system/user-client.service.ts 与 authorization.service.ts:148-150。
promisifyServiceMethods:把 gRPC 客户端的全部 Observable 方法包装为 async 函数的工具(proto-pkg/src/utils/grpc-utils.ts),同时挂错误回调——回调是全系统"调用失败即重建客户端"自愈机制的触发点。配合《18-代码走读实录》§1.5 阅读效果最佳。
gRPC TLS:内网 gRPC 的单向 TLS 加密,由环境变量 GRPC_TLS=on 统一开关,证书是 proto-pkg/certs 随包分发的自签证书(生产卷挂覆盖)。必须三端一致(服务端、网关客户端、health 探测端),不一致的后果见 ADR-009 与《12-FAQ与故障排查》。
Consul / 注册中心:HashiCorp 的服务注册与发现组件,本项目以 dev agent 模式运行两个实例(:8500/:8501,第二个全套端口偏移)。注册侧证据 user/src/consul/consul-client.service.ts,三种运行形态见《14-配置与环境详解》§4。
服务发现(Service Discovery):网关把"服务名(如 nestjs-service)→ 可用地址:端口"的解析委托给 Consul 的过程。实现主体是 gateway/src/consul/consul.service.ts,含随机负载均衡、指数退避重试与多实例竞速,逐行走读见《18-代码走读实录》§1。
发现键 / 服务名(SERVICE_NAME):注册与发现共用的名字,同服务所有实例必须一致(user 默认 nestjs-service,system 为 nestjs-system)。与之相对的 SERVICE_ID 是实例唯一键,缺省 nestjs-user-${PORT},多实例时必须显式区分否则互相覆盖注册。
健康检查(Health Check):Consul 每 10 秒对注册实例发起的 HTTP 探测,指向 health 服务的聚合端点。与 gRPC 健康检查(Health.Check) 区分:后者是 gRPC 标准协议的存活应答(由 proto-pkg HealthModule 提供,恒返 SERVING),health 服务把两者翻译衔接。完整链路见《05-核心流程》流程四。
deregisterCriticalServiceAfter:Consul 注册体里的摘除阈值('60s')——健康检查连续失败的实例 60 秒后被自动注销。它解释了"服务注册成功又消失"现象的时序特征,相关事故注记见《05-核心流程》流程四与 ADR-010。
容灾竞速:retryGetServiceInfo 把发现查询并行 fan-out 到所有注册中心(mergeMap 并行 + take(1)),任一先返回即采用的机制。与串行 fallback 的区别就一个操作符,走读见《18-代码走读实录》§1.4,决策背景见 ADR-003。
自愈(Self-healing):gRPC 调用失败触发 updateGrpcClient 重新发现、重建客户端并向注册表中所有同服务条目广播的机制。它是本架构里"实例漂移对业务无感"的关键,设计动机(落选条目 bug)见《18-代码走读实录》§1.5。
health 服务::3030 的纯基础设施服务,职责是把 SERVICE_HEALTHCHECK_ENDPOINTS 环境变量描述的若干 gRPC 端点翻译为 HTTP 200/500 供 Consul 探测。它的可用性等于全系统可发现性(health 挂 → 全部 gRPC 服务 60s 后被摘除),见 ADR-010 与《01-系统架构》§7。
双 token:access token(2h,API 访问凭证)+ refresh token(7d,仅用于换发 access,payload 带 type:'refresh')。两枚都在签发时带 jwtid: randomUUID() 防同秒撞签。签发逻辑 gateway/src/auth/auth.service.ts,闭环时序见《05-核心流程》流程一,决策见 ADR-005。
内存会话表(SessionService):网关进程内的三张 Map(access_token→记录、sessionId→token、refresh_token→sessionId),承载在线用户列表、强退、refresh 换发与陈旧清扫。单实例部署的既定方案,Redis 化路径见 session.service.ts 头注释与《13-技术债务与演进建议》路线图 P2。
单活跃会话:refresh 换发新 access 后旧 access 立即 401 的语义(会话以 token 明文为键,rotateAccessToken 换键即旧键消失)。曾被当 bug 报告,陷阱 28 确认为特性。
强退(forceLogout):管理员按 sessionId 删除会话的操作,access 与 refresh 同时失效——被踢用户的下一个请求即 401 且无法续期。端点 DELETE /api/monitor/online-users/:sessionId,流程见《05-核心流程》流程五。
无感刷新:前端在 access 过期时自动调 refresh 换发的机制,含单飞标志与并发请求队列(vue-admin/src/utils/http/index.ts),前端实现走读见《18-代码走读实录》§3.1。
RBAC(基于角色的访问控制):用户经 user_roles 绑角色、角色经授权表绑定资源(菜单/权限码/策略)的经典模型。本项目是"RBAC 骨架 + 权限码数据驱动"的混合体,模型全景见《08-安全与权限设计》§2。
权限码(Permission Code):<域>:<资源>:<动作> 格式的字符串(如 system:user:reset-pwd),本体是 system_db menus 表中 type=2"按钮"记录的 permission 字段,经 role_menus 授权给角色。"权限码即菜单记录"意味着加权限是纯数据操作,决策见 ADR-007,完整种子清单在 system/prisma/seed.sql(21 个按钮码,另有 8 个页面级 list 码)。
按钮码:权限码在前端口径下的别名——特指 type=2 菜单记录的 permission,经 GET /api/system/my-menus 下发、SET_PERMS 进 user store、hasPerms/v-perms 消费。前端消费端走读见《18-代码走读实录》§3.3。
CASL / Ability:@casl/ability 库的授权判定引擎。网关把两路规则(user 库 Policy 表 + system 库权限码)编译为一个 Ability<[string,string]> 实例并按用户缓存 60 秒。双源能力即指这两路规则的合并,fail-closed 指任一路失败时规则清空、全站 403 的降级语义(宁拒不放行)。实现 gateway/src/auth/authorization.service.ts,决策见 ADR-006。
@CheckPolicies / PoliciesGuard:声明式鉴权对——路由上 @CheckPolicies((ability) => ability.can('system:user:list','perm')) 写入元数据,守卫读取并执行判定,失败 403"无权限执行该操作"。源码 gateway/src/auth/policies/policies.guard.ts。
Ability 缓存 60 秒窗口:权限变更到生效的最长延迟(CACHE_TTL_MS = 60_000)。与前端"下次拉 my-menus 才更新按钮"叠加,构成"改权限不是立即生效"的双段延迟,急用生效法见《11-扩展开发指南》SOP-5。
Database-per-service(每服务一库):user_db 与 system_db 两个独立 PostgreSQL 库,互不 join,跨库逻辑上收到网关。两库实体与迁移史见《04-数据模型》,决策见 ADR-001。
Prisma 驱动适配器(PrismaPg):Prisma 7 的新连接架构——连接串不写进 schema,CLI 走 prisma.config.ts、运行时走 database.service.ts 的 new PrismaPg({connectionString})。两处必须指向同一库(陷阱 19 的连错库事故)。详见《04-数据模型》§1 与《17-依赖全景》§2.3。
seed(种子数据):user/prisma/seed.sql 与 system/prisma/seed.sql 两个可重放 SQL 文件,灌入默认角色、菜单树、权限码与授权。漏跑 seed = 菜单/权限 403(陷阱 31 真实事故)。显式 ID 插入后必须 setval 推进序列。
三级日志:oper_logs(操作日志,中间件对写请求自动采集)、login_logs(登录日志,signin/signup 路径规则采集)、system_logs(系统日志,异常过滤器对 5xx 落库)。三者全部是"尽力而为的旁路写入",业务代码零日志语句,决策见 ADR-012,字段定义见《04-数据模型》§3.3。
traceId:网关中间件生成的请求唯一标识(randomUUID),回写响应头 X-Request-Id,并出现在操作日志与系统日志里,是跨日志取证的关联键。排障时用它串起网关请求行、oper_logs、system_logs 三处现场(《12-FAQ与故障排查》§1)。
fail-closed:依赖服务不可用时"能力清空、全部拒绝"的降级取向(相对的 fail-open 是放行)。本项目的权限体系与配置缺失处理(JWT_SECRET 缺失拒绝启动)都取 fail-closed,含义辨析见《08-安全与权限设计》§7。
旁路采集(fire-and-forget):日志写入整体 try/catch、异步不等待、失败仅 warn 的纪律。它保证"日志通道故障不影响业务响应",代价是日志丢失无感知,纪律的由来见陷阱 16。
dev agent:Consul 的开发模式(consul agent -dev),内存运行、数据不持久、重启即空——因此每次起栈服务都会重新注册。生产形态对照见《14-配置与环境详解》§4。
信封适配:前端 api/*.ts 适配层把网关的裸 JSON({users,total})翻译为 pure-admin 组件期望的信封({code,data:{list,total,...}})的动作。它是"后端形状先 curl 确认再写适配器"纪律(陷阱 23)的执行现场。
SPA 回退:history 路由模式下,nginx 对未知路径统一返回 index.html 的配置(try_files $uri $uri/ /index.html),保证深链接与刷新不 404。生产配置在 admin-vue-deploy/nginx-admin.conf。
fail 降级与可选依赖:MinIO 缺凭据时上传功能降级不崩(upload.service.ts onModuleInit 仅 warn)、/auth/me 在 user 服务不可用时角色降级空数组——"可选依赖不阻断启动"是全项目的可用性取向,网关设计哲学的完整表述见《01-系统架构》§4。
用法:在 IDE 里读到下表左侧文件时,按右侧篇目深读。仅列"有专文讲解"的核心文件,其余文件以就近目录归属其所在服务的篇目。
| 源码文件 | 主要讲解篇目 |
|---|---|
nestjs-microservice-app/dev-start.sh | 《14-配置与环境详解》§1 逐段解析;《06-部署运行》§2 命令级 |
nestjs-microservice-app/Dockerfile、Dockerfile.service | 《14-配置与环境详解》§3 差异表;《06-部署运行》§4 |
nestjs-microservice-app/docker-compose.full.yml | 《14-配置与环境详解》§2;《13-技术债务》§1.8(未实测状态) |
nestjs-microservice-app/.env.example、dev-secrets.env | 《14-配置与环境详解》§5 全清单;《08-安全与权限设计》§5 secrets |
nestjs-microservice-app/smoke_fullchain.js | 《06-部署运行》§2.4;《00-项目总览》§5.4 |
nestjs-microservice-app/HANDOFF.md | 全篇引用其陷阱清单(01/05/08/12/13 等),本文不重复 |
gateway/src/main.ts | 《07-模块详解》§1.2 启动时序走读;《08-安全与权限设计》§3/§4 |
gateway/src/app.module.ts | 《01-系统架构》§3.2;《07-模块详解》§1.1 装配地图 |
gateway/src/consul/consul.service.ts | 《18-代码走读实录》§1 全文走读;《01-系统架构》§3.2 |
gateway/src/consul/consul-core.module.ts | 《07-模块详解》§1.3 工厂 provider 机制 |
gateway/src/consul/consul.controller.ts | 《07-模块详解》§1.1(双份健康能力注记);《15-接口全量参考》#63 |
gateway/src/auth/auth.service.ts | 《08-安全与权限设计》§1.1;《18-代码走读实录》引用;ADR-005 |
gateway/src/auth/auth.controller.ts | 《03-接口设计》§3.1;《15-接口全量参考》§2 |
gateway/src/auth/authorization.service.ts | 《08-安全与权限设计》§2.2;ADR-006;《18-代码走读实录》§2.2 |
gateway/src/auth/strategies/jwt.strategy.ts | 《08-安全与权限设计》§1.2;《05-核心流程》流程一/五 |
gateway/src/auth/policies/policies.guard.ts | 《08-安全与权限设计》§2.3;ADR-006/011 |
gateway/src/common/session/session.service.ts | 《08-安全与权限设计》§1.3;《05-核心流程》流程五;ADR-005 |
gateway/src/common/middleware/request-logging.middleware.ts | 《18-代码走读实录》引用;《01-系统架构》§4;ADR-012 |
gateway/src/common/filters/all-exceptions.filter.ts | 《03-接口设计》§5 错误映射表;ADR-012;《15-接口全量参考》§6 |
gateway/src/common/upload/upload.service.ts、uploads.controller.ts | 《04-数据模型》§1;《13-技术债务》§1.4(孤儿对象);《15-接口全量参考》#62 |
gateway/src/system/system-client.service.ts | 《18-代码走读实录》§2.2;《07-模块详解》§1.3 消费者模式 |
gateway/src/system/user-client.service.ts | 《18-代码走读实录》§2.2;《07-模块详解》§1.3 |
gateway/src/system/user.controller.ts | 《18-代码走读实录》§2.1;《07-模块详解》§1.4 兜底规则;《15-接口全量参考》§3.1 |
gateway/src/system/monitor.controller.ts | 《15-接口全量参考》§4.1;《05-核心流程》流程五 |
gateway/src/system/dashboard.controller.ts | 《19-数据契约与示例集》示例八;《00-项目总览》§2 |
user/src/main.ts | 《07-模块详解》§2.1;ADR-009(TLS 分支) |
user/src/app.controller.ts | 《07-模块详解》§2.2 RPC 清单;《18-代码走读实录》§2.3 事务走读 |
user/src/consul/consul-client.service.ts | 《01-系统架构》§3.1 注册侧;《14-配置与环境详解》§4 注册体字段 |
user/src/database/database.service.ts | 《04-数据模型》§1;陷阱 19 注记 |
user/prisma/schema.prisma、migrations/、seed.sql | 《04-数据模型》§2/§6/§7 |
system/src/app.controller.ts | 《07-模块详解》§3 分组表;listMenus 祖先链与 getPermissionCodes 见《12-FAQ与故障排查》§4 |
system/prisma/seed.sql | 《04-数据模型》§2.4;《08-安全与权限设计》§2.1;《12-FAQ与故障排查》§4 |
health/src/consul/consul.controller.ts、health/src/main.ts | 《07-模块详解》§4;《05-核心流程》流程四;ADR-010;《19-数据契约与示例集》示例十 |
proto-pkg/proto/user.proto、system.proto、health.proto | 《19-数据契约与示例集》附节;《15-接口全量参考》§5;《03-接口设计》§7 |
proto-pkg/src/utils/proto-utils.ts、grpc-utils.ts、consul-http.ts | 《07-模块详解》§5;ADR-004/008;《18-代码走读实录》§1 |
proto-pkg/src/nestjs-health/ | 《07-模块详解》§2.3 HealthModule 注记;ADR-008 |
template/ | 《07-模块详解》§6;《11-扩展开发指南》SOP-1;《17-依赖全景》红区 |
vue-admin/vite.config.ts | 《14-配置与环境详解》§6 走读;《06-部署运行》§2.3 代理兜底 |
vue-admin/src/utils/http/index.ts | 《18-代码走读实录》§3.1/3.2;《05-核心流程》流程一 |
vue-admin/src/utils/auth.ts | 《18-代码走读实录》§3.3;《02-页面设计》§3.1 双存储 |
vue-admin/src/api/routes.ts | 《07-模块详解》§7.2;《02-页面设计》§2;ADR-007 |
vue-admin/src/api/system.ts、api/user.ts | 《07-模块详解》§7.4;《15-接口全量参考》§6 函数清单 |
vue-admin/src/router/index.ts、router/utils.ts | 《02-页面设计》§2;《07-模块详解》§7.2 |
vue-admin/src/directives/perms/ | 《18-代码走读实录》§3.3;《11-扩展开发指南》SOP-5 |
vue-admin/src/store/modules/user.ts、permission.ts | 《07-模块详解》§7.3 |
vue-admin/src/views/**(业务页面) | 《02-页面设计》§3 逐页解析 |
admin-vue-deploy/(nginx-admin.conf、compose、sync.sh) | 《06-部署运行》§4-§5;《14-配置与环境详解》§2 生产对照表 |
先读《00-项目总览》§4 目录导览与《01-系统架构》§8 的推演段建立拓扑观,然后以《11-扩展开发指南》SOP-1 为操作主轴(六步:template 复制 → proto 定义 → 网关注册 → 客户端持有器 → 启动登记 → 验证)。动手过程中三份参考轮流查:《16-决策记录ADR》ADR-003/008/010 解释每个注册步骤背后的决策(防止把"必须两个 ConsulModule 都配"当成仪式);《14-配置与环境详解》§4/§5 给出 SERVICE_NAME/SERVICE_ID/CHECK/SERVICE_HEALTHCHECK_ENDPOINTS 的成对配置语义(新环境配置错误率最高的就是这对 CHECK-ENDPOINTS);《17-依赖全景》红区提醒先把 template 的 NestJS 10 版本线对齐再复制。验证闭环:bash dev-start.sh 看到 passing: 新服务≥1、curl health 端点 200、网关临时控制器调一次 RPC 走通。最常见的失败模式("注册成功又消失")直接翻《12-FAQ与故障排查》§3 决策树一。
从《12-FAQ与故障排查》§4 的决策树二开始(带 Bearer 调 my-menus 分流数据链/前端消费侧),理解"403 九成在数据链"的先验。机制背景按需补:《08-安全与权限设计》§2 讲清守卫判定的三步(req.user → getAbility → ability.can);《16-决策记录ADR》ADR-006/007 解释 fail-closed 与"权限码即菜单记录"两个决策(为什么 seed 缺行 = 全站 403、为什么能力为空是防线在工作);《19-数据契约与示例集》示例六给出 my-menus 的响应形状(type=2 且 permission 非空即按钮码全集)。修复动作按根因落位:缺 seed 跑 seed.sql、缺授权补 role_menus、菜单停用查 status、缓存窗口等 60 秒或重启网关。若 403 伴随"测试账号不可以修改密码"类文案则属业务保护而非权限问题(user/src/app.controller.ts 双写死),见《12-FAQ与故障排查》§5 Q4。
以《06-部署运行》§4 部署链路为主线,逐项核对:《14-配置与环境详解》§2 的生产 compose 对照表(镜像单化、external 网络、600 权限 .env、证书卷挂)与 §5 环境变量全清单(重点 JWT_SECRET 强随机、GRPC_TLS 三端一致、HOST 写服务名、CHECK 与 ENDPOINTS 成对);《08-安全与权限设计》§5.3 密钥与演示账号清单(prodadmin 是否已改密 ⚠️ 待确认、env.production.template 的凭据轮换——13 篇 P0 项);《01-系统架构》§7 的六条架构边界(确认单实例会话、health 单点、自签证书的接受度);《13-技术债务与演进建议》§2 的待确认汇总表过一遍。上线冒烟按《06-部署运行》§2.4 的顺序:/api 探针 → health 聚合 → smoke_fullchain.js ALL GREEN → 前端新标签页登录复验(HANDOFF 方法论)。公网链路(frp + VPS 反代)的缓存与 XFF 细节见《06-部署运行》§4.3,限流分桶验证见《12-FAQ与故障排查》§2 的限流行。
按《12-FAQ与故障排查》§3 决策树一的顺序取证:先 curl /v1/agent/services 判断注册侧还是发现侧。注册侧问题配读《14-配置与环境详解》§4(CONSUL_HOST/PORT、SERVICE_NAME、注册体字段)与 ADR-003/004(注册机制与自研客户端的行为边界,含 10 秒请求超时与静默失败——注册失败仅记 error 不重试);发现侧问题配读《18-代码走读实录》§1(竞速、no passing instance found 的翻译链)与《01-系统架构》§3.2(发现与客户端构建流程五步)。健康检查链路的排查(404 key 不匹配 / 500 探测失败)按《05-核心流程》流程四的三分支走,GRPC_TLS 双端一致性的经典事故(health 探测端漏开 → 60 秒被注销)在 ADR-009 与《12-FAQ与故障排查》§2 各有一条记录。本机第二个 Consul agent 的端口偏移清单在《11-扩展开发指南》SOP-4(漏偏移撞 8300,陷阱 12)。
半天内建立可运行环境的顺序:《06-部署运行》§1-§2(前置条件、建库迁移 seed 三步不可颠倒)→ 《00-项目总览》§5 快速上手 → 首次起栈失败查《12-FAQ与故障排查》§2 高频报错表(换机后首启九成是迁移漂移,陷阱 31)→ 跑通后用《19-数据契约与示例集》示例一/三/六做三个手工验证(登录、用户列表、动态菜单),对照《02-页面设计》§3 认一遍页面。至此接手者具备"起栈、登录、看数据"的最小闭环,再按需进入前四条任务路径。
00-20 共 21 篇的定位分层:入门层(00 总览、02 页面、05 流程)建立全貌与体感;设计层(01 架构、03 接口、04 数据模型、07 模块、08 安全)是日常开发的主要查询对象;操作层(06 部署、11 扩展、14 配置、15 接口参考、19 契约示例)面向"动手时";治理层(09 测试、10 性能、12 FAQ、13 技术债、16 ADR)面向维护决策;索引层(本篇)串起全部。两个使用纪律:其一,遇到与其他篇目表述冲突时,按"源码 > 契约文件 > 篇目"的优先级裁决,并优先怀疑篇目过期而非源码错误(文档集 v1.0-v1.2 与代码同日生成,漂移风险主要在后续演进中累积);其二,本篇 §1 术语表在评审、交接、写新文档时应作为用词规范引用——"按钮码"与"权限码"、"发现键"与"服务名"这类同义异名在历史文档中偶有混用,新文档统一按本篇口径书写。文档集的下一轮更新建议随《13-技术债务》路线图的 P0/P1 完成滚动推进:每清一笔债务同步修订对应篇目,每新增一个"已知取舍"就补进 ADR 篇——让这套文档像它服务的代码一样,保持可审计的演进史。