任务有本体,不只是一行字
每类任务(缺陷、需求、评审……)由一张模板定义它该有哪些字段,任务是模板的实例。改模板不会追改已有任务——实例记着自己用的是哪一版。
任务详情里写着 bug · v3
WorkGraph 把任务当节点、关系当边、模板当本体。父子层级之外还有依赖、阻塞、引用三种语义边,于是「谁卡住了谁」不再靠人记——它能被查询、能被画出来,也能被别的系统订阅。

这三条不是功能清单上的三行,而是三个建模决定。它们决定了这个产品能回答哪些问题。
每类任务(缺陷、需求、评审……)由一张模板定义它该有哪些字段,任务是模板的实例。改模板不会追改已有任务——实例记着自己用的是哪一版。
任务详情里写着 bug · v3
除了父子层级,任务还能有依赖 / 阻塞 / 引用这些语义边。于是「谁卡住了谁」是能被查询、能被画出来的,而不是靠人在会上复述。
依赖顺序 = 图上的横向轴
不是你的项目,对你来说等于不存在:返回 404,而不是 403。全局管理员也没有例外——任务口径一律按项目成员制过滤,管理员要看得先加入,而加入会留痕。
404 而不是 403,是刻意的
从进得来到投影出去,产品只有这一条主线;其它一切都挂在它旁边。
邮箱 + 口令登录。顶栏的项目切换器决定这一页列出谁的数据,侧栏按权限过滤——看不到的条目不是被禁用,是你的角色没有这项权限。
先挑模板再填表。模板决定表单长什么样,也决定这类任务将来能被怎么统计。
动态表单按模板生成,另有自定义字段兜住模板没覆盖的那几格。
挂父子(最多 8 层,不能挂到自己或自己的后代上),连依赖 / 阻塞 / 引用。这一步是产品的分水岭。
分水岭四态状态机:未开始 / 进行中 / 已完成 / 受阻。看板可拖,进度按直接子任务平均上卷——刻意不加权,要精确口径就看数字,别看百分比。
前置没完成的任务会亮锁标记。没有实时协同编辑,但保存时做版本校验,不静默覆盖别人的改动。
把这张图投影出去:Webhook 事件与 JSON-LD 读接口,让别的系统订阅任务的变化。


自绘 SVG + ELK 布局,不是一张导出的静态图。横向是依赖顺序,虚线框是层级归属;节点底色是状态,左侧色条是优先级,图标是类型。
图例
硬上限,写在明处

四件事,它和别处不一样
没命中的节点淡出而不是消失,角上给出「命中 X / Y」。所以你始终知道自己在看整体的哪一部分。
聚焦模式保留祖先、后代与传递依赖;筛选、聚焦、折叠状态都写进 URL 的查询参数,同事打开看到的是同一屏。
下载 SVG、下载 PNG(2 倍)、复制 PlantUML 源码、另存为项目图表。前三条完全在浏览器里完成,图不出站。
Tab / Enter 走位,点节点出浮层;另附节点与依赖关系的纯文本清单,读屏不必去啃 SVG。
WorkSync 里的五个模块,在这里是同一套资源机制的五个 kind:同一份权限、同一个回收站、同一种分享。不是五个子系统各写一遍。
markdown树最多 5 级,约 2 秒自动保存。完整版本历史:行级 diff、预览、打标、回滚,历史只追加不改写。文档互链按 id 补全,所以改名不断链。
diagram渲染走自建的 PlantUML 服务端,源码不进 URL、不进 Referer、不进代理日志。10 万字符上限,语法错误返回一张带批注的错误图;项目的任务关系图自动生成。
whiteboardExcalidraw 画布,自动保存,只存画布、背景与网格。只接受位图粘贴——SVG 有脚本注入风险,所以不收。画布上限 3MB。
file默认 50MB,平台策略可调 1–500MB。病毒扫描失败即拒:扫描器没配、连不上、超时,一律拒绝上传,而不是放过去。
external_url站外资料登记在册,和其它资源一样能挂到任务上、进回收站、被分享。


全局角色(admin / user)决定你能进哪些页面,项目角色(PM / 协作者 / 测试 / 观察者)决定你能动哪些任务。两层相乘,认不出的角色一律回退成最小权限。
治理页——用户、日志、项目清单——归管理员;项目内容仍按成员制过滤。没有一扇后门通向他不是成员的项目,而加入某个项目这件事本身会被审计。
五类白名单:越权、分享、销毁性操作、认证与凭据、配置变更,另外所有被拒绝的动作一并高亮。普通字段编辑去对象自己的活动动态,不挤进审计。审计没有 TTL。
后登录的那一处生效。强制下线不是即时断线、也不改口令;要真正堵住一个人得用停用。账号从不删除——删了,审计里的「谁做的」就指向虚空。
文档 / 图表 / 白板 / 附件 / 外链软删 30 天可恢复;任务是立即彻底删除,用「有子任务的任务不允许直接删」兜住。分享链接随删除失效,恢复也不会复活。

对外访问的身份是外部主体,不是一串裸令牌——它同样受项目成员制约束。订阅范围可选:指定任务、项目根任务、指派给我。
投递头
X-TaskGraph-Signature: sha256=HMAC-SHA256(secret, raw body)X-TaskGraph-Delivery: 本次投递的编号WorkGraph 是产品名;代码仓库、CLI 与投递头里的标识一律是 TaskGraph,对接时按上面的头名写死即可。
令牌只在签发那一刻完整显示一次,之后只剩 8 位指纹;签发本身是最高严重级的审计事件。

task.created / task.updated / task.status_changed / task.deleted,以及 link.created / link.deleted。任务和关系的变化都在里面。
消费方要对原始 body 字节验签,并按 payload 里的 id 去重——产品不承诺全局顺序,重复投递是允许的。
1 分钟 → 5 分钟 → 30 分钟 → 2 小时 → 6 小时,用满仍失败转死信。投递记录里能看到失败原因。
只读的任务列表与任务详情两个接口。带上 JSON-LD 的 Accept 头就拿到语义投影,响应带 Vary: Accept。目前只有读,没有对外写接口。
内置 GitHub。在线导入与离线导入共用同一套映射与幂等逻辑,结果逐字段一致;重跑安全,「新建 0 / 跳过 48」就是成功。单向只读,产品里的改动不回流上游。
主线 0–6 全部完成,正在真实项目里跑。一套 compose 起全栈,数据、图源与文件都不出你的网络。
六个服务:应用、单实例 worker、MongoDB 7 副本集、对象存储、上传病毒扫描、PlantUML 渲染。只有应用容器对外,其余四个不发布宿主端口,只在栈内网络可见。
P95 内部查询 200ms 以内:复合索引一律以 projectId 领头,判祖先走物化路径,进度在写时算好。读全在服务端组件完成,客户端没有要缓存的请求。
PlantUML 自托管并钉死沙箱配置;对象存储不发预签名 URL,文件字节全部经应用转发,所以它没有理由对外可达。构建期同样不外联,遥测一律关掉。
先建集合、校验器与索引,再灌内置手册——两步都幂等,升级时重跑不会重复写入。发信配置改完自增一位版本号即热生效,worker 不用重启。
WORKGRAPH
约一次 30 分钟的演示:拿你手上一段真实排期,把依赖和层级画成图,当场看清哪条链卡住了。正在用 WorkSync 的团队可以顺便聊迁移路径。
1 个工作日内回复