本文面向修改 MeetFlow 源码的开发者和 agent。部署或维护服务器请阅读运维指南,发布镜像请阅读发布指南。
- 后端是 Python 3.12 上的 FastAPI 和 SQLAlchemy 服务;路由、领域服务与数据模型都位于
backend/app/。 - 前端是 Vue 3、TypeScript 与 Vite,源码位于
frontend/src/;生产构建由同一个 FastAPI 服务提供。UI 使用 Naive UI(仅浅色主题)并保留深绿品牌:frontend/src/theme/naive.ts维护themeOverrides与状态色映射(statusTone/priorityTone),品牌 token 的唯一权威值仍是frontend/src/styles.css的:root(改一处必须两处同步)。图标一律@lucide/vue组件经NIcon渲染,字母头像统一走AppAvatar(优先使用后端avatar_color);编辑器与富文本渲染沿用 Milkdown Crepe 与 marked + DOMPurify;状态保持既有 reactive 单例模式(auth/session.ts、useInboxUnread、useUserNameMap),不引入 Pinia。 - 跨页交互约定:创建/编辑实体用右侧
n-drawer表单(宽度min(560px, 100vw)),确认/破坏性操作优先n-popconfirm(信息量大时n-dialog);瞬时反馈用n-message,页面级错误保留行内n-alert;稠密全局列表(行动项、决策、管理员用户、插件事件)用n-data-table+ 服务端筛选分页,富内容面(首页、项目、会议、工作区)保留卡片/行布局。 - SQLite 保存结构化数据,附件和备份保存在数据目录。容器运行时的持久化目录是
/app/data,部署时对应宿主机的./data/。 - 生产镜像只有一个应用容器。Vue 资源在构建阶段生成,运行阶段启动 Uvicorn 和内置的插件任务 worker。
- 会议系列的固定周期实例由应用进程内的低频 worker 创建;读取系列、会议列表和开始固定实例也会补算,因而不依赖外部 Cron。
- 生命周期转换(
start、finish、cancel、reopen)统一由MeetingService在单会话事务中提交:简单转换走表驱动的_transition,start/finish走_run_meeting_command,失败时回滚并按expected_version报告 409,共享的乐观锁诊断位于domain/versioning.py::resolve_stale;LifecyclePolicy负责纯状态迁移判断和会议可变状态白名单(MUTABLE_MEETING_STATUSES,保留ready以兼容旧数据)。会议列表由meetings/queries.py::query_meetings纯函数提供唯一的查询与序列化实现(项目内列表与工作区全局/api/meetings共用),meetings/projectors.py承担快照、附件与引用投影,outcomes/projectors.py承担成果序列化;读取路径不再反向依赖 service。 - 外部插件目录固定为
/app/plugins。生产部署可将宿主机目录以只读方式挂载到这里;插件代码仅应来自可信的服务器管理员。
需要 Python 3.12、Node.js 22 和 npm。首次准备环境:
python -m venv .venv
.venv/bin/python -m pip install -e '.[test]'
npm --prefix frontend ci
./scripts/start.sh local该脚本会在 http://127.0.0.1:8000 启动带自动重载的后端,并在 http://localhost:5173 启动 Vite;Vite 会将 /api 代理到后端。健康检查是 http://127.0.0.1:8000/api/health。
本地开发直接使用 backend/app/config.py 中的开发默认值(开发模式、data/、frontend/dist),无需创建 .env。需要覆盖时,在项目根目录创建被 Git 忽略的 .env;根目录 .env.example 是生产服务器模板,不要用于本地开发。
后端测试、前端测试和生产构建分别运行:
.venv/bin/python -m pytest -q
npm --prefix frontend test
npm --prefix frontend run build也可以从 frontend/ 目录运行 npm test 和 npm run build。不要在仓库根目录直接运行 npm 命令,因为根目录没有前端 package.json。
前端测试基于 Vitest + @testing-library/vue + jsdom;Naive UI 组件依赖 frontend/src/tests/setup.ts 的全局 jsdom 补丁(ResizeObserver、window.matchMedia、Element.prototype.scrollTo)。弹出层(drawer/dialog/popconfirm/dropdown)Teleport 到 document.body,测试统一用全局 screen.findBy... 查询;n-data-table 在 jsdom 下不启用虚拟滚动与固定列,需要横向滚动时显式设置 scroll-x。
需要对运行中的实例做端到端 API 冒烟时,运行 scripts/smoke_api.py。它会写入真实数据,只应指向一次性或专用测试实例:
.venv/bin/python scripts/smoke_api.py --base-url http://127.0.0.1:8000 --admin-password "$ADMIN_PASSWORD"改动发布或容器相关文件时,还应阅读发布指南中的 CI 与镜像验证说明。
依赖更新由 .github/dependabot.yml 每周检查:GitHub Actions、frontend/ 的 npm 依赖和根目录的 pip 依赖;minor/patch 更新各归组为一个 PR。typescript 与 vue-router 的 major 升级暂被忽略(工具链/生态未就绪,需手动评估迁移)。
Compose 是从源码构建、调试或修改 MEETFLOW_PORT、MEETFLOW_BIND 时使用的高级路径,不是普通服务器使用公开镜像的默认方式。无需 .env 即可启动,容器使用镜像内置的开发默认值:
./scripts/start.sh docker-detached
docker compose ps停止该 Compose 服务:
docker compose downcompose.yaml 将 ./data 映射为 /app/data,并将 ./plugins 以只读方式映射为 /app/plugins。需要覆盖配置时,在项目根目录创建 .env(不要复制面向服务器的生产模板 .env.example);不要把 .env、data/ 或备份文件加入提交。
运行中的非测试环境会在启动时执行 Alembic 的 head 迁移;迁移配置在 backend/alembic.ini,版本文件位于 backend/migrations/versions/。任何会改变已持久化表结构的改动都必须包含经过审查的 Alembic 迁移,并在真实数据上升级前完成备份。
测试环境使用独立的 schema 创建路径以保持测试隔离。不要把这种测试便利性当作生产数据库升级策略。
项目是工作区访问边界。完整的角色和 API 契约见协同加固设计:admin 与项目负责人(lead)可管理工作区,member 可贡献会议、议题、产出、附件和项目进展,stakeholder 只能查看。非项目成员若被邀请为某场会议参与人,仅能查看该场会议及其材料,并可在该会议评论;这不授予项目级访问或写入权。
项目和会议详情的 capabilities 由服务端计算,前端只能据此渲染操作入口,不能从登录角色或成员列表自行推导权限。附件响应另有逐项 can_delete,它同时反映贡献能力及作者/管理员约束。个人 attention 与 inbox 共用同一工作区通知范围:权限撤销后,既有私有项目通知不得出现在列表、增量、未读数或已读命令中。编辑项目进展必须提交 expected_version;过期写入返回 409 version_conflict,客户端应刷新后重试。该版本字段和 project_members.user_id 索引由 Alembic 迁移 0009 交付,不能用测试建表逻辑替代生产迁移。
MeetingSeries 的周期规则使用 IANA 时区和结构化频率字段,而不是展示用文字。Meeting.occurrence_kind 区分固定周期与临时实例,series_slot_at 唯一标识固定周期槽位;临时实例不得占用该槽位。修改这些字段或 AgendaItem.actual_duration_seconds、自动产出来源字段时,必须提供 Alembic 迁移。
开始固定周期实例会收尾同一系列上一个未结束的固定实例。结束会议会在同一事务内跳过未结束议题、保存会议及议题实际时长并创建快照。会后 UI 必须读取快照中的纪要、议题记录、状态、时长和产出,而不是读取可重新打开后改变的当前记录;全部 API 响应都会把 SQLite 读回的无偏移时间规范为带 Z 的 UTC,前端统一经 src/utils/time.ts 的解析与本地时区格式化,不能按浏览器本地时区直接解释无后缀时间。
工作台的会议级草稿集中在 useMeetingWorkspace:它维护服务器版本、dirty 状态、保存状态和 409 冲突,并在生命周期命令前 flush 会议纪要、目的和原始笔记。当前页面仍保留显式保存按钮以兼容既有用户流程;离开有未保存草稿的页面会触发路由和浏览器 unload 保护。议题编辑继续由 AgendaWorkbench 显式保存,避免与会议级 PUT 并发写同一条记录。