Skip to content

Latest commit

 

History

History
178 lines (133 loc) · 14.1 KB

File metadata and controls

178 lines (133 loc) · 14.1 KB

朵拉魔盒 / DoraBox 项目宪法(Constitution)

本文件是项目的最高约束("宪法"),把团队技术决策固化为 AI 的"潜意识"。 所有 spec.md / plan.md / tasks.md 及代码变更都必须遵守本文件;与本文件冲突的产出一律无效。 修改本文件需显式评审,且视为对全体特性的影响,需回看受影响的 spec。

适用范围:本仓库(Tauri v2 桌面应用 DoraBox)全部前后端代码、脚本、文档。


0. 不可动摇的产品红线(Product Invariants)

这些来自 docs/00-project.md,任何实现都不得违背:

  1. 纯 Python 教学环境(本项目形态):基础教程 100% 使用 Python 开发,学生不编译任何 Rust。所有 Rust 相关产物(dora CLI 二进制、dora Python wheel)由作者预编译并打包进朵拉魔盒安装包,学生端不安装 Rust 工具链、不安装 C 编译器/MSVC/Xcode CLT、不克隆 dora 源码、不做本地编译
  2. 零系统污染:绝不写入或修改系统级位置——系统 Python、系统 PATH、shell 配置文件(.zshrc/.bashrc/.profile 等)、Windows 注册表、/etc 或用户级 ~/.config(DoraBox 自身少量应用配置除外,见 §3)。魔盒 app 通过标准安装/卸载,不改系统环境。
  3. 产物与环境分置不可变产物(dora CLI + dora wheel)随魔盒 app 安装包分发、装在系统 app 位置;可变环境(Python venv、课程代码、模型、缓存)落在用户显式选择的工作目录内。彻底移除 = 卸载 app(移除产物)+ 删工作目录(移除环境)。注意:从系统直接卸载 app 不会自动删工作目录(其路径由用户选定、记于应用配置),需用户在魔盒内"彻底清理"或按提示手动删除;两者均不触碰系统级位置。
  4. 工作目录由用户显式选择:不预设、不硬编码任何默认工作路径。
  5. 环境变量仅进程级注入:所有 env(VIRTUAL_ENV/PIP_CACHE_DIR/UV_CACHE_DIR/UV_PYTHON_INSTALL_DIR/PIP_CONFIG_FILE/MODELSCOPE_CACHE/HF_HOME/TMPDIR/PATH 等)只注入到由 DoraBox 拉起的子进程/内置终端会话,进程退出即失效,绝不落盘到用户 shell 配置。
  6. 版本锁定(保证可复现):① dora 锁定到 commit 25bac6b3e5ed7435f49bd494e0ff4ef81ee0a674(来源 https://atomgit.com/dora-rs/dora),由作者据此预编译 CLI 与 wheel;② 内置 Python 版本锁定(wheel 的 ABI 依赖它)。锁定信息记于 .dorabox/config.json 与 app 版本。学生端得到的 CLI/wheel 版本一致(同一 app 版本 = 同一 dora)。变更锁定值须走 spec + 重新出包。
  7. 国内镜像默认开启:pip(清华 TUNA)、模型(ModelScope 优先,hf-mirror 回退)。对学生透明、免配置。(dora 本身已内置于 app,无需下载源码/crates。)
  8. 面向零基础学生:默认路径必须"打开即用",错误信息用中文、给可执行的修复建议。
  9. 分发签名:正式分发的安装包应做代码签名以免被系统拦截(macOS Gatekeeper 公证 / Windows SmartScreen);签名须带可信时间戳(已发布版本不因证书到期失效)。当前阶段可暂不购证书,用"首启中文引导(右键打开 / 仍要运行 / 去隔离)"兑底,正式签名列为发布前待办。Linux 无需签名。

1. 目录结构约定

1.1 仓库结构(源码)

DoraBox/
├── constitution.md              # 本文件(项目宪法)
├── docs/                        # 产品级规格与文档(顶层 WHAT/WHY)
│   ├── 00-project.md            #   产品功能规格(唯一真实来源·产品层)
│   └── specs/                   # SDD 特性规格
│       ├── ROADMAP.md           #     特性拆分 + 阶段 + 依赖顺序(总索引)
│       └── <Fxx-feature>/       #     每个特性一套三件套
│           ├── spec.md          #       需求规格:WHAT + WHY
│           ├── plan.md          #       技术方案:HOW
│           └── tasks.md         #       原子任务清单(可独立验证)
├── src/                         # 前端(React 19 + TS + Vite)
│   ├── features/<feature>/      #   按特性分目录(组件/hooks/状态)
│   ├── shared/                  #   跨特性复用(ipc 封装、类型、UI 基元)
│   └── ...
└── src-tauri/                   # 后端(Rust / Tauri v2)
    └── src/
        ├── main.rs / lib.rs     #   入口与 Builder 装配
        ├── commands/            #   IPC 入口层(薄;只做参数校验+编排)
        ├── core/                #   领域逻辑(纯逻辑,禁止直接 IO)
        └── infra/               #   副作用适配层(与 Tauri 无关的 fs/net/process,trait 抽象)

1.2 运行期工作目录结构(用户所选目录内,权威定义见 docs/00-project.md §四)

<工作目录>/
├── .dorabox/     # 魔盒元数据:config.json / state.json / logs/
├── python/       # 独立 Python 运行时 + 共享 venv(VIRTUAL_ENV;site-packages 含 dora wheel + 第三方包)
├── caches/       # pip/ uv/ tmp/
├── models/       # modelscope/ hf/
├── config/       # pip.conf(清华源)
└── course/       # repo/  workspace/

命名铁律:目录名全小写 ASCII、无空格、无中文。所有对上述目录的引用必须通过 core 中的单一路径定义源(一处常量/函数),禁止在各处硬编码字符串拼接。

dora CLI 与 wheel 不在工作目录:它们是不可变产物,随魔盒 app 安装包分发、装在系统 app 位置(dora CLI 二进制打进 app、随 app 签名;dora wheel 打进 app 资源,环境准备时从本地 wheel pip install 进 venv,dora 本体不从 PyPI/网络获取、不编译;wheel 的运行依赖如 pyarrow 经 pip 镜像联网补齐)。工作目录只放可变环境(venv/课程/模型/缓存)。


2. 模块边界与依赖方向

单向依赖,禁止反向或跨层:

commands  ──►  core  ──►  infra(trait)
   前端 (React)  ──invoke/event──►  commands
  • commands/:IPC 入口,薄层。只做:反序列化入参、调用 core 编排、序列化结果/错误、构造并注入 infra 实现、把 core 通过 trait 上报的进度转成 Tauri event 发出。不写业务逻辑。
  • core/:领域逻辑与决策(路径拼装、env 映射、平台分支、状态机、断点续做进度计算、长任务编排)。纯逻辑,绝不直接触碰文件/网络/进程;需要副作用时通过注入的 infra trait(含进度上报 trait)。
  • infra/:执行与 Tauri 无关的副作用(std::fsreqweststd::processportable-pty 等)。以 trait 暴露,便于测试 mock。
  • Tauri 绑定的副作用边界(重要):与 Tauri 运行时强绑定的 IO —— 事件 emitdialog、窗口、pty 会话在前端的桥接等 —— 一律commands 层承载commands 是"Tauri IO 适配边界")。core 只依赖抽象 trait(如 ProgressReporter),其 Tauri 实现放在 commands 侧并注入。这样 core/infra不依赖 Tauri 运行时类型,可脱离 Tauri 单独编译与单测。
  • core 不得依赖 commandscore/infra 不得 use tauri::*(保持可单测、可脱离 Tauri 运行)。
  • 前端只能通过 shared/ipc 封装调用后端,禁止组件内散落 invoke/listen 字符串。

3. 安全约束(红线,违者一律驳回)

  1. 禁止系统污染:见 §0.2。任何写文件操作,其目标路径必须位于「用户工作目录」或「DoraBox 应用自身配置目录」之内,且需经 core 的路径校验函数确认。
  2. DoraBox 应用自身配置:仅允许存放"最近使用的工作目录列表 / 应用 UI 偏好"等极少量数据于 OS 标准应用配置位置(经 Tauri path API);绝不在此存放缓存、env、镜像配置。
  3. env 仅进程级:见 §0.5。严禁调用任何修改用户持久环境的接口(如写 shell rc、setx、注册表)。
  4. 密钥/敏感数据禁入日志:日志与 event 不得输出 token、完整下载凭证。
  5. 子进程可控:所有外部命令(uv、python、pip、dora)通过 infra/process 统一拉起,显式传入隔离 env,不继承会污染结果的系统变量。
  6. 网络来源白名单:下载仅走 §0.7 约定的镜像/官方源;URL 由 core 常量集中管理,禁止分散硬编码。
  7. 路径安全:处理用户输入路径时防注入/越界;校验可写、空间、特殊字符(尤其 Windows 盘符/长路径、macOS 外置卷、Linux 挂载点权限)。

4. 跨平台约定

  • PATH 注入:前置顺序 venv 可执行目录 + dora CLI 所在目录(app 内);分隔符 macOS/Linux 用 :、Windows 用 ;
  • venv 可执行目录:macOS/Linux 为 bin/,Windows 为 Scripts/
  • dora CLI 定位:dora CLI 在魔盒 app 安装位置内(随平台不同),由魔盒按平台解析其路径并注入 PATH。
  • 平台差异只在一处分支:所有平台相关逻辑集中在 core 的平台适配模块,其余代码平台无关。
  • 课程命令三平台一致:内置终端对外表现统一,屏蔽底层 shell 差异。
  • 分发包按平台构建:mac-arm64 / mac-x64 / win-x64 / linux-x64 各出一个安装包(内含对应平台的 dora CLI 二进制与匹配 Python 版本/ABI 的 dora wheel)。

5. 测试要求(TDD 强制)

红 → 绿 → 重构。先写测试,再写实现。每个交付物必须可独立验证。

  • 后端(Rust)
    • core 纯逻辑(路径拼装、env 映射表、平台分支、状态机)必须有单元测试,覆盖正常 + 边界 + 平台分支。
    • infra 通过 trait mock 做集成测试;真实 IO 用临时目录(tempfile),测试后清理,绝不触碰真实系统目录
    • 命令:cargo test(在 src-tauri/ 下)。
  • 前端:Vitest + React Testing Library;invoke/event 打桩。命令:bun run test(待引入)。
  • 验收(Validate 阶段不可省略):自动化测试通过 + 人工 Code Review。Spec 替代需求文档,不替代 Review
  • 无对应测试的功能代码不算"完成"。tasks.md 中每个任务的完成标准必须包含"测试通过"。
    • 例外:纯脚手架任务(建目录/加依赖)、薄适配层(命令层仅注入+调用 core+emit)、测试设施本身,其逻辑已被下层单测或上层集成/前端测试覆盖时,完成标准可用"构建成功 / 上层测试通过"替代独立单测,但须在任务中注明理由(可追溯)。

6. 可观测性(Observability)

长任务(下载 Python 包/模型、创建 venv、下载课程包)与关键操作必须可观测,至少能回答 SKILL §7 的 6 维度(当前目标 / 当前步骤 / 所用工具 / 失败原因 / 是否重试回退 / 本轮耗时)。

  • 进度上报:后端长任务通过 Tauri event 向前端推送结构化进度(步骤 id、状态、百分比/日志行)。
  • 日志落盘:操作日志写入 <工作目录>/.dorabox/logs/,便于复盘。
  • 断点续做:多步流程状态持久化到 .dorabox/state.json,失败可从断点重试,不必从头再来。
  • 错误可诊断:错误信息包含"发生了什么 + 可能原因 + 中文修复建议"。

7. IPC 约定(前后端契约)

  • 命令命名snake_case 动宾结构,语义清晰(如 select_workspaceprepare_envrun_diagnostics)。
  • 统一结构化错误:命令在边界返回统一的结构化错误 DTO,含 code(机器可读)+ message(中文,面向用户)+ 可选 hint(修复建议)。禁止把裸 String/panic 抛给前端。
    • 两型分离(实现约定)core/内部使用富错误类型(如 AppError,可携带上下文、便于 ? 传播与匹配);命令边界将其序列化为上述 wire DTO(如 ErrorPayload)。二者解耦:内部错误可自由演进,对前端契约保持稳定。命令签名形如 Result<T, ErrorPayload>
  • 事件命名domain://event(如 env://progressterminal://data)。
  • 共享类型单一定义:前后端交互的数据结构以后端为准,前端在 shared/types 保持对齐(后续可考虑生成)。
  • 命令层保持薄:一个命令对应一次明确用户意图;复杂编排下沉 core

8. 命名规则

  • Rust:模块/文件 snake_case,类型 PascalCase,函数/变量 snake_case,常量 SCREAMING_SNAKE_CASE
  • TypeScript/React:组件 PascalCase,hooks useXxx,变量/函数 camelCase,常量 SCREAMING_SNAKE_CASE,文件与组件同名。
  • 特性目录:docs/specs/Fxx-kebab-name(如 docs/specs/F01-workspace)。
  • 运行期工作目录内一律小写(见 §1.2)。

9. 变更治理(防规格官僚化 / 防规格腐烂)

  • 重大变更 / 跨模块影响:先改 spec → 改 plan → 再改代码。
  • 微小变更(措辞、按钮颜色、单模块内部重构且不改契约):可直接改代码,无需走全流程。
  • 规格腐烂防治:发现需求变化或 BUG,立即写增量 spec,保持 spec 与代码同步;禁止代码走了 V2、spec 停在 V1。
  • 判断标准:是否影响其他模块 / 是否改变对外契约 → 是则走 Spec。

检查清单(每个特性开工前对照)

  • 未触碰任何系统级位置(§0.2 / §3)
  • 所有落盘路径在工作目录或应用配置目录内,且过路径校验
  • env 仅进程级注入
  • 走单一路径定义源 / URL 常量源,无散落硬编码
  • 依赖方向 commands→core→infra,core 无直接 IO
  • 平台差异集中在平台适配模块
  • 先写测试,core 纯逻辑单测齐全
  • 长任务有 event 进度 + 日志落盘 + 断点续做
  • 命令返回统一结构化错误 DTO(code/message/hint),错误含中文修复建议