---
title: 项目约束总表
doc_type: constraint-index
domain: project
keywords:
  - 项目约束
  - fail fast
  - 分层边界
  - 文档治理
summary: 一页看清项目级硬约束、边界和当前落地状态。
when_to_read:
  - 改业务、架构或跨层边界前
  - 想快速确认哪些规则不能碰
read_next:
  - ./coding-rules.md
  - ../overview/architecture.md
---
# 项目约束总表

这份文档把当前项目已经设计出来的主要约束收敛成一份总表。

它回答的是：

- 这个项目在产品定位上被约束成什么
- 实现时哪些分层、权限、运行时和契约规则不能碰
- 哪些约束已经落到代码，哪些目前主要由文档约束

如果你只想看最硬的编码规则，直接读 [项目编码约束](./coding-rules.md)。如果你想理解这些约束为什么存在，再回看 [项目架构](../overview/architecture.md) 和 [项目业务总览](../business/README.md)。

## 一眼看完

| 约束组 | 核心要求 | 当前状态 |
| --- | --- | --- |
| 产品定位 | 本地优先的桌面研究工作台，不是普通 Web 后台 | 已文档化 |
| 架构分层 | 页面不越级，bridge 不承载业务，Rust 负责业务编排 | 已文档化，部分已落码，已加静态检查 |
| 任务运行 | 长任务统一由 Rust 后台执行，支持后台常驻和调度 | 已文档化，已落码 |
| 时间语义 | 业务日期与调度判断统一按北京时间；存储时间戳统一按 UTC | 已文档化，逐步收口到统一时间入口 |
| 状态中心 | SQLite 是本地状态中心，关键结果尽量从本地库读取 | 已文档化，已部分落码 |
| 运维权限 | 控制面菜单作为正式菜单交付给用户，不再依赖开发者模式显隐 | 已文档化，已落码 |
| 契约与编码 | 禁止运行时兼容，单一契约，fail fast | 已文档化，已加静态检查，约束最硬 |
| 数据表命名 | SQLite 表必须带固定分类前缀，legacy 表名必须显式登记迁移债务 | 已文档化，已加静态检查 |
| Git 工作区协作 | 如果采用临时 `worktree` 协作，改动应在独立 `worktree` 中执行，完成后回灌并删除临时工作树 | 已文档化 |
| 协作运行时状态 | 如果启用任务看板或 `worktree` 协作，运行时状态由协作工具自行维护，项目只约束唯一真值与冲突显式暴露 | 已文档化 |
| 逻辑验证 | 业务与边界改动必须完成逻辑准确性校验，并覆盖适用链路 | 已文档化，已加统一校验命令和 CI |
| 文档治理 | `docs/` 只保留根目录和一级分类目录；每篇文档头部自带关键词、用途和后续阅读 | 已文档化，已执行 |
| 数据初始化 | 初始化包和 dump 导入导出单独治理，不与业务文档混写 | 已文档化 |

## 1. 产品定位约束

### 约束

- 这个项目被定义为“本地优先的桌面端业务应用”
- 它的产品形态是“研究工作台”，不是单纯的数据查看器，也不是孤立任务后台
- 当日看盘、公告分析、个股详情、公告原文、深度报告属于同一条研究链路
- 调度、运行日志、LLM 日志和失败操作记录属于控制面，不是产品终点

### 来源

- [项目架构](../overview/architecture.md)
- [项目业务总览](../business/README.md)
- [业务背景](../business/context.md)

### 对实现的含义

- 做页面时要围绕研究流程组织，不要把系统做成零散工具集合
- 做后端能力时，要优先服务研究链路，而不是优先堆内部管理页面

## 2. 架构分层约束

### 约束

- 页面层不能直接碰 SQLite
- 页面层不能直接请求第三方数据源
- 页面层只能通过 `api/client.ts` 消费能力
- bridge 层只做协议适配和命名转换，不承载业务逻辑
- `commands.rs` 是 IPC 入口，不应该继续膨胀成跨模块业务中心
- 真正的业务编排落在 Rust 服务层

### 来源

- [项目架构](../overview/architecture.md)

### 对实现的含义

- 改页面时，不直接写 `invoke()`，先看 `api/client.ts`
- 改 bridge 时，只处理协议，不顺手塞业务逻辑
- 需要跨表、跨流程、跨数据源编排时，优先在 Rust 服务层完成
- 本地和 CI 默认通过 `npm run check:constraints` 检查页面层越级访问

## 3. 运行时与后台约束

### 约束

- 同步、导入、调度、分析这类长任务必须由 Rust 后台执行
- renderer 只负责发起、展示状态和查看结果
- 应用支持单进程后台模式
- 主窗口关闭时允许隐藏到托盘而不是直接退出
- 后台模式开启时，退出请求可以被拦截并转成常驻
- 业务日期、交易日、默认查询窗口和调度判断统一按北京时间（`Asia/Shanghai`）
- SQLite `CURRENT_TIMESTAMP` 及与之对齐的 Rust 写库时间戳统一按 UTC
- 禁止把宿主机本地时区当成业务真值直接参与市场日期判断

### 来源

- [项目架构](../overview/architecture.md)
- [src-tauri/src/lib.rs](/Users/winkd/my-projects/ai-stock-assistant-project/ai-stock-assistant-desktop-tauri/src-tauri/src/lib.rs#L201)

### 对实现的含义

- 不要把长耗时逻辑重新搬回前端
- 设计任务相关功能时，要默认考虑“后台持续运行”和“任务可恢复”
- 新增或修改业务日期判断时，优先走统一时间入口，不直接写 `Local::now()` 或浏览器本地 `new Date()`

## 4. 本地状态约束

### 约束

- SQLite 是本地状态中心
- 页面展示的关键结果应尽量从本地库读取
- 不要让页面自己维护一套脱离数据库的隐藏真实状态

### 来源

- [项目架构](../overview/architecture.md)

### 对实现的含义

- 新增关键业务结果时，优先考虑先落库，再展示
- 页面缓存可以有，但不应取代数据库中的真实状态

## 5. 运维与权限约束

### 约束

- 用户看到一套完整正式菜单，不再依赖开发者模式隐藏控制面入口
- `任务调度`、`通知治理`、`LLM 日志` 这类控制面页面属于正式研究工作台能力
- 如果某项操作需要额外限制，应在对应流程里显式约束，而不是靠整页隐藏

### 来源

- [项目架构](../overview/architecture.md)
- [src/renderer/src/router/index.ts](/Users/winkd/my-projects/ai-stock-assistant-project/ai-stock-assistant-desktop-tauri/src/renderer/src/router/index.ts#L86)

### 对实现的含义

- 新增运维入口时，要先判断它是否属于正式菜单能力，并与现有设置分组保持一致
- 路由、导航和页面本身都应保持同一套可见性口径，不能菜单可见但页面仍被挡住

## 6. 契约与编码硬规则

这组约束最强，默认按硬规则执行。

### 约束

- 禁止用兜底、兼容、静默回退掩盖问题
- 采用 fail fast，尽快暴露真实契约问题
- 同一业务语义只能保留一个正式字段名和一个正式语义
- 不允许新增运行时兼容层
- 结构性错误不能在 UI 上被空字符串、`-` 或默认值吞掉
- 修问题时优先修 producer、contract、service boundary，而不是 consumer 侧打补丁

### 来源

- [项目编码约束](./coding-rules.md)

### 对实现的含义

- 新改动不能再走“先兼容一下，后面再收口”的路线
- 发现字段漂移时，优先改契约，不要先在 UI 双读字段

### 已落地的机器可读约束

- 机器可读规则单一来源：`config/constraints.json`
- 逻辑验证统一入口：`npm run verify:logic`
- 本地检查脚本：`scripts/check_constraints.mjs`
- 当前已自动检查的重点：
  - 页面 / 组件禁止直接 `invoke()`
  - 页面 / 组件禁止直接访问 desktop bridge
  - 页面 / 组件禁止直接导入 `@tauri-apps/*`
  - `composables/*`、`stores/*` 和 `App.vue` 禁止直接访问 desktop bridge
  - `composables/*`、`stores/*` 和 `App.vue` 禁止直接导入 `@tauri-apps/*`
  - 前端运行时代码禁止依赖公告原文链路的 legacy snake_case 字段
  - SQLite 新建表必须使用固定分类前缀，未登记的 legacy 表名会直接失败
- 当前页面层没有登记中的直达 Tauri / desktop bridge 例外；如果后续必须临时破例，必须先在 `config/constraints.json` 的 `documented_debt` 里登记原因和退出条件

### 新增：SQLite 表命名分类前缀约束

以后新增 SQLite 表时，第一段必须是固定分类前缀，不能再直接用业务域名裸开头。

当前正式前缀如下：

| 前缀 | 表示什么 |
| --- | --- |
| `api_` | 第三方 provider 原始快照、官方码表、原始返回值 |
| `art_` | 原文、报告、快照等制品登记 |
| `biz_` | 产品正式消费的业务事实和业务工作流实体 |
| `llm_` | 大模型调用和审计控制面 |
| `mkt_` | 市场底座、行情、指标和派生市场事实 |
| `sync_` | 同步状态、导入批次和同步元数据 |
| `sys_` | 系统配置、用户、审计和通用控制面 |
| `tsk_` | 后台任务运行轨迹和任务事件 |
| `tmp_` | 一次性迁移、导入、测试期临时表 |

对实现的含义：

- 以后不要再新增 `notice_*`、`stock_*`、`tushare_*` 这类没有固定分类语义的表名。
- 如果历史表暂时还没改名，必须在 `config/constraints.json` 里显式登记为 legacy 迁移债务。
- `npm run check:constraints` 会检查 SQL schema 和 Rust migration 中的建表语句，不允许偷偷引入新的未分类表名。

## 7. 逻辑准确性校验约束

### 约束

- 涉及业务逻辑、共享契约、映射、筛选、状态推进或跨层编排的改动，不算完成，直到做完逻辑准确性校验
- 逻辑准确性校验必须覆盖下面 3 类中的所有适用项：
  - 契约校验：输入输出结构、字段语义、命名一致性
  - 核心逻辑校验：主要分支、边界条件、失败路径、关键计算
  - 关键链路校验：至少一个真实关键链路的调用编排或状态传递
- 不能用“只是重构”“只是搬代码”“只是 UI 调整”跳过适用的逻辑验证
- 提交前默认运行 `npm run verify:logic`

### 来源

- [项目编码约束](./coding-rules.md)
- [config/constraints.json](/Users/winkd/my-projects/ai-stock-assistant-project/ai-stock-assistant-desktop-tauri/config/constraints.json#L1)
- [scripts/verify_logic.mjs](/Users/winkd/my-projects/ai-stock-assistant-project/ai-stock-assistant-desktop-tauri/scripts/verify_logic.mjs#L1)

### 对实现的含义

- 新增或修改业务逻辑时，要同时补契约测试、逻辑测试或链路测试中的适用项
- 如果一段代码难以验证，优先继续拆边界，而不是放弃校验
- CI 默认应以 `npm run verify:logic` 作为逻辑正确性的最低门槛

## 8. Git 工作区协作约束

### 约束

- 只要需求会产生文件变动，默认先切临时 `worktree` 开发；纯分析、只读任务留在当前工作区。
- 开始改动前先检查当前工作区是否已有未提交改动。
- 如果工作区已经脏，且本次目标文件在主工作区仍是干净的，也必须切临时 `worktree` 隔离开发。
- 临时 `worktree` 必须从当前 `HEAD` 新建临时分支创建，不直接复用已有长期分支。
- 临时 `worktree` 里完成的改动必须回灌主工作区；回灌遇到冲突时直接失败并暴露，不允许静默覆盖或偷偷改写用户现场。
- 临时 `worktree` 完成回灌后必须删除；关联临时分支如果不再需要，也一起删除。
- 如果主工作区目标文件本身已经有未提交改动，不允许继续叠加，也不允许用 `stash`、`reset --hard`、`checkout --` 之类破坏现场的命令强行推进。

### 来源

- [AGENTS](../../AGENTS.md)

### 对实现的含义

- 项目协作默认把“是否会改文件”作为是否切 `worktree` 的分界线，而不是只看主工作区干不干净。
- 编辑任务默认保护用户当前现场，不把新的改动直接压到主工作区上。
- `worktree` 不是兼容层，也不是绕过冲突的手段；它只用于隔离无冲突的新任务。
- 真正发生文件重叠时，应直接暴露冲突并停下，而不是发明自动合并逻辑。

## 9. 协作运行时状态约束

### 约束

- 如果启用任务看板协作，运行时状态由协作工具自行维护，不要求项目内存在固定看板文件
- 项目只约束协作流程必须保持单一真值，不能并存第二套长期运行时状态
- 活跃任务是否绑定 `worktree`、状态怎么推进、什么时候创建或收尾，由所用协作工具定义
- 仓库本身不在约束里重复编码 `create/start/sync/finish` 之类具体命令或状态迁移细节

### 来源

- [AGENTS](../../AGENTS.md)

### 对实现的含义

- 如果某个 skill 或人工流程启用了任务看板协作，应把任务真值收口到同一份共享运行时状态里。
- 项目不感知状态文件地址、命令名、锁机制或某个特定协作工具的实现细节。
- 子代理开启、自动分发、agent 运行态登记和冲突裁决不属于当前正式流程；如需试验，只能作为临时手工过程，不能再写进仓库协作硬约束。

## 10. 功能专项约束

### 约束

- 某个功能的专项设计、对齐说明、测试文档统一进入 `docs/features/<feature-name>.md` 或 `docs/features/<feature-name>-*.md`
- 功能说明和功能测试都直接放在 `docs/features/` 根下，不再依赖目录级 `README.md`
- 功能文件命名统一用短横线

### 来源

- [文档目录](../README.md)

### 对实现的含义

- 后续新增功能文档时，优先套模板，不再把功能说明散落到 `docs/` 根目录

## 11. 文档治理约束

### 约束

- `docs/` 只允许“根目录 + 一级分类目录”的结构，不再继续嵌套正式文档目录
- 每篇正式文档头部都必须自带 frontmatter，至少写清 `title`、`doc_type`、`domain`、`keywords`、`summary`、`when_to_read`、`read_next`
- 每篇正式文档在标题下都要有简短导语，先说明“这篇文档讲什么、什么时候用、读完再看什么”
- `constraints/` 只放项目级硬约束和编码规则
- `overview/` 只放系统结构、分层和模块职责
- `business/` 只放长期稳定的业务知识、任务口径和业务沉淀
- `features/` 只放功能专项设计、实现现状和迁移方案
- `operations/` 只放运行说明、功能测试、排障和人工验收
- `bootstrap/` 只放初始化包和导入导出
- `templates/` 只放模板，不承载正式知识

### 来源

- [文档总入口](../README.md)
- [业务沉淀入口](../business/README.md)
- [功能专项入口](../features/README.md)
- [运维与验证入口](../operations/README.md)

### 对实现的含义

- 新增文档前先判断它属于哪一层，不要一篇文档同时承担多种职责
- 不要再维护仓库级集中关键词表；关键词和使用方式跟着文档头部走
- 如果改了某类文档，还要同步最近一级 `README.md`

## 12. 数据初始化约束

### 约束

- 数据初始化文档只讨论数据包怎么生成和导入
- 优先选择最接近原始数据源的路径，减少中间转换
- 只有在需要保留完整 dump 快照时，才走 dump 转换链路

### 来源

- [文档总入口](../README.md)
- [初始化包入口](../bootstrap/README.md)

### 对实现的含义

- 不要把产品业务讨论写进数据初始化文档
- 导入导出方案应保持独立治理

## 13. 当前最应该默认遵守的 5 条

如果你不想一次记住全部约束，至少先记住这 5 条：

1. 文件变更任务默认走隔离执行位，冲突直接显式暴露
2. 页面层不越级，只走 `api/client.ts`
3. 长任务统一由 Rust 后台执行
4. SQLite 是本地状态中心
5. 业务与边界改动必须完成逻辑准确性校验
