Files
multica/docs/workspace-url-refactor-proposal.md

6.6 KiB
Raw Permalink Blame History

Workspace URL 化重构 — 项目汇报

日期2026-04-15 作者Naiyuan 状态:调研完成,待评审


一、为什么要做

当前 workspace 上下文完全靠 X-Workspace-ID HTTP header + Zustand store + localStorage 承载URL 里不含任何 workspace 信息。所有路径都是 /issues/issues/:id 这种 workspace-agnostic 的。

这个设计已经在产品里直接表现为 3 个已知问题:

  1. 分享链接不可靠MUL-43/issues/abc 发给另一个成员,会用他自己 localStorage 里的 workspace 去解析,导致 404 或看到错误 workspace 的数据
  2. 手机端无法切 workspaceMUL-509切换只靠 sidebar UI手机端不展开 sidebar 就没有切换入口
  3. 多 tab 互相覆盖multica_workspace_id 是全局 localStorage key两个 tab 打开不同 workspace 会互相污染

除了这 3 个显性 bug架构上的"多份 workspace 状态拷贝互相同步"也带来一些隐性问题(创建 workspace 闪页、切换 workspace 时 cache 竞态等),积累时间越长后续改动越难。

行业惯例Linear / Notion / Vercel / GitHub都是 /{workspace-slug}/... 的 URL 形态,把 URL 当作 workspace 的唯一来源。这是我们应该对齐的最佳实践。

二、调研结论

好消息:基础设施已经就位

  • 数据库 workspace.slug 字段已经存在(TEXT UNIQUE NOT NULL),用户创建时手动指定且不可修改
  • 后端已有 GetWorkspaceBySlug 查询
  • 前端 Workspace 类型已包含 slug 字段
  • Web 端认证已经切换为 HttpOnly cookie 模式Next.js middleware 可读到登录态

也就是说这次改造不需要大量后端改动,主要是前端路由和状态管理的重新组织。

坏消息:范围比最初估计大

初看以为只是"URL 前缀加个 slug",调研后发现必须一起做的事情有:

  1. URL 路由重组web 端所有 dashboard 路由迁到 app/[workspaceSlug]/(dashboard)/*desktop 端所有 react-router 路由加 /:workspaceSlug 前缀
  2. 状态管理清理:删除 useWorkspaceStore.workspace 作为独立状态,改为从 URL 派生;删除 hydrateWorkspace / switchWorkspace actions切 workspace 变成纯导航);删除 localStorage["multica_workspace_id"]
  3. 所有路径引用替换push("/issues") 改为 path builderpaths.issues()),影响 ~25 个组件文件
  4. Mutation 副作用重构useCreateWorkspace / useLeaveWorkspace / useDeleteWorkspace 里的 switchWorkspace 调用全部移除(这些调用正是 MUL-727 闪页、MUL-728 删除后不跳转、MUL-820 接受邀请不切 workspace 等一系列 bug 的根因)
  5. 桌面端 tab 系统适配tab 路径天然包含 workspace切 workspace = 开新 tab 或导航,不再有全局切换动作
  6. Shareable URL 修复:桌面端 getShareableUrl 当前生成 https://www.multica.ai/issues/abc(缺 slug需要更新
  7. 后端保留词校验slug 不能和前端顶级路由冲突(loginonboardinginviteapisettings 等),后端创建时校验
  8. 内部 markdown 链接兼容issue 评论里写的 [foo](/issues/abc) 触发的 multica:navigate 事件需要自动补当前 workspace slug

不需要改的(边界已确认)

  • 邮件邀请链接 /invite/{id} — 接受邀请是 pre-workspace 流程,不需要 slug
  • mention://type/id 协议 — 只存 UUIDworkspace-agnostic
  • CLI 登录 URL — /login 也是 pre-workspace不需要 slug
  • 后端 API 路径 — 保持 /api/workspaces/{id}slug 仅用于前端 URL
  • 桌面端 multica://auth/callback — 认证回调,不涉及 workspace

三、方案要点

核心原则URL 是 workspace 上下文的唯一 source of truth其他状态都是派生态。

URL 形状/{workspace-slug}/issues/{id} (和 Linear / Notion 一致)

切换 workspace = 导航sidebar 下拉改为 <Link href="/{new-slug}/issues">,不再有命令式的 switchWorkspace 函数。这样一次性消除前面列出的一大批 mutation 副作用 bug。

预估影响面~30-35 个文件,其中约 20 个是机械替换hardcoded 路径 → path builder真正需要思考的核心逻辑改动集中在 5-6 个文件。

一个 PR 合并中间状态不可运行URL 结构是原子变化),不拆 PR。worktree 里充分开发和自测,一次 review 合并。

四、执行与测试计划

执行阶段

  1. 本周内:完成方案详细实施文档(精确到文件 / 行号 / 代码片段)
  2. 下一步:在独立 worktree 上开发AI 辅助写代码,过程中人工 review
  3. 开发完成后:本地跑全套验证(make check — TypeScript + 单测 + Go 测试 + E2E

测试阶段

  1. 本地自测
    • 已知功能路径(创建 / 浏览 / 搜索 issue切换 workspace接受邀请分享链接
    • 已知 bug 场景MUL-43 / MUL-509 / MUL-727 / MUL-820逐一验证已修复
    • 多 tab 场景(两个 tab 打开不同 workspace 互不影响)
  2. 测试环境部署:本地通过后发测试环境,全员试用几天,观察:
    • 是否有回归(特别是导航流、创建/删除 workspace、邀请流程
    • URL 使用感受(分享、收藏、刷新)
  3. 灰度 / 生产:测试环境稳定后推生产

风险提示

  • 唯一的硬中断点:现有的 /issues 等 URL 在重构后会 404产品还没正式 ship、用户量可忽略所以不做兼容性重定向
  • E2E 测试断言:约 20-30 处 URL 断言需要更新
  • 后端保留词清单:如果现有 workspace 里有名字撞到保留词的(例如正好叫 settings),需要提前 migrate可能性极低因 slug 限制较严)

五、附注

这次重构会顺带修掉以下已登记 issue不需要单独开 PR

Issue 修复方式
MUL-43切换 workspace 报错 / 分享链接失效) URL 带 slug根本解决
MUL-509手机端无法切 workspace 切换变导航,手机能点链接就能切
MUL-723workspace 不在 URL 核心目标
MUL-727创建 workspace 闪 /issues 删除 mutation 里的 switchWorkspace 副作用
MUL-728删除 workspace 后留在 /settings 删除成功后 navigate 到下一个 workspace
MUL-820sidebar Join 不切 workspace Join 改成跳转到 /invite/{id} 走统一路径

不在本次范围内的Issue #951WebSocket 半开导致 cache 陈旧)—— 这是 realtime 层独立问题,单独 PR 处理。


当前状态:准备进入详细实施方案撰写,预计完成后再同步一次。