backend-index
给本地后端项目建「模块 ↔ 目录/依赖/数据表」索引(.fe-index/):改模块前查依赖与被依赖,改表前查影响模块,接任务先看模块地图。触发:"后端索引"、"后端模块地图"、"改这个模块影响谁"、"改这张表影响哪些模块"。
SKILL.mdskills/backend-index/SKILL.md
GitHub后端模块索引(backend-index)
概述
目的:把「后端模块」的位置、边界、依赖与被依赖、数据面,从"每次 grep 试探 + 逐条读文件收敛"变成"查表直达"。改某模块前知道要连带看谁;改某张表前知道要通知哪些模块;接后端任务先拿到模块地图。
功能:
- 扫描本地后端源码,提取模块(NestJS
@Module/ Django app):目录、定义处、挂载前缀、接口数、controller 文件 - 双向依赖:
模块 → 依赖(imports 的兄弟模块)+模块 → 被依赖(穷举反查,防漏) - 表双向:
模块 → 数据表(forFeature /@InjectRepository/models.Model/ 跨 app import)+表 → 模块(反向,改表找谁) - 非 HTTP 入口:MQ 消费者(
@Processor)、CQRS Handler、定时任务;模块级守卫 - 事件/命令耦合边:
bus.execute(new X)→@CommandHandler(X)所在模块、@InjectQueue('q')→@Processor('q')所在模块——这类耦合不经imports(靠 CQRS 总线 / 队列解耦),但"改一个 Command 或消息结构"照样影响对方。只统计模块自有文件,每条边都可用grep 模块目录复验 - 专家资产探测:
.module-experts/里有哪些专家包、各自关联哪个模块(索引成为专家团的入口) - 一键重建:
--emit-tree一条命令落盘整棵树;新鲜度闸门--check比对 commit - 诚实降级:展不开的常量数组、找不到
@Entity的 token、默认命名的表名 → 全部进「待确认」,不猜
使用场景:
- 要改 / 删某张数据表 → 先查哪些模块引用了它(防漏通知、防漏回归)
- 要改某个模块的配置 / 依赖 / 对外面 → 先看它依赖谁、谁依赖它
- 新会话接手后端项目 → 一份模块地图建立认知(含"哪些模块有专家资产可深挖")
- 用户说"给后端建索引"、"后端模块地图"、"改这个模块影响谁"、"改这张表影响哪些模块"时
- 之前建过索引的项目再次被问起——先查
.fe-index/INDEX.md进消费模式,而不是重跑扫描
定位
与邻接 skill 的分工(防重叠)
| 邻接能力 | 它做什么 | 本 skill 做什么 |
|---|---|---|
expert-team(.module-experts/) |
按模块深挖:契约层(怎么用 / 接口契约 / 数据流向 C4 / 关键决策)+ 实现层 Wiki | 只给位置与依赖骨架,并指向专家资产。接口清单与契约一律不重复建设(专家 Step 8.3 已写 ki tags=api) |
ki-search 接口信息 |
可检索的接口原子(按子功能聚合) | 索引给"哪个模块",ki 给"接口怎么用" |
strong-relation |
人工/AI 沉淀的模块间强耦合关系 | 机械提取的模块依赖边(覆盖全量、零维护);两者互补,冲突时以代码为准 |
frontend-index |
前端「页面 ↔ 接口」索引(.fe-index/{前端slug}/) |
后端「模块 ↔ 表 / 依赖」索引(.fe-index/{后端slug}/);跨端 join 见「被其它 skill 集成」 |
GitNexus MCP(impact / context) |
符号级影响面(需 CLI + 已建索引) | 模块级视角、零依赖、产物人可读、不依赖 MCP 可用性 |
| grep / LSP | 随机访问(搜到什么算什么) | 穷举反查 + 落盘复用(被依赖 / 表反查 / 跨会话一致) |
一句话边界:本 skill 回答「去哪看、动了谁」;专家团回答「是什么、怎么用」;grep 回答「具体在哪一行」。
与 frontend-index 的关系(同族)
两个 skill 实现独立、产物同根(.fe-index/),口径一致:双模式 / 新鲜度闸门 / 退出码族 / [待确认] 不猜 / 脚本提取骨架 + AI 补语义。可以各自单独安装使用。
核心原则
- 索引模块,不是索引接口:接口清单交给专家团与 ki(
tags=api)——重复建设必然漂移。本索引只在模块卡里记「挂载前缀 + 接口数 + controller 文件」,不逐接口建表。 - 脚本管骨架,AI 管语义:穷举机械活(模块全集 / 前缀合成 / 依赖反查 / 表反查 / 一键重建)交给脚本;语义判断(模块中文职责、专家关联确认、分组)交给 AI。不让 AI 重复做穷举提取(会漏,且每次重建都贵)。
- 反查必须穷举:
被依赖与表 → 模块是"扫完全部才知道"的反查——漏一条边就是一份看起来完整但会误导的报告。这类活只能机械提取。 - 失效要显式:
meta.json记 commit,读表前--check;范围外无变化不误报。 - 不猜:展不开的数组、找不到声明的 token、默认命名的表 → 进「待确认」,宁可缺,不给错。
- 双模式分离:消费模式(查表 → 读码,不跑脚本)与建造模式(采集建库)严格分开。
- 可见性由集成方负责:
.fe-index/是隐藏目录,本 skill 不擅自往用户的 AGENTS.md / 规则里写钩子。
产物结构
落点一律在【项目根】(
git rev-parse --show-toplevel;非 git 仓库则逐级向上找.git):即{项目根}/.fe-index/。 monorepo 里--root可以给应用子目录,但索引属于整个项目——--emit-tree不带值就落这里,带相对路径也以项目根为基准(不看 cwd)。
{项目根}/.fe-index/
├── INDEX.md # 必存在:全项目登记表(一行一应用)—— 后续会话的发现入口
└── {app-slug}/
├── index.md # 必存在:模块地图 + 依赖图 + 表反查摘要 + 专家资产 + 待确认
├── modules/{模块slug}.md # 每模块一张卡(占位/依赖/表/事件耦合/入口/守卫/专家指针/归属文件)
├── tables.md # 必存在:表 → 模块(反向索引)
└── meta.json # 必存在:机器可读元信息(commit / 范围 / 统计)—— `--check` 依据
| 类别 | 文件 | git 建议 |
|---|---|---|
| 人工维护(发现入口) | INDEX.md |
入库(一行一应用,冲突少) |
| 派生产物(脚本生成) | meta.json / index.md / modules/ / tables.md |
默认不入库(会随代码过期) |
INDEX.md 是这个机制的生命线:隐藏目录不会被自动发现,每次建造都必须同步更新它。
INDEX.md 模板(与 frontend-index 共用同一份文件,列结构必须一致)
# 索引登记表(.fe-index/)
> 涉及下列应用的问题,先查对应条目所在的分区/映射表,再看代码
| 应用 | 类型 | slug | 根目录 | 规模 | commit | 生成日期 |
|------|------|------|--------|------|--------|----------|
| cloud-web | frontend | cloud-web | `/root/xpert` | 页面 121 · 接口 66 | `889e265c` | 2026-10-13 |
| server-ai | backend | server-ai | `/root/xpert` | 模块 125 · 表 122 | `889e265c` | 2026-10-13 |
更新纪律:只增改本应用那一行,不动其他行;同一仓库前后端各占一行(slug 不同,不合并)。
「根目录」列口径(消费方按此解析):绝对路径直用;相对路径以 .fe-index/ 的上一级为基准(便于跨机器与仓库整体搬迁)。查找登记表时若 {root} 下没有,逐级向上找 ≤3 层。
meta.json 模板(--check 依赖,必写)
{
"slug": "server-ai",
"kind": "backend",
"root": "/root/xpert",
"scope": ["packages/**", "apps/**"],
"framework": "nestjs",
"commit": "889e265cdfdec200e5a6446f4463fe43505f84ac",
"generated": "2026-10-13",
"stats": { "modules": 125, "tables": 122, "deps_edges": 428, "routes": 806 },
"scanner": "scan_backend.py v2.0.0"
}
--emit-tree会自动写 meta.json(含 commit),无需手写;手工建库时(见阶段 2 的小项目分支)必须自己填。
index.md 模板
# {slug} 后端模块索引
> 根目录:`…` · 框架:**nestjs** · 全局前缀:`/api`
> 生成:2026-10-13 · commit:`889e265cdf` · 范围:`packages/**, apps/**`
> 新鲜度校验:`python3 scan_backend.py --root <根> --check --index <本目录>`
**这个索引回答什么**:改某模块要连带看谁、改某张表要通知哪些模块、模块的数据面与非 HTTP 入口、模块的代码在哪。
**接口级契约**见 `.module-experts/` 专家资产与 ki 接口信息(`tags=api`)——本索引不重复建设。
## 1. 模块地图(N)
| 模块 | 目录 | 挂载前缀 | 接口 | 表 | 依赖 | 被依赖 | 非 HTTP 入口 | 专家资产 |
…(每模块一行,链接到 modules/{slug}.md)
## 2. 模块依赖图(M 条边) ← mermaid graph LR(边 >120 时降级为文本列表)
## 3. 表 → 模块(反向,K 张表) ← 摘要,完整见 tables.md
## 4. 专家资产(N 个) ← 专家名 / 路径 / 关联模块(未关联显式标注)
## 5. 待确认(N) ← 类型 / 位置 / 内容 / 原因
modules/{模块slug}.md 模板
# {模块名}(`{slug}`)
- 位置:`{目录}/` · 归属文件 N 个 · 约 M 行
- 定义:`{module.ts}:{line}`(nestjs) | 挂载前缀:`/api/x` · 接口 N 个 | 置信度:🟢
## 控制器(模块对外面) ← 文件 / 前缀 / 接口数 / 行号
## 依赖关系 ← 依赖(改它要连带看)/ 被依赖(动它会影响)/ 依赖的库
## 事件/命令耦合 ← 我发出(→ 目标模块 + 命令/队列名)/ 我接收(← 来源模块 + 命令名)
## 数据表(N) ← 表 / 实体 / 引用次数 / 来源(定义 or import)/ 证据 file:line
## 非 HTTP 入口 ← MQ / CQRS / 定时任务
## 守卫/权限
## 专家资产(深挖读这些)
## 归属文件(N)
工作流
第一步先判模式(必做):读 .fe-index/INDEX.md(不存在则视为首次建库;被集成时落点以调用方指定为准)。
消费模式(查表 → 读码)
- 读
.fe-index/INDEX.md→ 找到对应应用与 slug - 新鲜度闸门(必做):
python3 <skill>/scripts/scan_backend.py --root <根> --check --index .fe-index/{slug}- 退出码 0:新鲜 → 继续
- 退出码 6:过期 → 先问用户是否重建(重建 = 重跑
--emit-tree,秒级) - 退出码 7:缺
meta.json→ 按"无新鲜度信息"处理,告知用户 - 退出码 3:git 不可用 / 记录的 commit 不可达 → 按"无法判定"处理,建议重建
- 按问题查表:
- "改这张表要注意什么" →
tables.md找到表 → 拿到模块清单(定义方 vs 使用方)→ 读对应modules/*.md - "改这个模块影响谁" →
modules/{slug}.md的被依赖 → 逐个看 - "改一个 Command / 队列消息影响谁" →
modules/{slug}.md的事件/命令耦合段(我发出 → 目标模块;我接收 ← 来源模块) - "这个接口/功能在哪" →
index.md模块地图按前缀定位模块 → 进模块目录看 controller - "这个模块怎么用 / 契约是什么" → 交给专家资产(模块卡里有指针);没有专家则 ki
tags=api或现场读码
- "改这张表要注意什么" →
- 命中即止:不再全库 grep;只有模块定位后需要行级细节时才在模块目录内查
建造模式总览
阶段 0 准入与模式判定 → 阶段 1 约定探测(含"值不值得建/要不要跑脚本")→ 阶段 2 提取(脚本 --emit-tree)
→ 阶段 3 语义补充(AI,可选但推荐)→ 阶段 4 登记(INDEX.md)→ 阶段 5 交付与使用协议
阶段 0:准入判断(AI 自主)
| 信号 | 处置 |
|---|---|
目标应用已在 INDEX.md 在册 |
➡️ 转消费模式(用户要求重建除外) |
| 后端模块 ≤10 个且只要"模块在哪",不需要"谁依赖我 / 改表影响谁" | ➡️ 小项目分支:AI 直接读代码建索引,不跑脚本(仍需写 meta.json 与 INDEX.md;不承诺 --check) |
| 需要反向穷举(被依赖 / 表 → 模块)或模块数 >10 或要跨会话复用 | ✅ 进建造模式(跑脚本) |
| 代码不在本地 / 无源码 | ❌ 退出(本 skill 只索引本地代码) |
阶段 1:约定探测(唯一的用户确认点)
python3 <skill>/scripts/scan_backend.py --root <根> --dump-config
输出:框架(nestjs / django)、全局前缀、src_dirs、模块声明数、建议 include。
- 有
{项目根}/.fe-index/config.json(集成方或此前建库留下)→ 脚本自动读取并应用(--config可指定路径;只认kind=backend,--app/--slug选应用)→ 重建零猜测;文件里只有他端条目(如只声明了前端)时说明一行后忽略,不拦路 - 与用户确认:扫描范围(哪个应用、哪些包、slug 名)
- 框架识别失败(退出码 2)→ 用
--framework显式指定,或收窄--include - 探测结果建议固化为声明文件(
--dump-config会给出suggested_config):与前端共用同一份config.json,各自按kind取用自己的条目
阶段 2:脚本提取
python3 <skill>/scripts/scan_backend.py --root <根> --framework nestjs \
--include 'packages/**' --include 'apps/**' --slug server-ai \
--emit-tree
--emit-tree 不带值 → 自动落 {项目根}/.fe-index/server-ai/(推荐用法)。要自定义位置时才给它一个值(绝对路径直用;相对路径以项目根为基准)。
一步完成:模块全集 / 前缀 / 依赖图(含被依赖)/ 表双向 / 非 HTTP 入口 / 专家探测 / 待确认 / meta.json。
退出码处置:
| 码 | 含义 | 处置 |
|---|---|---|
| 0 | 成功 | 继续 |
| 2 | 未识别框架 | --framework 显式指定 / 收窄 --include |
| 3 | 根目录不存在或 git 失败 | 修正参数 |
| 4 | 识别到框架但零模块 | 检查 --include 是否覆盖后端源码 |
| 5 | 入参非法 | 修正参数 |
| 6 | --check 判定过期(范围文件有变化) |
先问用户是否重建(--emit-tree 覆盖落盘) |
| 7 | --check 缺 meta.json 或无 commit |
按"无新鲜度信息"处理,建议重建 |
成本:实测 3183 个 TS 文件 0.5 秒(NestJS)/ 5530 个 PY 文件 1.3 秒(Django)。重建近乎零成本——这是"索引不会腐烂"的前提。
阶段 3:语义补充(AI,可选但推荐)
脚本出的是机械骨架;下面这些 AI 直接读代码补,更准:
- 模块中文职责:给核心模块补一句话(写进模块卡顶部)。只补"改代码前需要知道的",不写百科。
- 专家关联确认:脚本按名字机械匹配,可能漏(专家用中文业务名)。逐个核对
未关联的专家,人工指到模块卡里。 - 待确认处理:读
index.md第 5 节,对影响判断的项(如展不开的数组、缺@Entity的关键 token)回源码确认,确认结果写进模块卡或meta.json的 notes。 - 分组(可选):模块 >40 个时,按业务域在
index.md里给模块地图加分组小标题(不改modules/目录结构)。
成本闸门:阶段 3 读文件 ≤15 个(骨架已由脚本给出,只读"需要判断"的)。
阶段 4:登记(INDEX.md)
- 脚本没写
INDEX.md(它是跨应用登记表):新增或更新该应用那一行(应用 / 类型 backend / 根目录 / 范围 / 规模 / commit / 日期) - 若同项目已有前端索引:保持两个 slug 各自一行,不要合并
阶段 5:交付
- 一句话总结:模块数、表数、依赖边数、待确认数、专家资产覆盖情况
- 给出使用协议(消费模式三问:改表去哪查 / 改模块去哪查 / 接口契约去哪查)
- 可选提醒:在
AGENTS.md里加一句"改后端模块或数据表前,先查.fe-index/INDEX.md"(加不加由用户决定,本 skill 不代劳)
反模式
- ❌ 把接口清单再抄一遍:专家团/ki 已有(
tags=api)——重复建设必然漂移,且接口级数据天然过期快 - ❌ 让 AI 全量手工建库:模块数 >10 或需要反查时会漏边,且每次重建成本高到不会重建 → 索引腐烂
- ❌ 不写 meta.json 就交付:没有 commit 就无法判断新鲜度,索引会静默过期
- ❌ 跳过
--check直接信表:代码映射失效是静默的(表还能查,结果是错的) - ❌ 在建造模式里逐模块读代码(脚本已给骨架):除非属于阶段 3 的"需要判断"清单
- ❌ 把「未关联」的专家当无关:专家名多为中文业务名,与代码标识无字面重叠 → 需人工指认
- ❌ 拿默认命名的表名当真:Django/TypeORM 默认命名在「待确认」里,向用户确认后才写入结论
行为边界(明确不承诺)
- ❌ 运行时行为:动态模块(
forRootAsync里拼出来的)、反射注册的 provider、@Controller路径运行时改写 - ❌ 跨服务:RPC / 微服务另一端的模块(只到本仓声明)
- ❌ 接口级清单与契约(归专家团 / ki)、精确到
file:line的调用链(归 GitNexus / LSP / grep) - ❌ 非 NestJS / Django 框架的模块体系(可扩展,见
reference.md的规则表) - ⚠️ monorepo 需
--include限定应用范围;前后端同仓时前端文件会被自动排除(同名类污染,已实测) - ⚠️ 表名若为框架默认命名(Django
{app}_{模型}/ TypeORM 类名推断)→ 标 🟡 进「待确认」 - ⚠️ 依赖边分两类:
imports声明(模块间依赖)与事件/命令耦合(bus.execute(new X)/@InjectQueue配对,只取模块自有文件)。仍不入图:字符串主题的事件(emit('x'))、跨进程 MQ 主题约定、共享配置 / 环境变量——需要时按reference.md的抽样核对方法局部 grep 补齐 - ⚠️ 同仓多框架(NestJS + Django 并存)时
--framework一次只扫一侧:脚本会显式告警,另一侧需单独建一个 slug
被其它 skill 集成(调用契约 · SSOT)
规则只在本节维护,调用方引用本 skill,不复制规则。
| 集成方 | 建议用法 | 状态 |
|---|---|---|
index-lookup(统一查询入口) |
消费方(code-review / debug / product-manager / expert-team / code-survey …)先调它按代码路径判定该查前端还是后端索引(读同一张 .fe-index/INDEX.md),再按本 skill 的查询口径查表 |
推荐接入:不要让每个消费方自己实现"选哪端",否则口径必然漂移 |
跨端 join(与 frontend-index 组合) |
先读后端 index.md 的「模块 → 挂载前缀」,再用前端 apis/{分区}.md 里的接口路径匹配前缀 → 答"后端改接口 → 前端哪些页面在用" |
可直接用(两端产物同根、口径已对齐;@Controller() 无前缀的模块用「方法路径」提示匹配) |
expert-team |
建完专家包后重跑 --emit-tree,专家列会因目录存在而出现 → 索引成为专家团的发现入口(解决"建了没人知道") |
可直接用(产物级衔接,无需改对方) |
module-teach |
讲解某后端模块前读 modules/{slug}.md 定位范围与依赖 |
已接入(「与相邻 skill 的分工与路由」表,module 类讲解先用索引锁定范围) |
code-survey / 设计前调研 |
查 INDEX.md 命中则消费,未命中再决定是否建库 |
已接入(「ki-search 与资产复用优先」链,缩小搜索域) |
bug-impact-analysis / code-review / debug |
改到后端模块或数据表时,用被依赖与表反查确认影响面 | 已接入(bug-impact-analysis 3.0 / code-review 阶段 2 / debug Step 0) |
上表不声明"已接入":本 skill 的产物需要目标项目先建一次索引,集成方需自行降级(无索引时按原流程 grep)。
全局前缀匹配口径(跨端 join 的关键,写清防歧义):挂载前缀 = "/" + global_prefix + controller前缀;@Controller() 无路径时,用方法路径首段(模块卡/表格里显示为"方法路径 x、y")与前端接口路径做包含匹配。
更多资源
reference.md:为什么是模块级(设计依据与专家团证据)· 框架提取规则明细 · 脚本参数与退出码全表 · 证据分级与[待确认]规则 · 两靶子实测数据与已知坑 · 抽样核对方法