17 KiB
17 KiB
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(详见部署与配置变更日志) |
历史遗留说明: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 由 Svelte 渲染且会在 StrictMode 双挂载、切换文档时重建 DOM,插槽采用
- 修复编辑器全屏层级: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) |
上线清单(发布执行顺序)
- 按提交划分合并改动(编辑器 / UI 规范 / 后端修复 / 脚本 / 文档 / 配置 / 测试)。
git tag -a v1.0.0 -m "NEX Docus v1.0.0" && git push origin v1.0.0。- 先解决 OI-P0(Redis RDB),再执行部署。
- Docker 演练:
./scripts/deploy.sh upgrade→ 登录 → 打开文档编辑 → AI 问答 → 分享预览。 - 立即修改默认管理员密码(两套初始口令见部署变更日志),并在
.env显式设置:ADMIN_PASSWORD=<随机值>、DEFAULT_USER_PASSWORD=<随机值>、SECRET_KEY=$(openssl rand -hex 32)。 - 确认
GET /返回version=1.0.0,并且docker compose logs backend | grep 安全自检无输出(有输出说明第 5 步没做完)。 - 按 OI-13 把 MySQL/Redis 端口绑到
127.0.0.1(或确认主机防火墙已拦截)。