130 lines
17 KiB
Markdown
130 lines
17 KiB
Markdown
# Release v1.0.0(首个正式版本)
|
||
|
||
> 本文件是 **v1.0.0 的发布记录与验证边界**。发布内容 = git 基线 `ba80d28 fix project role permission`(v0.9.9-SP1 之后)+ 当前工作区未提交的发布前整改。
|
||
> **上线动作**:本发布**尚未打 git tag**,需在整改提交合并后执行 `git tag -a v1.0.0 -m "NEX Docus v1.0.0"` 并推送,使「版本以 git 为准」的规则重新成立。
|
||
|
||
## 元数据
|
||
| 项 | 值 |
|
||
| --- | --- |
|
||
| 版本 | v1.0.0(首个正式版本 / 第一个大版本) |
|
||
| git 基线提交 | `ba80d28 fix project role permission`(main) |
|
||
| 上一条版本标记 | `eea3b96 v0.9.9-SP1`(非连续,其间的 `5d41339`/`fef17e5`/`b3f5fb0`/`dfd4618` 无版本标记) |
|
||
| git tag | **待创建** `v1.0.0` |
|
||
| 代码内版本字段 | `backend/app/core/config.py` `APP_VERSION = "1.0.0"`;`frontend/package.json` `version = "1.0.0"` — **已对齐** |
|
||
| 适用组件 | backend(FastAPI + SQLAlchemy + MySQL + Redis)、frontend(React 18 + Vite + antd + ByteMD)、docker-compose 部署编排、`scripts/` 运维脚本 |
|
||
| 数据库 | 无 schema 变更(本发布不含迁移;表结构与 `docs/database.md` 一致,共 18 张表) |
|
||
| 破坏性变更 | 脚本路径 `./deploy.sh` → `./scripts/deploy.sh`;`.env` 移除 `VITE_API_BASE_URL`(详见[部署与配置变更日志](../../deploy/changelog.md#v100未发布)) |
|
||
|
||
> 历史遗留说明:v0.9.9.md 与旧 `releases/README.md` 曾把代码里的 1.0.0 判定为「遗留占位」。本发布通过**显式建 tag** 把版本线正式推进到 v1.0.0,占位问题到此结束。
|
||
|
||
## 本发布范围
|
||
|
||
### 1. 文档编辑体验(DV-0003)
|
||
- 编辑器**默认只打开编辑区**(`edit` / `split` / `preview` 三态可切换,选择写入 `localStorage` 并按用户记忆)。旧行为是编辑区与预览区同时打开。
|
||
- **视图模式切换并入编辑器工具栏**:三态分段控件由内容区标题栏移到 ByteMD 编辑器工具栏**右侧**,与内置「全屏」按钮同排(`createPortal` 注入 `.bytemd-toolbar-right` 末个子节点),只保留图标 + Tooltip(「编辑 · 仅编辑区」等);与重复的内置开关(文档索引 / 帮助 / 仅编辑 / 仅预览)统一隐藏,标题栏只留「未保存」标记与保存/重置。
|
||
- ByteMD 由 Svelte 渲染且会在 StrictMode 双挂载、切换文档时重建 DOM,插槽采用 `MutationObserver` + rAF **持续校验**(缓存节点 `isConnected` 失效即重找),避免 Portal 渲染到游离节点。
|
||
- 仅**分栏**模式显示「同步滚动」开关;纯编辑 / 纯预览下自动隐藏。
|
||
- **修复编辑器全屏层级**:ByteMD 的 `.bytemd-fullscreen` 是 `position: fixed` 但没有 `z-index`,会被 `.mode-switch`(`z-index: 1`)等浮层压住,导致左侧项目树的操作按钮浮现在全屏编辑器上。现在显式抬到 `var(--z-float)`(900),文档索引浮标再抬一层仍可点;并补 **`Esc` 退出全屏**(自动补全等浮层打开时不抢占)。
|
||
- **Table of Contents 不再依赖预览区**:新增 `frontend/src/utils/markdownToc.js`,大纲直接从 Markdown **源码**解析(标题层级 + 滚动定位),因此在纯编辑视图下 TOC 依然可用(`FloatingToc`)。
|
||
- **未保存保护**:以 `contentBaseline` 计算 `isDirty` → 标题栏显示「未保存」标记;离开页面(`beforeunload`)与返回项目列表时拦截确认;新增全局 **Ctrl/Cmd + S** 保存并带 loading 并发保护。
|
||
|
||
### 2. UI / 交互 / 设计规范统一(跨 DV)
|
||
- 新增设计令牌层 `frontend/src/styles/design-tokens.css` 与 antd 主题映射 `frontend/src/theme/antdTheme.js`;22 个文件中的硬编码颜色/圆角/间距替换为令牌。
|
||
- 新增统一反馈组件 `frontend/src/components/Feedback`(Toast / `Toast.confirm`),16 处 `Modal.confirm` 迁移;新增路由级 `PageLoading`,全部路由改为 `React.lazy` 代码分割。
|
||
- 新增 `frontend/.eslintrc.cjs` 固化前端规范;删除 33 个从未被引用的死代码组件/模块,删除无效的「语言切换」假开关。
|
||
|
||
### 3. 后端正确性修复
|
||
- `app/models/__init__.py` 补齐 `Notification`、`ProjectGitRepo` 注册 —— 此前单独导入这两个模型会缺表,影响 metadata 完整性与新库初始化。
|
||
- `GET /api/v1/projects/{id}` 由 500(`MissingGreenlet`)修复为正常返回:改用 `require_project_read_access(..., allow_public=True)` + `await db.refresh(...)` + `serialize_project(...)`,响应补充 `doc_count`、`user_role`。
|
||
- 项目角色判定统一走 `normalize_project_role`(历史数据角色名为大写),修复分享/仪表盘/项目接口对同一用户判定不一致的问题;`projects.py` 中重复的 `check_project_access` 死代码删除。
|
||
- 新增回归用例覆盖角色归一化与项目读权限。
|
||
|
||
### 4. 仓库与运维整理
|
||
- **脚本统一迁入 `scripts/`**:`deploy.sh`(路径变更)+ **新增** `start.sh` 一键启动(依赖检查 / 后端 venv / 前端 vite / `/health` 探活)+ 新增 `stop.sh`;`scripts/README.md` 说明用途。
|
||
- 删除 19 个与新 schema 脱节的一次性 SQL/Python 脚本、删除针对旧 compose 结构的 `fix_docker_deployment.sh`。
|
||
- `docker-compose.yml` 去除废弃 `version` 字段与无效的 `VITE_API_BASE_URL` 构建参数;`.gitignore` 补 `backups/`、`.run/`;`deploy.sh uninstall` 行为修正。
|
||
- 新增 `backend/requirements-dev.txt` 与 `backend/pytest.ini`,使后端测试可一条命令运行。
|
||
- 删除根目录里与本项目无关的历史残留 `.dsh-plugins/pet-dock/`(第三方桌面 shell 插件,仓库内无任何引用);`.gitignore` 补 `.claude/`。
|
||
|
||
### 4b. 配置与安全加固
|
||
- `docker-compose.yml` 补 `DEFAULT_USER_PASSWORD` 透传,`.env.example` 补齐该键 —— 此前 Docker 部署下改 `.env` **完全无效**,新建用户恒为 `User@123456`。
|
||
- 新增启动期「安全自检」`Settings.security_warnings()`:`SECRET_KEY` 命中模板占位值或长度 < 16、`DEFAULT_USER_PASSWORD` 仍为仓库默认值时打 `WARNING`(**只告警不阻断**,兼容存量部署)。此前漏配 `.env` 会带着**公开已知的 JWT 密钥**静默上线。
|
||
- `.env.example` 的 `ADMIN_EMAIL` 由真实域名邮箱改为 `admin@example.com`,与 compose / `init_db.py` 默认值对齐。
|
||
- `scripts/start.sh` 新增 `--daemon`:健康检查通过后立即返回(默认仍为前台驻留 + Ctrl+C 停止),使一键启动可被 CI / 上层脚本调用。
|
||
|
||
### 5. 文档体系重组(`docs/`)
|
||
- 根目录仅保留 `README.md` + `docker-compose.yml` + `.env.example` + `.gitignore`/`.dockerignore`,文档全部归入 `docs/`。
|
||
- 重写:根 `README.md`、`docs/README.md`(总入口)、`docs/quickstart.md`、`docs/database.md`、`docs/deploy/README.md`、`docs/deploy/changelog.md`、`backend/README.md`、`docs/manual/user-guide.md`(13 章用户手册,替代原中文命名手册)。
|
||
- 归档:`PROJECT.md`、`IMPLEMENTATION_PLAN.md` → `docs/archive/`(含登记表 `docs/archive/README.md`);删除内容重复且过期的 `DEPLOYEE.md`、`README_DOCKER.md`。
|
||
- 清理文档中的明文生产凭据;修复失效链接与**与代码不符的描述**:健康检查统一为 `GET /health`(不存在 `/api/v1/health`)、OpenAPI 实际路径是 `/openapi.json` 而非 `/api/v1/openapi.json`、`APP_NAME`/`ADMIN_EMAIL` 默认值回填、`app/utils` 目录并不存在等。
|
||
|
||
## 能力覆盖(DV 矩阵)
|
||
| DV | 单元 | v1.0.0 影响 |
|
||
| --- | --- | --- |
|
||
| DV-0001 | 认证与会话 | 无功能变更;`/health` 探活口径在文档中统一 |
|
||
| DV-0002 | 项目与文件系统 | `get_project` 500 修复、角色归一化、响应补 `doc_count`/`user_role` |
|
||
| DV-0003 | 文档编辑与文件操作 | **重点变更**:默认编辑区 + 工具栏内三态切换 + 源码 TOC + 未保存保护 + Ctrl/Cmd+S + 全屏层级修复 |
|
||
| DV-0004 | RBAC 与系统管理 | 角色大小写归一化,读权限判定统一 |
|
||
| DV-0005 | 全文检索 | 无功能变更;UI 令牌化 |
|
||
| DV-0006 | ZVec 向量化 | 无功能变更;`backend/models/`(本地向量模型)明确 gitignore |
|
||
| DV-0007 | 知识库 RAG 对话 | UI 令牌化、Toast 反馈、SSE 约定写入 `backend/README.md` |
|
||
| DV-0008 | LLM 模型配置 | UI 令牌化;`api_key` 明文存储列为已知问题 |
|
||
| DV-0009 | 分享与公开预览 | 角色归一化影响分享权限判定 |
|
||
| DV-0010 | 通知/日志/Git/导出 | 模型注册修复;UI 令牌化 |
|
||
| DV-0011 | MCP 接入 | 无功能变更;接入说明见 `docs/sdd/integrations/mcp.md` |
|
||
|
||
## 验证边界(本发布实际做过什么)
|
||
|
||
### 已验证(可复验)
|
||
| 项 | 命令 / 方法 | 结果 |
|
||
| --- | --- | --- |
|
||
| 后端单测 | `cd backend && ./venv/bin/python -m pytest` | **40 passed**,10 warnings(均为 Pydantic `class Config` 弃用告警) |
|
||
| 前端静态检查 | `cd frontend && npm run lint` | **0 error / 25 warning**(全部为 `react-hooks/exhaustive-deps`) |
|
||
| 前端构建 | `cd frontend && npm run build` | 通过;产物见下方「已知问题」的体积表 |
|
||
| 编辑器三态 + TOC | 浏览器实测(headless Chrome + CDP,1680×980,临时项目,用后已清理) | 默认 `编辑` 且 `.bytemd-preview{display:none}`;分栏 641/641;预览模式下左栏 Markdown 工具栏隐藏;TOC 来自源码大纲,编辑模式下点条目光标跳到目标行;切换文件(编辑器重挂载)后分段控件仍在;超大文档(>250000 字符)与 PDF 不出现分段控件 |
|
||
| 工具栏三态切换与全屏同排 | 同上 | 工具栏右侧顺序:`编辑/分栏/预览`(88×24)→ 全屏图标(24×24),垂直中心差 0px,工具栏高 33px 无重叠;≥1100px 视口不换行;明/暗主题配色一致 |
|
||
| 全屏层级与 `Esc` 退出 | 同上 | `.bytemd-fullscreen` `z-index:900` + `fixed` 覆盖 1680×980;`.mode-switch`(`z-index:1`)被完全压住(`elementFromPoint` 落在编辑器内);`Esc` 两次均退出并恢复布局 |
|
||
| 未保存保护 | 同上 | 输入 → 「未保存」标记出现;`Cmd+S` → 保存成功且标记消失;不脏时返回不弹框;脏时弹框且「继续编辑」保持现场 |
|
||
| 项目详情接口 | `GET /api/v1/projects/{id}` | 有权 200(含 `doc_count`/`user_role`)、不存在 404、他人私有 403,与 `/files/{id}/tree` 口径一致 |
|
||
| 模型注册 | 遍历 `Base.metadata.tables` 与线上库双向 diff | 18 张表,差异为空 |
|
||
| 本地一键启动 | `./scripts/start.sh --daemon` → `curl /health` → `./scripts/stop.sh` | 脚本返回 0;后端 `GET /health` healthy、前端 `:5173` 200、`.run/*.pid` 保留 |
|
||
| 安全自检 | `tests/test_security_selfcheck.py` | 占位/短 `SECRET_KEY`、默认 `DEFAULT_USER_PASSWORD` 均被告警;加固后的配置零告警 |
|
||
| 文档链接完整性 | 全仓 Markdown 相对链接检查(排除 `storage/`、`venv`、`models/`) | 0 断链(归档内 `_assets/*.png` 为预期缺图) |
|
||
| 凭据泄露扫描 | 全仓明文口令扫描 | 仅剩 `.env.example` / compose / `deploy.sh` 的模板默认值(`.env.example` 内的真实域名邮箱已改占位) |
|
||
| 文档命令/路径可执行性 | 逐条比对脚本与端点:`GET /`、`/health`、`/docs`、`/openapi.json`、`deploy.sh --help` 的子命令表、`start.sh --help` | 一致(`GET /` 返回 `version=1.0.0`;`/api/v1/health` 与 `/api/v1/openapi.json` 均不存在,文档已修正) |
|
||
|
||
### 未验证(发布风险,需在上线前补做)
|
||
- **Docker 端到端**:本机 Docker daemon 不可用,`docker compose up -d --build` + `./scripts/deploy.sh upgrade` 本发布**未实测**,只做静态审查(Dockerfile / nginx.conf / compose 已逐行核对,结论见 OI-5/OI-13/OI-14)。上线前必须演练一次:storage bind mount、SSE 流式对话、`/mcp` 反代、`init_db.py` 在空库上建表。
|
||
- **MCP 真实客户端接入**:仅有接口级验证,未用真实 MCP 客户端跑通 DV-0011 全链路。
|
||
- **Git 仓库同步真实远端**:`project_git_repos` 的 push/pull 未在真实远端验证(依赖外部环境凭据)。
|
||
- **多浏览器 / 移动端适配**:仅在 Chromium 内核验证;Safari/Firefox 与窄屏未测。
|
||
- **升级回归**:本发布无 DB 迁移,但未在「旧库 + 新代码」上做过完整冒烟(共享开发库含真实数据,禁止写测)。
|
||
|
||
## 已知问题(开放项)
|
||
| 编号 | 优先级 | 内容 | 建议处置 |
|
||
| --- | --- | --- | --- |
|
||
| OI-P0 | **P0(阻塞上线)** | 远端 Redis(`192.168.124.203`)`rdb_last_bgsave_status=err`,最近一次成功 RDB 已距今数小时,当前靠 `stop-writes-on-bgsave-error=no` 临时放开写入。该参数**非持久配置**,Redis 重启后恢复默认 → 全量写入返回 MISCONF | 上线前由运维排查磁盘/`fork` 内存并恢复 RDB;上线前把该参数写入正式配置或彻底修复 bgsave |
|
||
| OI-1 | P1 | 敏感信息明文入库:`share_links.access_pass`、`project_git_repos.token`、`llm_model_config.api_key`(详情接口回传原文) | 下一版本引入对称加密/KMS + 掩码回显;先限制详情接口权限 |
|
||
| OI-3 | P1 | 前端 **0 自动化测试**;后端仅 40 个用例,权限/文件系统覆盖薄 | 建 vitest + testing-library 基线,优先覆盖 DV-0002/0003/0004 |
|
||
| OI-5 | P1 | `frontend/Dockerfile` 中 `rm -rf package-lock.json && npm install` 导致前端构建不可重现。**根因已定位**:`package-lock.json` 在 macOS/arm64 上生成,`packages` 里只有 `@rollup/rollup-darwin-arm64`,**缺少 `@rollup/rollup-linux-x64-musl`**,直接 `npm ci` 会在 Alpine 镜像内因 rollup 缺原生二进制而失败(脚本注释提到的正是这个 bug) | 用 `npm install --cpu=x64 --os=linux --include=optional`(或 `npm install --package-lock-only --force`)重生成 lockfile 并验证含 linux-musl 条目,再切 `npm ci`;或把构建阶段换成 glibc 基础镜像。**未做**:本发布无法验证 Docker 构建,故保持现状不改 |
|
||
| OI-6 | P2 | 前端产物偏大:`antd` 1302 kB(gzip 408)、`index` 1242 kB(gzip 387)、`index` 919 kB(gzip 301)、`index` 522 kB(gzip 161) | 按需引入 antd 图标/组件、拆分 ByteMD 相关 chunk、提高 `manualChunks` 粒度 |
|
||
| OI-7 | P2 | 超大组件:`DocumentEditor` 1724 行、`DocumentPage` 1620 行、`Chat` 1638 行、`ProjectList` 1501 行 | 按 DV 切片拆分子组件与自定义 hook |
|
||
| OI-8 | P2 | eslint 25 warning(全部为 `react-hooks/exhaustive-deps`)。原 `ProjectList.jsx` 成员弹窗里 4 处输出成员/用户列表的 `console.log` 已删除,`notifications.py` 4 处 `print()` 降级日志已改 `logger`(`console.log`/`print()` 全仓归零) | 逐个消解 exhaustive-deps,CI 开启 `--max-warnings 0` |
|
||
| OI-9 | P2 | 重复实现:`shares.py` 内本地 `get_project_or_404`;`generate_share_code` 在 `projects.py` 与 `shares.py` 各一份;`api/knowledgeBase.js` 命名遗留 | 收敛到 `project_service` 与统一命名 |
|
||
| OI-10 | P2 | 配置键名两套体系:`backend/.env`(`STORAGE_ROOT/PROJECTS_PATH/USERS_PATH/TEMP_PATH`)与根 `.env`(`STORAGE_PATH`) | 下一版本统一并保留一个发布周期的兼容读取 |
|
||
| OI-11 | P2 | 超级管理员访问他人私有项目返回 403(全站口径已一致),但仪表盘提供全局统计 | 需产品明确超管边界(数据面 vs 管理面),再决定是否放开 |
|
||
| OI-12 | P3 | Pydantic `class Config` 弃用告警 10 处;磁盘遗留 `storage/projects_bak`(61M)、`backup/nex_docus_20260311.sql`(均已 gitignore) | 迁 `model_config`;离线归档后删除磁盘垃圾 |
|
||
| OI-13 | P1 | `docker-compose.yml` 默认把 **MySQL `3306` 与 Redis `6379` 发布到宿主机所有网卡**(`${MYSQL_PORT:-3306}:3306`)。配合默认口令/占位 `SECRET_KEY`,等同于把数据库直接暴露到局域网 | 默认改绑回环:`"127.0.0.1:${MYSQL_PORT:-3306}:3306"`;确需远程访问时用 `.env` 显式声明监听地址,并在主机防火墙拦截 |
|
||
| OI-14 | P2 | MySQL 数据目录挂在 `${STORAGE_PATH}/mysql`,而 `${STORAGE_PATH}` 又整体 bind mount 进后端容器当作文档存储根(`STORAGE_ROOT=/data/nex_docus_store`)→ 后端容器内可见数据库文件,且 `deploy.sh backup` 打包 storage 时会连正在写入的 datadir 一起归档 | 数据库与文件存储分目录(如 `${DATA_PATH}/mysql`),备份脚本显式排除 datadir |
|
||
| OI-15 | P2 | compose 里 `SECRET_KEY`/`ADMIN_PASSWORD`/`DB_PASSWORD` 等都有**公开已知的兜底默认值**,漏配 `.env` 时静默使用。本发布已加启动告警,但仍属"默认可用即不安全" | 下一版本移除敏感项兜底值,缺配即启动失败(fail-fast) |
|
||
|
||
## 上线清单(发布执行顺序)
|
||
1. 按提交划分合并改动(编辑器 / UI 规范 / 后端修复 / 脚本 / 文档 / 配置 / 测试)。
|
||
2. `git tag -a v1.0.0 -m "NEX Docus v1.0.0" && git push origin v1.0.0`。
|
||
3. **先解决 OI-P0(Redis RDB)**,再执行部署。
|
||
4. Docker 演练:`./scripts/deploy.sh upgrade` → 登录 → 打开文档编辑 → AI 问答 → 分享预览。
|
||
5. **立即修改默认管理员密码**(两套初始口令见[部署变更日志](../../deploy/changelog.md#5-两套默认密码并存重要易踩坑)),并在 `.env` 显式设置:
|
||
`ADMIN_PASSWORD=<随机值>`、`DEFAULT_USER_PASSWORD=<随机值>`、`SECRET_KEY=$(openssl rand -hex 32)`。
|
||
6. 确认 `GET /` 返回 `version=1.0.0`,并且 `docker compose logs backend | grep 安全自检` **无输出**(有输出说明第 5 步没做完)。
|
||
7. 按 OI-13 把 MySQL/Redis 端口绑到 `127.0.0.1`(或确认主机防火墙已拦截)。
|