# NEX Docus 后端 FastAPI + SQLAlchemy 2.0(异步)+ MySQL + Redis 的文档管理后端,同时提供 RAG 知识库问答与 MCP 服务。 > **上手请先看 [`docs/quickstart.md`](../docs/quickstart.md)**(一键启动、环境变量、初始化、常见问题)。 > 部署/运维见 [`docs/deploy/README.md`](../docs/deploy/README.md),表结构见 [`docs/database.md`](../docs/database.md)。 > 本文件只描述**后端代码内部结构**与开发约定。 ## 技术栈 | 用途 | 选型 | | --- | --- | | Web 框架 | FastAPI + Uvicorn | | ORM | SQLAlchemy 2.0 异步(aiomysql),Alembic 迁移 | | 数据库 / 缓存 | MySQL 8(utf8mb4)/ Redis | | 认证 | JWT(python-jose)+ bcrypt(passlib) | | 全文检索 | Whoosh 3 + jieba 分词 | | 向量检索 | ZVec(远端 Embedding 或本地 Sentence-Transformers) | | 文件与导出 | aiofiles、自研 Markdown/PDF 导出服务 | | Git 同步 | 通过命令行调用 `git`(主机需自行安装) | | 测试 | pytest + pytest-asyncio | ## 目录结构 ``` backend/ ├── app/ │ ├── api/v1/ # HTTP 路由(前缀 /api/v1),__init__.py 汇总注册 │ ├── core/ # config / database / deps / security / enums / migrations / redis_client │ ├── mcp/ # MCP server 与请求上下文(挂载在 /mcp) │ ├── models/ # SQLAlchemy 模型(__init__.py 必须导入全部模型,见下方陷阱) │ ├── schemas/ # Pydantic Schema 与统一响应包装 │ └── services/ # 业务逻辑:project/file/search/rag/zvec/git/vectorization/notification/log/storage/llm… ├── scripts/ # init_db.py(建表+种子数据)、generate_password.py,详见 scripts/README.md ├── tests/ # pytest 用例 ├── models/ # 本地向量模型目录(gitignore,需自行放置 HF 模型,如 m3e-small) ├── main.py # 应用入口:/api/v1 路由、/mcp 挂载、/ 与 /health ├── requirements.txt # 运行依赖 ├── requirements-dev.txt # 开发/测试依赖(含 pytest) ├── pytest.ini # testpaths=tests, pythonpath=. └── .env # 本地配置(不入库;键名见下表) ``` ## 路由一览 `main.py` 暴露:`GET /`(名称/版本/状态)、`GET /health`(`{"status":"healthy"}`)、`/docs`、`/openapi.json`、`/mcp`(MCP Streamable HTTP,需 `X-Bot-Id` / `X-Bot-Secret`)。 `app/api/v1/__init__.py` 注册的子路由前缀: | 前缀 | 模块 | 说明 | | --- | --- | --- | | `/auth` | auth | 登录、当前用户、资料/密码/头像、MCP 凭证签发与轮换 | | `/projects` | projects | 项目 CRUD、成员、所有权转移、分享开关、Git pull/push 与目录选择 | | (同 `/projects/{id}/git-repos`) | git_repos | 仓库配置的增删改查与连通性测试(路由内部自带前缀) | | `/files` | files | 目录树、读写文件、文件操作、上传、导入导出、PDF 导出、文档与静态资源流式访问 | | `/preview` | preview | 项目预览 | | `/shares` | shares | 分享链接创建/校验/访问 | | `/search` | search | 全文 + 向量双引擎检索 | | `/chat` | chat | 会话管理、SSE 流式问答、引用与中断 | | `/llm-model-configs` | llm_model_configs | chat / embedding 模型配置与连通性测试 | | `/dashboard` | dashboard | 管理员统计 | | `/users` `/roles` `/role-permissions` `/menu` | users/roles/role_permissions/menu | 用户、角色、角色权限、菜单树 | | `/notifications` | notifications | 站内通知 | | `/logs` | logs | 系统日志查询 | ## 环境变量(`backend/.env`) 完整键表与说明见 [`docs/quickstart.md`](../docs/quickstart.md);此处只列必填项与常见坑: - 必填:`DB_HOST` `DB_USER` `DB_PASSWORD` `DB_NAME`、`REDIS_HOST` `REDIS_PASSWORD`、`SECRET_KEY`。 - 文件存储:`STORAGE_ROOT` / `PROJECTS_PATH` / `USERS_PATH` / `TEMP_PATH`(**本地开发用这组绝对路径**;Docker 部署用根 `.env` 的 `STORAGE_PATH`,两套体系不同,别混用)。 - `DEBUG=True` 时 SQLAlchemy 会打印全量 SQL,**生产必须 `false`**。 - `DB_PASSWORD` 含特殊字符无需手动转义(连接串构造时已 `quote_plus`)。 > ⚠️ **不要在代码、文档或提交里写真实环境的账号密码。** 需要示例时用占位值(如 `password_change_me`)。 ## 开发命令 ```bash cd backend python3 -m venv venv ./venv/bin/pip install -r requirements-dev.txt # 含运行依赖 + pytest cp .env.example .env # 若无,按 docs/quickstart.md 的键表创建 ./venv/bin/python scripts/init_db.py # 建表 + 种子数据(幂等) ./venv/bin/python scripts/generate_password.py # 生成 bcrypt 哈希 ./venv/bin/python -m pytest # 单元测试 ./venv/bin/uvicorn main:app --reload --port 8000 # 单独起服务(推荐用仓库根 ./scripts/start.sh) ``` ## 必须知道的实现约定 1. **新增模型要在 `app/models/__init__.py` 里导入。** 只建表逻辑而不导入,`Base.metadata` 就看不到该表,`init_db.py` 会**静默漏建表**,线上表现为 `Table ... doesn't exist`。 2. **项目权限只走 `app/services/project_service.py`**(`require_project_read_access` / `require_project_write_access` / `normalize_project_role`)。不要在路由里手写角色判断:历史数据里 `project_members.role` 存在大写(`ADMIN`/`EDITOR`/`VIEWER`),直接 `== "admin"` 比较会静默失效。返回给前端的角色必须先 `normalize_project_role`。 3. **异步 Session 配了 `expire_on_commit=False`**,但 `onupdate=func.now()` 的列(如 `updated_at`)在 UPDATE 提交后仍会被标记过期;提交后若还要序列化整个 ORM 对象,**必须 `await db.refresh(obj)`**,否则会在异步上下文触发同步 IO 抛 `MissingGreenlet`(HTTP 500)。 4. **统一响应**用 `app/schemas/response.py` 的 `success_response()`;业务错误抛 `HTTPException` 并用 4xx 表达(不要用 500 表达"参数/状态不合法")。 5. **SSE 接口**(`/chat`)要求网关关闭响应缓冲,见 `docs/deploy/README.md` 的 nginx 示例。 6. **本地向量模型**放在 `backend/models/<模型名>/`(含 `config.json`、`1_Pooling/config.json`、`model.safetensors` 或 `pytorch_model.bin`),由 `LocalEmbeddingService` 扫描列出;该目录已 gitignore,不要提交。 ## 测试 ```bash cd backend && ./venv/bin/python -m pytest ``` 覆盖范围(v1.0.0):项目权限与角色归一化、Git 服务命令构造、搜索服务、模型与向量配置、RAG 引用解析。**前端目前没有自动化测试**,界面回归需手工验证,重点清单见 [`docs/sdd/releases/v1.0.0.md`](../docs/sdd/releases/v1.0.0.md)。