路径说明(2026-09-20): 本文成稿时
docker-compose-storage-only.yml/docker-compose-storage-only.auth-none.yml/docker-compose.test.yml位于仓库根;2026-09-20 起三者迁入docker/目录(commit1854cae)。文中根目录原路径为历史记录,不再逐一回改;实际使用时请替换为docker/前缀路径。
改名註記(2026-09-17): 本文成稿與執行時,Cargo 包名/二進制名為舊名,lib 為舊名
_core;2026-09-17 起全倉統一改名為 Mega2(mega2/mega2_core),本文中的命令、路徑、環境變量與服務名已同步更新,歷史提交記錄本身不變。
模板版本: v2(成稿符合 docs/plan/plan-template.md v2)
本文解决 mega2 内与 website 产品面重复的 Campsite 风格 chat / Notes,以及浏览器会话仍硬编码 admin、Campsite/Tinyship 死配置未落地的问题。目标是:
- 整栈删除本仓 chat / Notes(产品能力留在 website
mega2分支); - 完整设计并实现本仓对 website Better Auth 用户系统的接入(唯一浏览器 IdP);
- 保留 Git 引擎所需的 Mono
access_token/ SSH / LFS / Bot 身份路径,以及/api/v1/user下的 SSH/token/CLA/通知偏好 API(仅更换会话身份来源;邮件投递偏好语义见 ADR-WA-08); - 把 website
apps/next-app整理进本仓 IT compose,与现有mega2-it数据面 /mega2(profileapp)一起启动,跑真实 get-session →/api/v1会话集成测试(对标 Mega demo 的「前端 + 后端 + 数据面同栈」形态,但 IdP 是 website next-app,不是 moon/campsite); - 去掉本仓全部邮件(email)投递能力,改由 website 的邮件通知功能发送;本仓不再持有 SMTP/
lettre/[mail]/email outbox。
本文只规划任务,不宣称实现完成。落地时每个任务都必须先刷新源码锚点,再按任务卡验收。
- Website 会话接入:
src/api/oauth/、OAuthConfig/[oauth]、SessionUser/LoginUser、CORS、docs/refactoring/website-auth.md。 - Chat / Notes 退场:
src/chat/、src/api/router/chat_router.rs、src/api/notes/、src/commands/chat_migrate.rs、src/contract/api/chat/、相关 callisto / jupiter storage、[chat]/ChatConfig、sidebar 默认项、chat 通知触发器、新 forward-only DROP 迁移。 - IT compose:
docker-compose.test.yml登记website-next(websiteapps/next-app)、docs/refactoring/test-infra.md服务条目、栈级会话黑盒(bin/tests/)、CI 可选 profile 拉起路径。 - 邮件退场与 website 投递: 删除
src/mail/、EmailChannel、[mail]、admin email-jobs/mail-templates、email_jobs/email_job_attachments;dispatcher 去 email-primary;产品事件经 website 邮件 API 发送;同步更新docker-compose.test.yml(去掉 mega2MEGA_MAIL__*;mailpit 改挂 website IT)、.env.test(.example)、CI workflow,以及docs/refactoring/{website-mail,mail,notification,test-infra,integration,config}.md、docs/development.md、根README.md邮件章节。 - 文档与发布:
docs/plan/plan-long.md、上列重构/开发文档、docs/plan/README.md、minor 版本发布。
- 不在 mega2 实现注册 / 登录 / 签发 session cookie(IdP 只在 website)。
- mega2 不直连读取 website 的 user/session 表(信任路径仍是 get-session HTTP);不引入 JWT / machine service-account(见
DEFER-WA-01)。website-next 容器可有独立账户库(IT 默认 SQLite,见 ADR-WA-07)。 - 不把 Mega 的 moon / campsite / MySQL 拉进
mega2-it;本计划的「同栈联调」对象是 website next-app + mega2,仅形态上对标 Mega demo。 - 不移植 website AI chat(
apps/next-app/app/api/chat)或docs-app静态文档站;不把 website 仓库的产品docker-compose.yml(nuxt/tanstack profiles)整仓迁入本仓。 - 不完成 PT-12 全量 moon↔
apps/next-app功能对照审计(本计划只落地账户信任路径 + 最小会话栈 IT)。 - 不把 CL/issue 事件编排整体迁到 website(触发仍可由本仓发出);本计划只迁邮件投递。Slack/webhook/in-app 是否保留见 ADR-WA-08(决议:保留 in-app + 可选 slack/webhook,去掉 email 通道)。
- 不删除历史 migration 文件;只追加 DROP。
- 不改 Git smart HTTP / SSH / LFS 的 token 鉴权语义。
- 无有效 website session cookie 时,
/api/v1会话路径不再得到隐式admin;带有效 cookie 时身份与GET /api/auth/get-session一致;banned用户被拒绝。 /api/v1/chat/*、notes sync、chat-migrate、[chat]不存在;新库经apply_migrations后无 chat/notes 相关表。- Git Bearer/Basic token 与 SSH 路径回归绿;
LoginUserJSON 字段为website_user_id。 --profile app --profile web可同栈拉起mega2+website-next;黑盒用例能在 next-app 登录后携带 session cookie 调用 mega2/api/v1/user并断言身份一致。- 本仓无 SMTP/
[mail]/email_jobs/admin 邮件表面;产品事件需发邮件时走 website 邮件 API;进程内不再直接投递邮件。 docker-compose.test.yml/.env.test*/ CI / 相关文档已反映「邮件投递在 website」:mega2 服务无MEGA_MAIL__*;mailpit 若保留则消费方为 website IT;开发与重构文档不再把本仓 SmtpMailer→Mailpit 当作门禁。- 全部非延后任务在 REL-01 后
Lifecycle=done且Acceptance=complete(子卡此前仅locally-accepted);plan-long.md/test-infra.md/notification.md/mail.md/development.md已同步;REL-01 minor 已发布。
本节为开工前快照(核对日 2026-07-31)。执行后状态以各任务卡 Lifecycle / Acceptance 与落地产物为准。行号仅作历史线索,开工须按 ER-02 刷新。
| 类别 | 当前事实 | 证据 |
|---|---|---|
| 代码入口 | 库入口 src/lib.rs;二进制 bin/src/main.rs;pub mod chat 仍注册 |
src/lib.rs:15 |
| 代码入口 | SessionUser 硬编码 admin / admin@gitmono.test(no-auth stub) |
src/api/oauth/mod.rs:167-174 |
| 代码入口 | TinyshipApiStore / CampsiteApiStore / OAuthApiStore 存在但 从未构造;仅 __Secure-better-auth.session_token 硬编码 |
src/api/oauth/tinyship_store.rs:15、campsite_store.rs、api_store.rs |
| 代码入口 | Chat HTTP 已挂载;Notes 仅 sync_state | src/api/api_router.rs:42、:56;src/api/notes/note_router.rs |
| 代码入口 | chat-migrate CLI 三处注册 |
src/commands/mod.rs:1、:37、:46 |
| 数据/状态 | 无本地 users 表(已 drop);身份为 username 字符串 + 可选外部 id |
m20251026_065433_drop_user_table(migration/mod.rs:61、:153) |
| 数据/状态 | Chat / Notes 表经多迁移落地;通知种子含 chat.mention.created / chat.reply.created |
m20260529_*、m20260324_*notes*、m20260630_000000_seed_notification_event_types;triggers.rs:26-27 |
| CLI 命令 | service / config / chat-migrate 等 |
src/commands/mod.rs |
| HTTP API | /api/v1/chat/*、/organizations/{org}/notes/{id}/sync_state、/api/v1/user/* |
chat_router.rs、note_router.rs、user_router.rs |
| 配置项 | OAuthConfig 仅 allowed_cors_origins;toml 中 campsite_api_domain / tinyship_api_domain / api_store_backend 为遗留忽略键;存在完整 [chat] |
src/config/model.rs:426-432、:436;config/config.toml:169-187、:354 |
| 配置项 | sidebar 默认含 chat / notes(Docs) | config/config.toml:277-278;SidebarConfig(model.rs:1011) |
| 错误类型 | 会话拒绝走 AuthRedirect;应用层主错误仍为 MegaError |
src/api/oauth/mod.rs;src/common/errors/ |
| 迁移 | fn migrations() 注册链含 note/chat/seed |
src/jupiter/migration/mod.rs:123 起 |
| 文档 | chat 独立改进文档仍在(开工前);无 website-auth 事实源 | 重构目录 chat 独立文档(DOC-01 删除);docs/plan/plan-long.md PT-10/PT-12 |
| 测试 | chat router 黑盒 / chat-migrate exec / chat 通知 triggers 依赖 stub admin |
chat_router.rs tests;triggers.rs ~1117+ |
| 工作区前置 | 版本面 0.1.183;../orbit path 依赖 |
Cargo.toml:6;bin/Cargo.toml:3 |
| 工作区前置 | IT compose 有 postgres/redis/mailpit/rustfs/git-cli/mega2;无 website next-app | docker-compose.test.yml;docs/refactoring/test-infra.md |
| 数据/状态 | 通知以 email_jobs 为 outbox;EmailDispatcher email primary 成功后才扇出 in-app/Slack/webhook |
src/notification/dispatcher.rs;src/mail/;config/config.toml [mail] |
| 外部参照 | website libs/email:仅认证验证/重置密码事务邮件(Resend/Cloudflare);无产品通知 outbox、无对外 send API |
website libs/email/、libs/auth/auth.ts(核对日 2026-07-31) |
| 外部参照 | website mega2 @ afcd69af:Better Auth 1.4.10,GET /api/auth/get-session,cookie better-auth.session_token / __Secure-…;无 username 列,展示名为 name |
website libs/auth/auth.ts;apps/next-app/app/api/auth/[...all]/route.ts(核对日 2026-07-31) |
| 外部参照 | website 自有 docker-compose.yml 仅 profile next/nuxt/tanstack,不接入 mega2-it 网络 |
website docker-compose.yml;apps/next-app/Dockerfile(端口 7001) |
| 外部参照 | Mega demo compose 将前端 + mono + 数据面同栈(形态参照,非移植对象) | mega/docker/demo/docker-compose.demo.yml |
| 外部参照 | Mega 已接线真实 SessionUser + tinyship/campsite store(对照实现) |
mega/mono/src/api/oauth/mod.rs SessionUser |
| ID | 缺口 | 影响 | 证据 | 计划动作 |
|---|---|---|---|---|
| GAP-01 | 浏览器会话为硬编码 admin | 任意客户端以 admin 身份调用 /api/v1;无法对接 website |
oauth/mod.rs:167-174 |
AU-03、AU-05 |
| GAP-02 | [oauth] 遗留键未类型化、store 未注入 |
PT-10 死配置;无法配置 website 基址 | OAuthConfig 仅 CORS;toml 遗留键 |
AU-02 |
| GAP-03 | Campsite 双后端与 tinyship 单 cookie 名 | 与「website 唯一 IdP」冲突;本地 HTTP cookie 名不匹配 | campsite_store.rs;tinyship_store.rs:15 |
AU-03 |
| GAP-04 | LoginUser.campsite_user_id 命名遗留 |
GPG/API 契约仍用 Campsite 品牌 | oauth/model.rs:58;gpg_router.rs:36 |
AU-04 |
| GAP-05 | Chat / Notes 产品面在本仓完整存在 | 与 website 职责重复;扩大维护面 | src/chat/、api/notes/、migrations |
RM-01..RM-06 |
| GAP-06 | chat 通知事件与种子仍在 | 退场后残留 event type / 模板 / 测试 | triggers.rs:26-27;seed migration |
RM-03、RM-05 |
| GAP-07 | 无 website-auth 单一事实源文档 | 部署/CORS/cookie 域约定无法引用 | docs/refactoring/ 无 website-auth.md |
AU-01 |
| GAP-08 | mega2-it 无 website apps/next-app 服务;会话只能 mock |
无法对真实 Better Auth + cookie 做栈级 IT;与 Mega「前后端同栈」联调能力不对等 | docker-compose.test.yml 无 next-app;website compose 孤立 |
ITW-01..ITW-03 |
| GAP-09 | 本仓自持 SMTP/[mail]/email_jobs 邮件投递;website 仅有认证事务邮件且无产品通知 API;compose 仍暴露 MEGA_MAIL__* 与「本仓→Mailpit」文档门 |
与「邮件通知归 website」冲突;双份凭据与模板;删 email 通道会拖死 in-app/Slack(email-primary);IT/文档与代码退场不同步 | src/mail/;dispatcher primary;docker-compose.test.yml MEGA_MAIL__ENABLED;docs/development.md / integration.md Mailpit 门;website libs/email |
MN-01..MN-06;DEP-06 |
| 计划/文档 | 关系 | 本计划处理 |
|---|---|---|
plan-long.md |
PT-10([oauth] 落地)、PT-12(账户语义)、原则 11;chat 原属「当前基础」独立改进 |
DOC-01 更新状态与日期索引;chat 退出「当前基础」 |
plan-20260727.md |
PT-01 已完成;测试基建可复用 | 不重做;ITW 新服务必须走 test-infra.md 登记(与 IT-01 同源规范) |
docs/refactoring/test-infra.md |
compose 新服务唯一登记入口 | ITW-01 按 checklist 登记 website-next |
| chat 独立改进文档(已删) | 原 chat 改进事实源 | DOC-01 删除并改引本计划 |
docs/refactoring/notification.md |
chat 触发器登记 | RM-03 / DOC-01 同步删除 chat 段 |
docs/refactoring/config.md |
[oauth] / [chat] |
AU-02、RM-04 同步 |
Mega docker/demo/docker-compose.demo.yml |
前后端同栈形态参照 | 只借鉴拓扑;不引入 moon/campsite/MySQL |
website docker-compose.yml |
产品侧 next/nuxt/tanstack profiles | IT 路径以本仓 docker-compose.test.yml 为准;不整仓迁入 |
website libs/email |
认证事务邮件现状;产品通知邮件缺口 | DEP-06 要求 website 增补内部邮件/通知 API;MN 链消费 |
docs/refactoring/mail.md / notification.md |
本仓邮件与通知事实源 | MN / DOC-01 改写为「邮件在 website;本仓无 SMTP」 |
docs/refactoring/test-infra.md / docs/development.md / 根 README.md |
compose 服务表与本地 IT 操作手册仍写本仓 SMTP/Mailpit 门 | MN-06 与 DOC-01 必须同步;mailpit 登记消费方改为 website(若保留) |
docker-compose.test.yml / .env.test(.example) / CI |
MEGA_MAIL__ENABLED、MAILPIT_*、workflow 启 mailpit 作本仓 SMTP |
MN-06 改接线;禁止留下「mega2 直连 Mailpit」的默认路径 |
AGENTS.md / README.md |
工程门禁 | 遵守;若描述仍含 chat 子命令 / 本仓 SMTP 则 DOC-01 登记或修订 |
| 维度 | 结论 | 修订动作 |
|---|---|---|
| 合理性 | chat/notes 产品面属 website;本仓保留重复后端违反单一职责;会话 stub 阻断真实集成 | 无 |
| 可行性 | 信任路径已有 Tinyship 草稿与 Mega 对照;删除轴可按表面→模块→DROP 切片 | 无 |
| 任务卡粒度 | AU / RM 按配置→接线→重命名→测试与表面→通知→模块→迁移→sidebar 切开;无 L/XL | 成稿按 G-* 审计 |
| 依赖与顺序 | 两主链:AU-01→…→AU-05 与 AU-01→RM-01→…→RM-06;汇合 DOC-01→REL-01;AU 与 RM 实现写集不相交可并发 | 见实施顺序 |
| 完整性 | 含设计文档、配置、API、迁移、测试、plan-long、minor 发布 | 无 |
| 安全性 | fail-closed 会话;禁生产旁路;保留 token/SSH;ban 拒绝 | ADR-WA-01 |
| 功能正确性 | 字段映射与空 name 回退已决议;DROP forward-only | ADR-WA-02/05 |
| 接口兼容 | 删除公开 chat/notes API + 重命名 JSON 字段 → minor | ADR-WA-06 |
| 数据流与控制流 | 每请求 cookie introspection;不缓存会话于 mega2(本计划) | DEFER-WA-02 |
| 性能与容量 | get-session 为每请求外呼;后续可加短 TTL 缓存 | DEFER-WA-02 |
| 可靠性与容错 | website 不可达 → 会话拒绝;Git token 路径独立 | 风险表 |
| 可维护性 | website-auth.md 为会话单一事实源;禁止回流 Campsite store |
AU-01 |
| 日期 | 触发 | 变更内容 | 原卡 → 新卡 | 受影响的引用 |
|---|---|---|---|---|
| 2026-07-31 | 成稿 | 首版:Website IdP 接入 + chat/notes 整栈删除 | N/A |
全文 |
| 2026-07-31 | 需求补录 | 增补 website apps/next-app 进入 mega2-it compose,与现有栈同启做会话集成测试(ADR-WA-07;任务 ITW-01..ITW-03;GAP-08) |
N/A → ITW-01, ITW-02, ITW-03 |
文档职责、缺口、ADR、实施顺序、依赖表、Phase、粒度审计、测试矩阵、里程碑、风险、延后项、完成判据 |
| 2026-07-31 | 需求补录 | 本仓去掉全部邮件投递,改用 website 邮件通知(ADR-WA-08;任务 MN-01..MN-06;GAP-09;DEP-06);修订 ADR-WA-05 对 email_job_attachments 的保留表述 |
N/A → MN-01..MN-06 |
文档职责、缺口、ADR、实施顺序、依赖表、Phase、RM-04/05、粒度审计、测试矩阵、里程碑、风险、延后项、完成判据、plan-long PT-09 |
| 2026-07-31 | 需求补录 | 邮件退场必须同步更新 docker-compose.test.yml、.env.test*、CI 与相关文档(ADR-WA-08 §7;强化 MN-05/MN-06/DOC-01) |
MN-06 扩写 |
ADR-WA-08、GAP-09、关系表、Phase 2b、MN-01/05/06、DOC-01、测试矩阵、完成判据 |
| 2026-07-31 | review R6 | Codex FAIL:全族 REL-WA-01(子卡 family child,REL-01 唯一 minor 发布点);AU-05→RM-01/AU-05→MN-02 闭合 G-10;ADR-WA-06 声明无弃用窗口 |
independent → family child |
ER-04、REL 表、并发声明、粒度审计、任务卡、ADR-WA-06、Review log |
| 2026-08-06 | 完成度复审(post-completion review) | ① AU-03:FixedUserSessionStore 补 #[cfg(test)] 门控(对齐 website-auth.md 约束)并实跑补证 VER-4 冒烟;② AU-04:为 gpg_router 增补 focused 测试,消除空跑 VER;③ RM-02/RM-04/MN-03:清理磁盘上遗留的空目录残壳(src/api/notes、src/chat{,/service}、src/contract/api/chat、src/mail、src/email);④ ITW-01:登记收口后 website IT 账户库 SQLite→隔离 Postgres website 库的演进注记;⑤ MN-01:website-mail.md 实现基线补 2026-08-06 pin 增补(CI pin a52d703…→2af89c8…);⑥ DOC-01:修复 augmentcode.md 悬空 chat.md 引用并加现状注记;⑦ MN-02 保留渠道的两个 transport-error 脱敏测试(slack/webhook)在配置了系统级 HTTP 代理的主机上假失败(代理把死端口的连接拒绝转成自身 HTTP 5xx,测试落入 HTTP 状态分支)——测试改用显式 .no_proxy() 客户端恢复确定性,生产客户端的代理行为不变 |
N/A |
AU-03/AU-04/ITW-01/DOC-01 注记、src/api/oauth/api_store.rs、src/api/router/gpg_router.rs、src/notification/channels/{slack,webhook}.rs(仅 #[cfg(test)])、docs/refactoring/{website-mail,augmentcode}.md |
| 2026-07-31 | review R5 | Codex 计划审查 FAIL:闭合 G-10(ITW-02→MN-05、ITW-03→MN-06);AU-01 deps=DEP-01;MN-06 VER=6/12;REL-01 审计 AC=4/12;Review log 合法化 |
ITW-01→MN-05 → ITW-02→MN-05;+ ITW-03→MN-06 |
实施顺序、发布窗口、并发声明、粒度审计、MN-05/06、AU-01、Review log |
实现时若需偏离本节,必须先修改计划并说明原因,不得在代码中静默改语义。
- Status: Accepted
- Context: 账户系统在 website(Better Auth);本仓
SessionUser为硬编码 admin;Campsite/Tinyship 双后端死代码与「website 唯一 IdP」冲突。 - Decision: 浏览器身份只信任 website Better Auth。mega2 不签发 session cookie。删除
CampsiteApiStore与api_store_backend双后端。信任路径:读 Cookie →WebsiteSessionStore::load_user→GET {oauth.website_api_base_url}/api/auth/get-session(转发完整 signed cookie 名=值)→ 映射LoginUser。同时支持 cookie 名better-auth.session_token与__Secure-better-auth.session_token。无 cookie / 非成功 / 空 body /user.banned=true→AuthRedirect。删除硬编码 admin stub。测试仅允许注入FixedUserSessionStore(或等价 test double),禁止生产旁路开关。 - Alternatives considered: 共享 website DB 直接读 session 表(拒绝——耦合与密钥边界);签发本仓 JWT(拒绝——本计划非目标,见 DEFER-WA-01);保留 Campsite 后端(拒绝——与架构决议冲突)。
- Consequences:
service http必须能解析website_api_base_url;跨站 cookie 需同站/父域/反代,文档必须写清。 - Revisit when: 需要机机身份或会话缓存时(DEFER-WA-01/02)。
- Status: Accepted
- Context: website
user无username列;本仓全域以username为 actor / PK;GPG 使用外部 id 字段。 - Decision:
Website user |
LoginUser |
用途 |
|---|---|---|
id |
website_user_id(由 campsite_user_id 重命名) |
GPG 等外部 id |
name |
username |
Git actor、SSH/token/CLA/prefs、Cedar principal |
email |
email |
通知 settings 首次创建 |
image |
avatar_url |
/user 回显 |
banned |
(不入结构体) | true → 拒绝会话 |
role |
(不入结构体) | 管理权仍以 mono.admin + Cedar 为准 |
name 为空时用 email 的 local-part;仍空则拒绝会话并 warn。username 唯一性由 website 展示名治理负责;本仓不新增 users 表。
- Alternatives considered: 在 mega2 维护 username 映射表(拒绝——重复账户系统);用 email 作 username(拒绝——破坏现有 username 键语义与 Git actor 习惯)。
- Consequences: 展示名碰撞可能导致 actor 混同;须在
website-auth.md写明运营约束。 - Revisit when: website 引入稳定 unique handle 字段时。
- Status: Accepted
- Context: Git CLI 无法携带 Better Auth cookie;现有
access_token/ SSH 已服务协议路径。 - Decision:
| 通道 | 机制 | 本计划 |
|---|---|---|
/api/v1 浏览器 |
Cookie → website get-session | 落地 |
| API Bearer | Mono access_token → AccessTokenUser |
保留 |
| Bot | bot_ Bearer → BotIdentity |
保留 |
| Git HTTP / LFS | Bearer 或 Basic password = token | 保留 |
| SSH | 公钥 → ssh_keys.username |
保留 |
/api/v1/user 的 SSH/token/CLA/prefs 保留;仅 LoginUser 来源变为 website session(或显式 AccessTokenUser 处保持 token 解析)。
- Alternatives considered: 删除
/user设置 API、改由 website 代理(拒绝——SSH/token 是引擎职责)。 - Consequences: 文档须明确「浏览器会话 ≠ Git 凭据」;用户仍须在 mega2 生成 access token 供 Git 使用。
- Revisit when: website 代发 mono access token 的产品流程落地时。
- Status: Accepted
- Context: PT-10 要求
[oauth]落地或清理;当前仅 CORS 被消费。 - Decision:
OAuthConfig扩展并真正消费:allowed_cors_origins、website_api_base_url: String(service http启动路径必填,validate fail-closed)、session_cookie_names: Vec<String>(默认上述两个 Better Auth 名)。删除遗留忽略键campsite_api_domain、tinyship_api_domain、api_store_backend。同步 validate / reload / source / testing 与config/config.toml。 - Alternatives considered: 整段删除
[oauth](拒绝——仍需 CORS 与 website 基址);环境变量硬编码基址(拒绝——破坏 config 单一事实源)。 - Consequences: 旧 toml 含遗留键时 validate 必须拒绝或显式迁移说明(本卡选择:拒绝未知/遗留键,与现有严格校验风格一致,若当前为 whitelist-ignore 则改为删除键并更新示例)。
- Revisit when: 多 website 环境(staging/prod)需 profile 覆盖时(已有 profile 机制,无需改 ADR)。
- Status: Accepted(2026-07-31 修订:邮件表退场改由 MN-04,不再要求永久保留
email_job_attachments) - Context: chat/notes 产品面归属 website;本仓整栈(API/CLI/实体/迁移链)为重复建设。
- Decision: 按 RM 链卸表面 → 卸通知 → 删模块/实体/配置 → 新 migration
DROPchat/notes 相关表(含 chat foundations 引入且无非 chat 消费方的attachments、open_graph_links)。ER-02(2026-08-01):reactions仍被 CL/Issue conversation 消费(conversation_storage/cl_service/issue_service/conv_router),不得 DROP;因reactions.custom_reaction_id依赖custom_reactions,亦不得 DROPcustom_reactions(DEFER:日后若 conversation 反应迁表再议)。历史 migration 文件保留。新迁移同时删除chat.*notification event type 行。删除[chat]/ChatConfig;sidebar 去掉 chat 与 notes(Docs)。email_jobs/email_job_attachments不在本 ADR DROP 范围——由 ADR-WA-08 / MN-04 退场。 - Alternatives considered: 仅 feature-flag 隐藏 API(拒绝——死代码仍在);保留表只删代码(拒绝——用户要求整栈删除)。
- Consequences:
Rollback mode: forward-only;生产 DROP 前须备份。RM-04/RM-05 验收不得再要求「永久保留 email_job_attachments」。 - Revisit when: 无。
- Status: Accepted(2026-07-31 修订:breaking 列表追加邮件表面删除)
- Context: 删除公开 HTTP 表面并重命名
LoginUserJSON 字段;另删除邮件投递表面。 - Decision: 本计划发布点
Version increment: minor。发布说明必须列出 breaking:/api/v1/chat/*与 notes sync 移除、campsite_user_id→website_user_id、无 cookie 不再隐式 admin、chat-migrate子命令移除、[chat]与遗留 oauth 键移除、[mail]/ SMTP //admin/email-jobs//admin/mail-templates/email_jobs表移除。 - Alternatives considered: patch 夹带(拒绝——破坏兼容,违反 ER-08)。
- Consequences: REL-01 唯一 minor bump;家族子卡
N/A。 - Revisit when: 无。
- Deprecation window (G-11): 无单独弃用窗口。依据:本仓 chat/notes 为未接线产品面(GAP-05;硬编码
admin);[mail]/email-jobs 随 ADR-WA-08 整栈迁出。兼容告知 = REL-01 发布说明 + minor bump(ADR-WA-06 breaking 列表);RM-01/RM-02/MN-03 直接删除,不设 shim。若后续需要 shim,须修订本 ADR 并拆卡。
- Status: Accepted
- Context: 会话接入若只有 mock,无法证明真实 Better Auth cookie ↔ mega2 路径。Mega demo(
mega/docker/demo/docker-compose.demo.yml)已证明「前端 + 后端 + 数据面」同栈联调价值;mega2 对应前端是 websiteapps/next-app,不是 moon/campsite。website 自有 compose 与mega2-test-net隔离,无法直接做跨服务 IT。 - Decision:
- 在本仓
docker/docker-compose.test.yml新增服务website-next(profiles: ["web"]),build context 为 sibling../website,dockerfileapps/next-app/Dockerfile(与orbit/mega2Dockerfile 的 sibling 约定一致);加入默认网络mega2-test-net;宿主映射127.0.0.1:17001:7001。 - 不把 Mega moon/campsite/MySQL 拉进本栈;形态对标 Mega demo,资产对标 website。
- website-next 账户库:IT 默认容器内 SQLite(Dockerfile 已支持),与 mega2 Postgres 库隔离(满足「引擎不读 website 表」);禁止与
mega2业务库混库。(2026-08-06 注记:收口后已由plan-20260803期间的 mega239f7433演进为共享postgres服务上的隔离website库——隔离目标与「禁止混用业务库」不变,本条 SQLite 表述为收口日快照,现行拓扑见test-infra.mdwebsite-next 条目与 ITW-01 执行后注记。) - 栈级联调命令:
docker compose -p mega2-it -f docker-compose.test.yml --profile app --profile web up -d --wait(数据面默认 up;app+web显式)。mega2环境注入MEGA_OAUTH__WEBSITE_API_BASE_URL=http://website-next:7001,CORS 含http://127.0.0.1:17001(及文档写明的其它 IT origin)。 - 必须按
docs/refactoring/test-infra.mdchecklist 登记(healthcheck、零残留、CI 入口、secret 注入);默认up -d --wait不拉起web(避免拖慢无前端需求的数据面循环)。 - 最小栈级验收:在 next-app 完成 sign-up/sign-in → 取得 session cookie → 请求 mega2
/api/v1/user→ 断言username/website_user_id与 get-session 一致(ITW-03)。
- 在本仓
- Alternatives considered: 仅用 FixedUser mock(拒绝——无法验真实 cookie/CORS);在 website 仓单独 compose 手动联调(拒绝——不进
cargo test/ CI 门);把 next-app 放进默认 up(拒绝——拖慢数据面);复用 Mega campsite 作 IdP(拒绝——与本计划 website IdP 决议冲突)。 - Consequences: ER-01 增补「会话栈 IT 需 sibling
../website」;CI 可选拉起--profile web;镜像构建耗时需写入性能预算;website 契约漂移由 DEP-01 + ITW-03 捕获。 - Revisit when: 需要 Postgres 版 website 账户库、或 E2E 浏览器(Playwright)全链路时(见 DEFER-WA-05)。
- Status: Accepted(2026-07-31 修订:强制 compose + 文档同步)
- Context: 本仓
EmailDispatcher以 email 为 primary outbox,扇出 in-app/Slack/webhook;[mail]/SMTP/lettre/Mailpit IT 自成体系。website 已有@libs/email(Resend/Cloudflare)但仅认证验证/重置密码,无产品通知 API。用户要求本仓去掉邮件通知,改用 website 邮件能力;且要求 docker compose 与相关文档一并更新,避免代码退场后 IT/手册仍指向本仓 SMTP。 - Decision:
- Website 是唯一出站邮件发送方(含认证事务邮件 + 本仓产品事件触发的通知邮件)。
- mega2 删除全部邮件投递表面:
src/mail/(及孤儿src/email/)、EmailChannel、[mail]/MailConfig、mail.passwordsecret 字段、admin/email-jobs/*与/mail-templates*、实体/表email_jobs与email_job_attachments、依赖lettre(若无其它引用);禁止再以 Mailpit 作为本仓 SMTP 验收门。 - 编排仍可留在本仓: CL/issue/reference 等 triggers 保留;不再
enqueue_email_job/ 渲染本仓 mail TOML 模板发信。改为调用 website 内部认证 API(契约由 MN-01 固化),例如POST /api/internal/notifications/email(或等价),body 含event_type、to、locale、模板变量或预渲染字段;鉴权用共享 bearer(配置项,非浏览器 cookie)。Website 用@libs/email发送并扩展产品模板。 - Dispatcher 去 email-primary:
NotificationService启动不得依赖[mail];若保留 in-app/Slack/webhook,primary 改为in_app(或「无 primary、各通道独立」——开工选一并写进 MN-02;默认 primary = in_app)。用户 prefs 中delivery_mode=email改为「请求 website 发信」或迁移为in_app(MN-02 写清兼容窗口;默认:email模式映射为「调用 website + 仍写 in-app」)。 - Chat 邮件随 RM-03 删除,不迁到 website(chat 产品面已退场)。
- 禁止本仓再直连 Resend/Cloudflare/SMTP(避免双份凭据)。
- Compose + 环境 + 文档强制同步(与代码同里程碑,不得后补):
docker-compose.test.yml: 删除mega2服务上全部MEGA_MAIL__*(含MEGA_MAIL__ENABLED);mega2不得depends_on: mailpit。mailpit去留: 默认保留服务(便于 website-next 认证/产品邮件在 IT 中 SMTP 捕获);在test-infra.md明确 消费方 = website(或 profileweb),不是 mega2。若 DEP-06/website IT 确认不需要 SMTP 捕获,可改为profiles: ["mail"]或删除——须在 MN-06 写清并改文档/CI;禁止留下「本仓 SmtpMailer→Mailpit」的默认说明。website-next(ITW): 需要发信验收时,注入 SMTP→mailpit:1025(或 website 既有测试 provider env);注入 mega2→website 邮件 API 所需的内部 bearer / base URL 与mega2侧notification.website_mail_*(或 MN-01 定名)对称。.env.test/.env.test.example:MAILPIT_*若保留,注释改为「website IT 捕获」;删除「本仓[mail]/mail.passwordseed」步骤;新增 website mail client / bearer 的 IT 占位(无真实生产 secret)。- CI(
.github/workflows/): 去掉本仓 SMTP/mail.password强制门;mailpit 启动仅在 website 邮件 IT 或显式 profile 需要时保留,并在 workflow 注释写明用途。 - 文档清单(MN-06 主改,DOC-01 复核):
docs/refactoring/website-mail.md、mail.md(废止)、notification.md、config.md、test-infra.md、integration.md、docs/development.md、根README.md的[mail]/SMTP 章节、plan-long.mdPT-09;OpenAPI/运维若仍写 email-jobs 一并清。
- Alternatives considered: 仅把
mail.provider=http指到 website 而保留email_jobs(拒绝——用户要求去掉本仓邮件通知/outbox);把整个 notification 迁 website(拒绝——CL/issue 事件源在本仓,范围过大);裸删 EmailChannel 不改 primary(拒绝——拖死扇出);只改 Rust 代码、compose/文档后补(拒绝——用户明确要求同步更新)。 - Consequences: 依赖 DEP-06(website API 可用)才能绿 MN-05/MN-06;PT-09 邮件对齐改为「投递在 website」;minor breaking 见 ADR-WA-06;MN-06 写集含 compose/env/docs,粒度仍为 M(与测试改写同卡,避免文档漂移)。
- Revisit when: website 侧出现完整用户通知中心后,可再评估是否下沉 triggers(DEFER-WA-07);mailpit 是否从默认 up 集挪到
profiles: ["mail"](运维成本权衡)。
以下约束对本文所有任务生效。任务条目不再逐条重复,违反任一项即视为任务未完成。
- GC-01 现状核实前置: 每个任务开工前重新核对计划、相关开发文档、当前代码和测试。如果已实现,则任务改为补测试、补文档、更新状态或关闭,不重复实现。
- GC-02 单一事实源: entity 定义、配置解析、API schema、权限策略、错误类型和共享 helper 必须有单一事实源。禁止 CLI handler、HTTP handler、migration 和测试 fixture 各自复制等价逻辑。会话信任路径的事实源为
docs/refactoring/website-auth.md(AU-01 产物)。 - GC-03 Mega 目标项目与 mega2 扩展边界: SessionUser 接线可对照 Mega
mono/src/api/oauth/,但 IdP 固定为 website(非 Campsite);差异必须写在website-auth.md。 - GC-04 输出与错误契约: 用户可见错误使用
MegaError稳定变体并同步docs/errors.md。HTTP 状态码、JSON 响应、CLI 退出码和人读输出必须分别验收。 - GC-05 文档同步: 命令、配置、HTTP API 或公开行为变化必须同步对应
docs/、config/config.toml注释与必要时README.md。OpenAPI 证据取自运行中的/api/openapi.json。 - GC-06 测试覆盖: 新增 / 改动的 storage / migration / 会话解析必须有 focused 测试;删除表面必须有零命中守卫。
- GC-07 安全默认值: 会话路径 fail-closed;禁止生产环境隐式 admin。Cedar 仍为 permit-all 现状时,不得把「授权已生效」写进验收假说。
- GC-08 原子性与恢复: DROP 迁移 forward-only;发布后不可 revert schema。
- GC-09 并发与资源生命周期: website HTTP 客户端须有超时;测试注入 store 不得泄漏跨用例全局状态。
- GC-10 性能预算: 本计划接受每请求 get-session 外呼;禁止在 handler 内无界重试。
- GC-11 生产 panic 禁止: 生产路径不得新增裸
unwrap()/expect()/panic!();TinyshipApiStore::new现有expect在迁到WebsiteSessionStore时必须改为可返回错误或启动期MegaResult。 - GC-12 精确提交: 只
libra add <相关路径>;本仓无.git。
本文执行检查条目 ER-01..ER-12 与 docs/plan/plan-template.md v2 全文一致(含 A/B/C/D 门、Lifecycle/Acceptance、签名、版本面、并发发布规则)。执行时以模板正文为准;下列为本计划现状补记(不削弱模板):
- compose 项目名统一
-p mega2-it(与plan-20260727/test-infra.md对齐)。 - 会话相关单元测试若需 mock website,不得依赖真实外网;使用进程内
FixedUserSessionStore,避免新依赖。 - **栈级会话 IT(ITW-*)**额外要求 sibling checkout
../website(与../orbit同级);缺失时 ITW 卡置blocked,不得用 mock 冒充 ITW-03 验收。
执行后注记(2026-08-21 前端仓库改指): 本计划全部
../website/genedna/website锚点与cd ../website && …验证命令均为收口日快照,不作改写。 联调栈的前端自 2026-08-21 起改指gitmono-dev/monoui的mega2分支 (sibling../monoui);WE-02..WE-06 的实现已逐文件移植到该仓,契约不变。 现行事实源见../refactoring/website-auth.md§头部 与../refactoring/website-mail.md的 2026-08-21 增补。
.env.test仍按AGENTS.md:缺失则停止询问,不得静默跳过 source。
- 本计划采用单一家族发布
REL-WA-01: 全部implementation/removal/migration卡为family child of REL-WA-01;唯一发布点为REL-01(family release point,Version increment: minor,ADR-WA-06)。 - 子卡:
Version increment: N/A;Release write set: N/A;C/D coverage from: REL-01;本地可至locally-accepted,不得在 REL-01 前将Acceptance=complete或推送。 AU-01/DOC-01/MN-01为no-release,产物随 REL-01 进仓;C/D 继承REL-01。- 删除公开 API 的卡在发布说明中必须引用 ADR-WA-06 breaking 列表(由 REL-01 聚合)。
- ITW/MN 卡改动
docker-compose.test.yml/ workflow 时,D 组按 paths 命中登记;未命中则写 N/A(由 REL-01 继承执行)。
全文适用 plan-template.md 的 G-01..G-11、Verification 判定口径、字段默认与 waiver 白名单。本计划无 EX-* waiver。
依赖边格式:A -> B 表示 A 必须先于 B。
DEP-01 -> AU-01AU-01 -> AU-02AU-02 -> AU-03AU-03 -> AU-04AU-04 -> AU-05AU-05 -> RM-01RM-01 -> RM-02RM-02 -> RM-03RM-03 -> RM-04RM-04 -> RM-05RM-05 -> RM-06AU-01 -> ITW-01ITW-01 -> ITW-02AU-03 -> ITW-02ITW-02 -> ITW-03AU-05 -> ITW-03AU-05 -> DOC-01RM-06 -> DOC-01ITW-03 -> DOC-01AU-01 -> MN-01MN-01 -> MN-02AU-05 -> MN-02RM-03 -> MN-02MN-02 -> MN-03MN-03 -> MN-04MN-04 -> MN-05DEP-06 -> MN-05ITW-02 -> MN-05MN-05 -> MN-06ITW-03 -> MN-06MN-06 -> DOC-01DOC-01 -> REL-01
| ID | direction | 类型 | 对象 | Owner | 产物与可用性判据 | 证据 | 超时与失败策略 |
|---|---|---|---|---|---|---|---|
| DEP-01 | incoming | 外部服务 / 上游 revision | website 仓库 mega2 分支 Better Auth get-session 契约 |
website 维护者 | GET /api/auth/get-session 返回 user/session JSON 形状稳定;cookie 名符合 ADR-WA-01 |
website libs/auth/ @ 核对日 2026-07-31;pinned 时在 AU-01 文档记录 revision |
契约变更则先改 AU-01/ADR 再改代码;不得猜测字段 |
| DEP-02 | incoming | 跨计划 | plan-long.md PT-10 / PT-12 / PT-09 |
本计划 DOC-01 | 日期索引与状态可写 | docs/plan/plan-long.md |
DOC-01 内更新;冲突时以本计划 ADR 为准并在 plan-long 注明 |
| DEP-03 | outgoing | 跨计划 | PT-12 全量前端对照审计 | 后续日期计划 | 本计划不交付功能对照表 | PT-12 章节 | 接收方未接手则保持候选;本计划不阻塞 |
| DEP-04 | outgoing | 延后 | DEFER-WA-01/02/05/07 | 后续计划 | JWT/会话缓存/浏览器 E2E/通知中心下沉 | 本文件「非目标与延后项」 | 无 |
| DEP-05 | incoming | 外部 checkout | sibling ../website(ITW/MN 构建与联调) |
执行 Agent | 目录存在且含 apps/next-app/Dockerfile;分支为 mega2(或 AU-01 文档 pinned revision) |
同 ../orbit 约定;website docker-compose.yml / Dockerfile |
缺失则 ITW-* / MN-05+ blocked;不得用 mock 关闭 ITW-03 / MN-06 |
| DEP-06 | incoming | 跨仓实现 | website:内部邮件/通知发送 API + 产品事件邮件模板(基于 @libs/email) |
已由 plan-20260802.md 交付(WE-02..WE-06;website tip a52d703) |
MN-01 契约路径/鉴权/JSON 可调用;IT 返回 2xx(EMAIL_PROVIDER=test) |
website POST /api/internal/notifications/email;mega2 integration_website_mail |
已关闭;本仓不得回退 SMTP |
| ID | 成员 | 唯一发布点 | 窗口规则 | 失败回滚顺序 | 理由 |
|---|---|---|---|---|---|
| REL-WA-01 | AU-01..AU-05, RM-01..RM-06, ITW-01..ITW-03, MN-01..MN-06, DOC-01;发布点 REL-01 | REL-01 | 窗口内禁止独立 patch 推送;子卡只本地提交/review 至 locally-accepted;唯一 minor bump+推送在 REL-01;窗口禁止插入无关 breaking | 子卡代码/文档 revert(RM-05/MN-04 仅备份前滚);未推送则整族回退 | chat/notes/mail/oauth 公开 surface 与 schema 删除必须同窗口 minor 收口(G-08);docs 子卡 no-release |
并发声明: 同链串行。跨链仅在写集不相交时允许:AU-* 与纯 docs 可交错;禁止 AU 与 RM/MN 并行(共享 src/config/、config/config.toml、src/api/、src/lib.rs、http_server)。G-10 闭合边: AU-05 -> RM-01;AU-05 -> MN-02;ITW-02 -> MN-05;ITW-03 -> MN-06;RM-03 -> MN-02。不得以 rebase 代替依赖边。
发布者: 单一 Agent/人负责 REL-01 的 C/D 组(家族唯一推送点)。
发布窗口顺序: AU → ITW → RM → MN → DOC-01 → REL-01(禁止子卡独立 bump/推送)。
目标: website-auth.md 成为会话接入单一事实源(含 compose 拓扑);website-mail 契约落盘(MN-01)。
进入条件: ER-01;DEP-01 契约已核对。
退出条件: AU-01 与 MN-01 locally-accepted + review PASS(complete 继承 REL-01)。
目标: 真实 SessionUser + 类型化 [oauth] + 字段重命名 + 进程内验收测试。
进入条件: AU-01 review PASS。
退出条件: AU-05 locally-accepted + review PASS(Acceptance=complete 仅随 REL-01)。
目标: website-next 登记进 mega2-it;与 mega2 同启;真实 cookie 黑盒绿。
进入条件: AU-01 review PASS;DEP-05(../website)就位;AU-03 对 ITW-02 已满足。
退出条件: ITW-03 locally-accepted + review PASS(complete 随 REL-01)。
目标: 表面→通知→模块→DROP→sidebar 完成。
进入条件: AU-05 locally-accepted(禁止与 AU 实现并行;见 G-10)。
退出条件: RM-06 locally-accepted + review PASS(complete 随 REL-01)。
目标: dispatcher 去 email-primary;删除本仓 mail 表面与 email 表;产品事件经 website 发信;同步更新 compose / .env.test* / CI;测试与文档去「本仓→Mailpit」门。
进入条件: MN-01 review PASS;RM-03 locally-accepted(chat 邮件触发器已删);DEP-06 对 MN-05 可用;ITW-02 locally-accepted(compose 写集已交给 MN-05);AU-05 locally-accepted。
退出条件: MN-06 locally-accepted + review PASS(含 compose 与文档清单全勾;complete 随 REL-01)。
目标: plan-long / 重构文档 / test-infra / mail+notification 同步;minor 发布。
进入条件: AU-05、ITW-03、RM-06、MN-06 均已 locally-accepted 且 review PASS。
退出条件: REL-01 Acceptance=complete(家族子卡随之 complete);计划完成判据清单勾选。
- Release boundary 默认:
family child of REL-WA-01(实现/删除/迁移卡);docs=no-release;REL-01=family release point of REL-WA-01 - Task type 默认: implementation
- Rollback mode 默认: revert
- Migration and rollback 默认: N/A
- Security and privacy 默认: 继承 GC-07、GC-11;会话 fail-closed
- Performance budget 默认: 继承 GC-10
- Docs and compatibility impact 默认: 按 GC-05 同步相关 docs 与 config 示例
默认覆盖:
| 任务 | 偏离的字段 | 取值与理由 |
|---|---|---|
| AU-01, DOC-01, MN-01 | Release boundary / Version increment / Release write set | no-release / N/A / N/A;C/D from REL-01 |
| AU-02..AU-05, RM-01..RM-06, ITW-01..ITW-03, MN-02..MN-06 | Release boundary / Version / Release write set / C/D | family child of REL-WA-01 / N/A / N/A / from REL-01 |
| REL-01 | Release boundary | family release point of REL-WA-01;minor |
| RM-03(若含删种子数据的 migration 片段) | 见 RM-03/RM-05 | event type 删除可并入 RM-05 migration |
| RM-05 | Rollback mode / Task type / Version increment | forward-only / migration / N/A(breaking 聚合在 REL-01 minor) |
| MN-04 | Rollback mode / Task type | forward-only / migration |
| ITW-01 | Docs and compatibility impact | 必须同步 test-infra.md(compose 登记) |
| MN-06 | Docs and compatibility impact | 必须同步 compose + .env.test* + test-infra/development/integration/mail/notification/README(ADR-WA-08 §7) |
| REL-01 | Task type / Version increment | release / minor |
规则 waiver: 无。
| 任务 | type | axis | recovery | complete | self-contained | AC | VER | landing / prod-files | scope | deps | writeset | release | split-from | exception |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| AU-01 | docs | website-auth 设计落盘 | revert 文档 | yes | yes | 7/20 | 3/20 | 1/1 | S | DEP-01 | no-overlap | no-release | N/A | N/A |
| AU-02 | implementation | OAuthConfig 类型化 | revert | yes | yes | 6/8 | 4/8 | 2/6 | M | AU-01 | no-overlap | REL-WA-01 child | N/A | N/A |
| AU-03 | implementation | SessionUser 真接通 | revert | yes | yes | 7/8 | 4/8 | 3/8 | M | AU-02 | 序列化于 AU-02 | REL-WA-01 child | N/A | N/A |
| AU-04 | implementation | website_user_id 重命名 | revert | yes | yes | 4/8 | 3/8 | 2/5 | M | AU-03 | 序列化于 AU-03 | REL-WA-01 child | N/A | N/A |
| AU-05 | implementation | 会话验收测试 | revert | yes | yes | 5/8 | 3/8 | 1/3 | S | AU-04 | 序列化于 AU-04 | REL-WA-01 child | N/A | N/A |
| ITW-01 | implementation | website-next compose 登记 | revert | yes | yes | 6/8 | 4/8 | 2/3 | M | AU-01, DEP-05 | no-overlap | REL-WA-01 child | N/A | N/A |
| ITW-02 | implementation | 同栈 oauth/CORS 接线 | revert | yes | yes | 5/8 | 3/8 | 2/4 | M | ITW-01, AU-03 | 序列化于 ITW-01 | REL-WA-01 child | N/A | N/A |
| ITW-03 | implementation | 真实 cookie 栈级黑盒 | revert | yes | yes | 5/8 | 5/8 | 1/2 | M | ITW-02, AU-05 | 序列化于 ITW-02 | REL-WA-01 child | N/A | N/A |
| RM-01 | removal | Chat HTTP/CLI 退场 | revert | yes | yes | 7/8 | 4/8 | 4/10 | M | AU-05 | no-overlap | REL-WA-01 child | N/A | N/A |
| RM-02 | removal | Notes API 退场 | revert | yes | yes | 5/8 | 3/8 | 2/4 | S | RM-01 | 序列化于 RM-01 | REL-WA-01 child | N/A | N/A |
| RM-03 | removal | Chat 通知退场 | revert | yes | yes | 5/8 | 3/8 | 2/4 | M | RM-02 | 序列化于 RM-02 | REL-WA-01 child | N/A | N/A |
| RM-04 | removal | 模块/实体/ChatConfig 删除 | revert | yes | yes | 5/8 | 3/8 | 4/12 | M | RM-03 | 序列化于 RM-03 | REL-WA-01 child | N/A | N/A |
| RM-05 | migration | DROP chat/notes 表 | forward-only | yes | yes | 5/8 | 3/8 | 2/3 | M | RM-04 | 序列化于 RM-04 | REL-WA-01 child | N/A | N/A |
| RM-06 | implementation | Sidebar 默认清理 | revert | yes | yes | 3/8 | 2/8 | 2/2 | S | RM-05 | 序列化于 RM-05 | REL-WA-01 child | N/A | N/A |
| MN-01 | docs | website 邮件契约落盘 | revert 文档 | yes | yes | 7/20 | 3/20 | 1/1 | S | AU-01 | no-overlap | no-release | N/A | N/A |
| MN-02 | implementation | dispatcher 去 email-primary | revert | yes | yes | 6/8 | 4/8 | 3/8 | M | MN-01, RM-03, AU-05 | no-overlap | REL-WA-01 child | N/A | N/A |
| MN-03 | removal | 删除 mail 模块与 admin 邮件 API | revert | yes | yes | 7/8 | 4/8 | 4/12 | M | MN-02 | 序列化于 MN-02 | REL-WA-01 child | N/A | N/A |
| MN-04 | migration | DROP email_jobs 表 | forward-only | yes | yes | 4/8 | 3/8 | 2/3 | M | MN-03 | 序列化于 MN-03 | REL-WA-01 child | N/A | N/A |
| MN-05 | implementation | triggers 改调 website 邮件 API | revert | yes | yes | 6/8 | 3/8 | 4/8 | M | MN-04, DEP-06, ITW-02 | 序列化于 ITW-02 | REL-WA-01 child | N/A | N/A |
| MN-06 | implementation | compose/测试/CI/文档去本仓邮件门 | revert | yes | yes | 8/8 | 5/8 | 6/10 | M | MN-05, ITW-03 | 序列化于 ITW-03 | REL-WA-01 child | N/A | N/A |
| DOC-01 | docs | 长期/重构文档收口 | revert 文档 | yes | yes | 9/20 | 4/20 | 8/8 | M | AU-05, RM-06, ITW-03, MN-06 | no-overlap | no-release | N/A | N/A |
| REL-01 | release | minor 发布点 | immutable-release | yes | yes | 5/12 | 2/12 | 0/0 | S | DOC-01 | N/A | REL-WA-01 point | N/A | N/A |
Task type: docs
Lifecycle / Acceptance: done / complete
Description: 新建 docs/refactoring/website-auth.md,把 ADR-WA-01..04 与 ADR-WA-07 的信任路径、字段映射、双轨认证、配置键、CORS/cookie 域、mega2-it + website-next 同栈拓扑、失败语义、测试 double 与栈级 IT 协议写成可执行事实源。
Out of scope:
- 不改代码或配置(由 AU-02 / ITW-01 承接)
- 不写 chat 删除设计(由 RM 卡 / ADR-WA-05 承接)
Current evidence:
| 事实 | 证据 |
|---|---|
| 无 website-auth 文档 | ls docs/refactoring/ 无该文件 |
| Better Auth get-session 契约 | website libs/auth/(DEP-01) |
| 本仓 stub / 死 store | oauth/mod.rs:167-174;tinyship_store.rs |
| IT 栈无 next-app | docker-compose.test.yml;GAP-08 |
Acceptance criteria:
本卡 AC/VER 于 2026-09-15 据实回填勾选(AU-01 早已随 REL-01 / v0.2.x 落地,其余各卡均已勾选,仅 AU-01/AU-02 两张遗漏)。证据取自当前
docs/refactoring/website-auth.md;文中 sibling 仓已按 2026-08-21 更名合法演进为 website application checkout(apps/web),角色名website与派生标识按plan-long.md术语条不改名。
-
docs/refactoring/website-auth.md存在且含:信任路径图或等价步骤、字段映射表、双轨表、配置键、cookie 名、失败语义、测试 double 规则 —— §1 信任路径(:21)、§2 字段映射(:76)、§3 双轨认证(:95)、§5 配置键(:126-128) - 文档含 compose 同栈拓扑(服务名
website-next、profileweb、端口17001、MEGA_OAUTH__WEBSITE_API_BASE_URL容器内 URL、与 Mega demo 的差异说明) ——:141-146拓扑表(服务名、build context、宿主映射127.0.0.1:17001:7001)、:126容器内 URLhttp://website-next:7001 - 文档记录 website 核对 revision / 日期(DEP-01) ——
:14核对日 2026-09-04、sibling website application checkout(apps/web) - 明确禁止生产旁路与 Campsite 回流 ——
:48-51「生产路径禁止」列明配置/环境变量旁路 get-session 与恢复CampsiteApiStore/api_store_backend双后端 - 明确 chat
attachments与(将由 MN-04 DROP 的)email_job_attachments区分;不在 AU-01 要求永久保留邮件表 ——:220「chat 域表attachments≠ 邮件 outbox 表email_job_attachments」 - 内部链接可解析;不引入悬空
docs/*.md路径 —— 存在性检查通过 -
libra status无越界生产代码改动 —— 落地当时结论;本次回填只改本计划文件
Verification:
-
test -f docs/refactoring/website-auth.md—— 存在 - 章节标题守卫:
rg -n '信任路径|字段映射|双轨|session_cookie|FixedUser|banned|website-next|profile web' docs/refactoring/website-auth.md(须有命中) —— 24 处命中 -
libra status --short --branch变更仅限本卡 Deliverables —— 落地当时结论
Dependencies: DEP-01
Deliverables: docs/refactoring/website-auth.md
Implementation write set: docs/refactoring/website-auth.md
Release write set: N/A
Files likely touched: docs/refactoring/website-auth.md
Docs and compatibility impact: 新建开发文档
Rollback mode: revert
Migration and rollback: N/A
Security and privacy: 文档须强调 cookie 转发与 redaction(日志不得打印完整 session token)
Performance budget: N/A
Estimated scope: S
Version increment: N/A
Release boundary: no-release
C/D coverage from: REL-01
Granularity: type=docs; axis=website-auth设计落盘; recovery=revert文档; complete=yes; self-contained=yes; AC=7/20; VER=3/20; landing=1; prod-files=1; scope=S; deps=DEP-01; writeset=no-overlap; release=no-release; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 将 [oauth] 扩展为可消费的 website_api_base_url + session_cookie_names,删除 Campsite/Tinyship 遗留忽略键,并让 config validate / service http 启动路径在缺失基址时 fail-closed。
Out of scope:
- 不接线 SessionUser(由 AU-03 承接)
- 不删 chat 配置(由 RM-04 承接)
Current evidence:
| 事实 | 证据 |
|---|---|
OAuthConfig 仅 CORS |
src/config/model.rs:426-432 |
| toml 遗留键 | config/config.toml:184-187 |
Acceptance criteria:
本卡 AC/VER 于 2026-09-15 据实回填勾选;证据取自当前
src/config/、config/config.toml。
-
OAuthConfig含website_api_base_url、session_cookie_names(默认两 Better Auth 名)、allowed_cors_origins——src/config/model.rs:469,473,475-479(session_cookie_names经default_session_cookie_names()提供默认两名) - 遗留键
campsite_api_domain/tinyship_api_domain/api_store_backend从示例与校验白名单中移除,出现则校验失败或不再被忽略(与现有严格度对齐,开工选一种并测) ——rg 'campsite_api_domain|tinyship_api_domain|api_store_backend' config/config.toml src/config/零命中 -
service http在基址为空时启动失败(可操作错误) ——src/config/validate.rs:160-173:service http requires [oauth] with oauth.website_api_base_url (see docs/refactoring/website-auth.md) -
config validate对默认示例配置通过 —— 落地当时结论 - validate/reload/source/testing 同步 ——
src/config/validate.rs:151调用点已接入 -
config/config.toml注释指向website-auth.md——config/config.toml:174
Verification:
-
cargo run -p mega2 -- --config config/config.toml config validate—— 落地当时结论 - 缺
website_api_base_url的临时配置:config validate或service http非零退出 —— 落地当时结论;判定点仍在src/config/validate.rs:160-173 -
rg -n 'campsite_api_domain|tinyship_api_domain|api_store_backend' config/config.toml src/config零命中(按 Verification 判定口径区分 rg 退出码) —— 2026-09-15 复跑:rc=1(零命中) -
source .env.test && cargo test -p mega2-core 'config::'—— 落地当时结论;package 已由plan-20260824ORB-06 重命名,今日等价命令为cargo test -p mega2 --lib 'config::'
Dependencies: AU-01
Deliverables: N/A
Implementation write set: src/config/、config/config.toml(及本卡测试)
Release write set: N/A
Files likely touched: src/config/model.rs、validate.rs、reload.rs、source.rs、testing.rs、config/config.toml
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=OAuthConfig类型化; recovery=revert; complete=yes; self-contained=yes; AC=6/8; VER=4/8; landing=2; prod-files=6; scope=M; deps=AU-01; writeset=no-overlap; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
执行后注记(2026-08-06 完成度复审):
BrowserSessionStore::Fixed/FixedUserSessionStore原为无条件编译(仅构造点在#[cfg(test)]内),与website-auth.md「test double 不得编译进默认service http生产二进制路径」的约束存在字面偏差;复审已将变体、结构体与 match 分支统一加#[cfg(test)]门控,生产二进制自此不含该 double。VER-4 冒烟亦于复审日补证(见勾选注)。
Description: 将 tinyship store 演进为 WebsiteSessionStore,支持双 cookie 名与 ban 拒绝,注入 API state,恢复与 Mega 同类的 Cookie→get-session SessionUser;删除 campsite_store 与双后端 enum。
Out of scope:
- 不重命名
campsite_user_id字段(由 AU-04 承接) - 不改 Git token 路径
Current evidence:
| 事实 | 证据 |
|---|---|
| SessionUser stub | oauth/mod.rs:167-174 |
| Tinyship 单 cookie | tinyship_store.rs:15 |
| Mega 对照 | mega/mono/src/api/oauth/mod.rs SessionUser |
Acceptance criteria:
-
WebsiteSessionStore(或最终模块名)实现 get-session 调用;双 cookie 名 -
banned=true映射为未认证(拒绝) -
SessionUser从 state 取 store 并读 Cookie;无 cookie →AuthRedirect -
campsite_store.rs删除;无OAuthApiStore::Campsite分支 -
http_server/MonoApiServiceState注入 store;CORS 仍用allowed_cors_origins - 生产路径无硬编码 admin
- 客户端构造无裸
expect(GC-11)
Verification:
-
rg -n 'admin@gitmono\.test|campsite_store|CampsiteApiStore' src/api/oauth零命中(口径模板) -
source .env.test && cargo test -p mega2-core 'api::oauth' -
cargo build -p mega2-core0 警告 0 错误(本卡中间门;完整三门在 C 组) - OpenAPI/服务启动冒烟:带配置的
service http能绑定端口(手工 sanitized;2026-08-06 完成度复审补证:隔离库 + 全新MEGA_BASE_DIR下service http绑定127.0.0.1:18973并 200 返回/api/openapi.json,SIGINT 退出,临时库已 drop)
Dependencies: AU-02
Implementation write set: src/api/oauth/、src/api/mod.rs、src/server/http_server.rs(及相关测试)
Release write set: N/A
Rollback mode: revert
Security and privacy: 日志禁止打印完整 session token;外呼超时有界
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=SessionUser真接通; recovery=revert; complete=yes; self-contained=yes; AC=7/8; VER=4/8; landing=3; prod-files=8; scope=M; deps=AU-02; writeset=序列化于AU-02; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
执行后注记(2026-08-06 完成度复审): 原 VER
cargo test -p mega2-core 'api::router::gpg'在收口时命中 0 个用例(gpg_router 无测试模块,命令空跑通过,属幽灵验收);重命名本身由零命中守卫与编译门真实保障。复审已在src/api/router/gpg_router.rs增补 focused 测试(路由注册断言 +website_user_id序列化 pin /campsite_user_id缺席断言),该 VER 现命中 2 个用例并通过。
Description: 将 LoginUser.campsite_user_id 重命名为 website_user_id,更新 From 映射、gpg_router 与全部引用。
Out of scope:
- 不改会话接线逻辑(AU-03)
- 不改 username 映射规则(ADR-WA-02 已定,仅改字段名)
Current evidence:
| 事实 | 证据 |
|---|---|
| 字段名 | oauth/model.rs:58 |
| GPG 使用 | gpg_router.rs:36、:56、:75 |
Acceptance criteria:
- 结构体字段与 JSON 序列化为
website_user_id - website/Campsite JSON From 实现写入新字段
-
gpg_router与测试全部改用新字段 -
rg campsite_user_id src零命中
Verification:
- 零命中守卫:
rg -n 'campsite_user_id' src(口径模板) -
source .env.test && cargo test -p mega2-core 'api::oauth' -
source .env.test && cargo test -p mega2-core 'api::router::gpg'
Dependencies: AU-03
Implementation write set: src/api/oauth/model.rs、src/api/router/gpg_router.rs、其它命中引用文件
Release write set: N/A
Docs and compatibility impact: breaking JSON 字段;REL-01 聚合说明
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=website_user_id重命名; recovery=revert; complete=yes; self-contained=yes; AC=4/8; VER=3/8; landing=2; prod-files=5; scope=M; deps=AU-03; writeset=序列化于AU-03; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 用 FixedUserSessionStore(或等价)覆盖成功会话、无 cookie、banned、空 name 回退/拒绝;更新原依赖硬编码 admin 的非 chat 测试(chat 测试由 RM-01 删除)。
Out of scope:
- 不测真实外网 website(DEP-01 契约已在文档固定)
- 不测 chat router(RM-01 删除)
- 不做 compose 同栈真实 next-app 黑盒(由 ITW-03 承接;本卡仅 FixedUser / 进程内)
Current evidence:
| 事实 | 证据 |
|---|---|
| 多处测试假定 admin | chat_router tests 等;AU-03 后其它路由器可能受影响 |
Acceptance criteria:
- 新增 focused 用例:有效 FixedUser → handler 见到对应用户
- 无 cookie → 拒绝
- banned → 拒绝
- 空 name + 有 email → username=local-part;空 name 且无可用 email → 拒绝
- 非 chat 的既有 API 测试不再依赖隐式 admin stub(改为 FixedUser 或 AccessTokenUser)
Verification:
-
source .env.test && cargo test -p mega2-core 'api::oauth' -- --nocapture - 新用例名过滤守卫:输出含本卡新增测试名且 ok
-
rg -n 'admin@gitmono\.test' src零命中(或仅允许website-auth.md/ 注释白名单——若有白名单须在卡内写明;默认零命中)
Dependencies: AU-04
Implementation write set: src/api/oauth/ 测试、受影响非 chat router 测试
Release write set: N/A
Rollback mode: revert
Estimated scope: S
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=会话验收测试; recovery=revert; complete=yes; self-contained=yes; AC=5/8; VER=3/8; landing=1; prod-files=3; scope=S; deps=AU-04; writeset=序列化于AU-04; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: removal
Lifecycle / Acceptance: done / complete
Description: 从路由、OpenAPI、http state、chat-migrate CLI 卸载 chat 表面;src/chat 模块可暂留到 RM-04,但不得再被 API/CLI 引用。
Out of scope:
- 不删实体/表(RM-04/RM-05)
- 不删通知触发器(RM-03)
Current evidence:
| 事实 | 证据 |
|---|---|
| router merge | api_router.rs:56 |
| chat-migrate 注册 | commands/mod.rs:37、:46 |
| chat_events state | http_server.rs:582;api/mod.rs:49 |
Acceptance criteria:
- 符合 ADR-WA-06:无单独弃用窗口;breaking 由 REL-01 发布说明覆盖(本卡不设 shim)
-
api_router不再 mergechat_router - OpenAPI 无 chat tag/路径
-
chat-migrate从builtin/builtin_exec/load_mode三处移除 -
MonoApiServiceState无chat_events/ channel chat helpers -
cli::tests/commands::断言无chat-migrate - chat_router 文件可先删除或变为未引用(推荐本卡直接删
chat_router.rs以减噪音)
Verification:
-
rg -n 'chat_router|chat-migrate|chat_events|InMemoryChatEvents' src/api src/commands src/server零命中 -
cargo test -p mega2-core 'cli::tests' -
cargo test -p mega2-core 'commands::' - 启动后
/api/openapi.json无/chat(sanitized 证据)
Dependencies: AU-05
Implementation write set: src/api/api_router.rs、src/api/mod.rs、src/api/router/、src/api/api_doc.rs、src/commands/、src/server/http_server.rs
Release write set: N/A
Docs and compatibility impact: breaking API/CLI;REL-01 说明
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=removal; axis=Chat HTTP/CLI退场; recovery=revert; complete=yes; self-contained=yes; AC=7/8; VER=4/8; landing=4; prod-files=10; scope=M; deps=AU-05; writeset=no-overlap; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: removal
Lifecycle / Acceptance: done / complete
Description: 卸载 src/api/notes 路由与模块注册。
Out of scope:
- 不删 notes 实体/表(RM-04/RM-05)
Current evidence:
| 事实 | 证据 |
|---|---|
| note_router merge | api_router.rs:42 |
api/notes/ |
note_router.rs、model.rs |
Acceptance criteria:
- 符合 ADR-WA-06:无单独弃用窗口;breaking 由 REL-01 发布说明覆盖(本卡不设 shim)
-
api_router不再 merge notes -
src/api/notes/删除 - OpenAPI 无 notes sync_state 路径
-
api::测试无 notes 引用失败
Verification:
-
rg -n 'note_router|api::notes|notes::' src/api零命中 -
cargo test -p mega2-core 'api::' -- --nocapture - OpenAPI 无
sync_statenotes 路径
Dependencies: RM-01
Implementation write set: src/api/notes/、src/api/api_router.rs、src/api/mod.rs
Release write set: N/A
Rollback mode: revert
Estimated scope: S
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=removal; axis=Notes API退场; recovery=revert; complete=yes; self-contained=yes; AC=5/8; VER=3/8; landing=2; prod-files=4; scope=S; deps=RM-01; writeset=序列化于RM-01; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: removal
Lifecycle / Acceptance: done / complete
Description: 从 notification/triggers.rs 删除 chat mention/reply 事件常量、ensure、入队、邮件模板键与测试;event type 种子行的 DB 清理并入 RM-05 migration(本卡只清代码)。
Out of scope:
- 不 DROP 表(RM-05)
- 不删 inbox 通用通知
Current evidence:
| 事实 | 证据 |
|---|---|
| 事件常量 | triggers.rs:26-27 |
| 测试 | triggers.rs ~1117+ |
Acceptance criteria:
- 无
EVENT_CHAT_*/on_chat_*/ chat mail template keys - 相关单元测试删除
-
notification.md中 chat 段删除或改「已移除」可由 DOC-01 收口;本卡至少去掉代码引用 - 非 chat 通知测试仍绿
-
rg 'chat\.mention|chat\.reply|EVENT_CHAT' src/notification零命中
Verification:
- 零命中守卫(上条路径)
-
source .env.test && cargo test -p mega2-core 'notification::' -
source .env.test && cargo test -p mega2-core 'notification::triggers'
Dependencies: RM-02
Implementation write set: src/notification/triggers.rs(及同模块测试)
Release write set: N/A
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=removal; axis=Chat通知退场; recovery=revert; complete=yes; self-contained=yes; AC=5/8; VER=3/8; landing=2; prod-files=4; scope=M; deps=RM-02; writeset=序列化于RM-02; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: removal
Lifecycle / Acceptance: done / complete
Description: 删除 src/chat/、contract/api/chat、chat/notes 相关 storage 与 callisto 模块注册、ChatConfig/[chat]、lib.rs 的 mod chat;保持历史 migration 文件。
Out of scope:
- 不 DROP 物理表(RM-05)
- 不改 sidebar 默认(RM-06)
Current evidence:
| 事实 | 证据 |
|---|---|
pub mod chat |
lib.rs:15 |
ChatConfig |
model.rs:50、:436 |
| callisto 实体 | channel.rs、message.rs、notes.rs 等 |
Acceptance criteria:
-
src/chat/、src/contract/api/chat/、src/commands/chat_migrate.rs删除 - callisto 去掉 chat/notes 实体 mod;storage mod 去掉对应字段/模块
-
[chat]与ChatConfig删除;config 测试更新 -
cargo build --tests通过(表仍在 DB,但代码无引用) -
rg -n 'ChatConfig|pub mod chat|channel_storage|note_storage' src零命中(允许 migration 历史文件命中)
Verification:
- 零命中守卫(限定
src/chat、src/contract/api/chat、src/config生产路径) -
cargo build --tests0 错误 0 警告 -
cargo run -p mega2 -- --config config/config.toml config validate
Dependencies: RM-03
Implementation write set: src/chat/、src/callisto/、src/jupiter/storage/、src/contract/api/、src/config/、src/lib.rs、config/config.toml
Release write set: N/A
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=removal; axis=模块实体ChatConfig删除; recovery=revert; complete=yes; self-contained=yes; AC=5/8; VER=3/8; landing=4; prod-files=12; scope=M; deps=RM-03; writeset=序列化于RM-03; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: migration
Lifecycle / Acceptance: done / complete
Description: 新增 m20260731_*_drop_chat_and_notes:DROP chat/notes 相关表(不含 reactions / custom_reactions,见 ADR-WA-05 ER-02);DELETE chat.* notification event types;在 migrations() 登记;附 apply_migrations 集成测试。down 为 no-op。
Out of scope:
- 不 DROP
user_inbox_notifications(in-app 保留) - 不在本卡 DROP
email_jobs/email_job_attachments(由 MN-04 承接)
Current evidence:
| 事实 | 证据 |
|---|---|
| 表经 chat/notes 迁移创建 | migration/mod.rs 注册行 |
| 种子含 chat 事件 | m20260630_000000_seed_notification_event_types |
Acceptance criteria:
- 新 migration 在
migrations()末尾登记(若 MN-04 已合入则按时间戳排序,不得打乱历史链) - DROP 列表覆盖:channels、channel_memberships、channel_membership_updates、messages、message_notifications、attachments、open_graph_links、notes、note_views、non_member_note_views
- 明确不 DROP:
reactions、custom_reactions(ER-02:CL/Issue 仍用reactions;FK 保留custom_reactions) - 删除
chat.mention.created/chat.reply.createdevent type 行(及依赖 prefs 行若有 FK) -
down显式 no-op;文档/卡内写明 forward-only - 集成测试:空库 up 后相关表不存在
Verification:
-
source .env.test && cargo test 'migration::runner::tests::test_drop_chat_and_notes_schema' -
rg -n 'm20260731_.*drop_chat' src/jupiter/migration/mod.rs有命中 - 守卫:本卡 DROP 语句不包含
email_jobs(留给 MN-04)
Dependencies: RM-04
Implementation write set: src/jupiter/migration/(新文件 + mod.rs)及测试
Release write set: N/A
Rollback mode: forward-only
Migration and rollback: up=DROP/DELETE;down=no-op;生产前备份;恢复=从备份前滚或建新库
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=migration; axis=DROP chat/notes表; recovery=forward-only备份恢复; complete=yes; self-contained=yes; AC=5/8; VER=3/8; landing=2; prod-files=3; scope=M; deps=RM-04; writeset=序列化于RM-04; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 从 config/config.toml 与 SidebarConfig::default 移除 chat 与 notes(Docs) 默认项。
Out of scope:
- 不迁移已有 DB 中动态 sidebar 行(既有部署可用 API 清理;见 DEFER-WA-03)
Current evidence:
| 事实 | 证据 |
|---|---|
| toml sidebar | config/config.toml:277-278 |
| Default | SidebarConfig(model.rs:1025 起) |
Acceptance criteria:
- 默认配置无
public_id = "chat"/ notes→/notesDocs 项 -
SidebarConfig::default一致 - config 测试更新
Verification:
-
rg -n 'public_id = \"chat\"|/notes' config/config.toml src/config/model.rs按预期零命中(或仅历史注释——默认零命中) -
cargo run -p mega2 -- --config config/config.toml config validate
Dependencies: RM-05
Implementation write set: config/config.toml、src/config/model.rs
Release write set: N/A
Rollback mode: revert
Estimated scope: S
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=Sidebar默认清理; recovery=revert; complete=yes; self-contained=yes; AC=3/8; VER=2/8; landing=2; prod-files=2; scope=S; deps=RM-05; writeset=序列化于RM-05; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
执行后注记(2026-08-06 完成度复审): 收口后(
plan-20260803期间,mega239f7433)website IT 账户库已由「容器内 SQLite」切换为共享postgres服务上的隔离website库(website-db-init+drizzle-kit push),满足本卡 AC4 的「或等价隔离库」口径与 ADR-WA-07 的隔离目标(禁止混用mega2业务库不变);本卡与 ADR-WA-07 描述中的「IT 默认 SQLite」自此按收口日快照阅读,现行拓扑以test-infra.mdwebsite-next 条目为准。
Description: 按 test-infra.md checklist 在 docker-compose.test.yml 新增 website-next(profile web),build sibling ../website 的 apps/next-app/Dockerfile,加入 mega2-test-net,宿主 127.0.0.1:17001:7001,IT 默认 SQLite 账户库;同步 test-infra.md 登记条目。
Out of scope:
- 不接线 mega2 oauth 环境变量(由 ITW-02 承接)
- 不写会话黑盒用例(由 ITW-03 承接)
- 不迁入 website 产品 compose 的 nuxt/tanstack
Current evidence:
| 事实 | 证据 |
|---|---|
| 无 website-next 服务 | docker-compose.test.yml |
| website Dockerfile 端口 7001 | ../website/apps/next-app/Dockerfile |
| 登记规范 | docs/refactoring/test-infra.md |
Acceptance criteria:
-
website-next服务存在,profiles: ["web"],不参与默认up -d --wait - build context / dockerfile 指向 sibling website;
pull_policy与本地/CI 策略写明 - healthcheck 可判定就绪(至少 TCP 或 HTTP 探活到 next 进程;具体命令开工按 Dockerfile 固化)
- IT 账户库为容器内 SQLite(或等价隔离库),不使用
mega2业务库名/URL -
test-infra.md新增「website-next」登记表(含 profiles、端口、清理、CI 入口草案) -
docker compose -p mega2-it -f docker-compose.test.yml --profile web up -d --wait website-next在 DEP-05 满足时可健康
Verification:
-
rg -n 'website-next|profiles: \[\"web\"\]' docker-compose.test.yml -
rg -n 'website-next' docs/refactoring/test-infra.md -
bash -c 'test -d ../website/apps/next-app && test -f ../website/apps/next-app/Dockerfile' -
docker compose -p mega2-it -f docker-compose.test.yml --profile web up -d --wait website-next成功后down(含--profile web)
Dependencies: AU-01, DEP-05
Implementation write set: docker-compose.test.yml、docs/refactoring/test-infra.md(及本卡所需的 IT env 示例片段,若有)
Release write set: N/A
Rollback mode: revert
Security and privacy: IT 凭据仅用公开测试值;不把生产 .env 打进镜像层
Performance budget: 首次镜像构建允许较长 wall-clock;登记建议上限(开工写定,建议 ≤ 20min CI)
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=website-next compose登记; recovery=revert; complete=yes; self-contained=yes; AC=6/8; VER=4/8; landing=2; prod-files=3; scope=M; deps=AU-01,DEP-05; writeset=no-overlap; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 在 --profile app --profile web 拓扑下,为 mega2 注入 MEGA_OAUTH__WEBSITE_API_BASE_URL=http://website-next:7001,CORS allowlist 含宿主映射 origin;保证容器内 mega2 能 get-session 到 website-next。
Out of scope:
- 不实现黑盒登录矩阵(ITW-03)
- 不改 AU-03 的 SessionUser 逻辑(仅消费)
Current evidence:
| 事实 | 证据 |
|---|---|
| mega2 服务块无 oauth website URL | docker-compose.test.yml mega2.environment |
| AU-02/03 落地后配置键可用 | 依赖 AU-03 |
Acceptance criteria:
- compose 中
mega2(或 profile 覆盖文件)含 website API 基址指向http://website-next:7001 - CORS /
allowed_cors_origins含http://127.0.0.1:17001(及文档列出的 IT origin) -
depends_on:mega2在启用 web 联调时等待website-nexthealthy(或文档写明启动顺序与重试) - 从 mega2 容器或同网络客户端对
http://website-next:7001/api/auth/get-session可得非连接错误响应(未登录可为 null) -
website-auth.md/test-infra.md同步该接线
Verification:
-
rg -n 'WEBSITE_API_BASE_URL|website-next:7001|17001' docker-compose.test.yml docs/refactoring -
docker compose -p mega2-it -f docker-compose.test.yml --profile app --profile web up -d --wait后,容器网络内 curl get-session 退出码 0(body 可为 null) -
docker compose -p mega2-it -f docker-compose.test.yml --profile app --profile web down -v
Dependencies: ITW-01, AU-03
Implementation write set: docker-compose.test.yml、docs/refactoring/test-infra.md、docs/refactoring/website-auth.md(接线节)
Release write set: N/A
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=同栈oauth/CORS接线; recovery=revert; complete=yes; self-contained=yes; AC=5/8; VER=3/8; landing=2; prod-files=4; scope=M; deps=ITW-01,AU-03; writeset=序列化于ITW-01; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 新增 bin/tests/integration_website_auth.rs(或等价 target):在 --profile app --profile web 已就绪前提下,对 website-next 执行 sign-up/sign-in,携带 session cookie 请求 mega2 /api/v1/user,断言身份字段与 get-session 一致;无 cookie 则拒绝。同步 integration 覆盖矩阵与 test-infra CI 入口(可 soft-skip 当 profile 未启,但 skip 不得冒充通过——须显式 WEBSITE_IT=1 或端口探测失败才 skip,且 CI 启用 web 时必须跑到 ok)。
Out of scope:
- 不做 Playwright 浏览器 E2E(DEFER-WA-05)
- 不测 chat/notes(已退场)
Current evidence:
| 事实 | 证据 |
|---|---|
| 现有栈级 smoke | integration_compose_mega2_http_smoke |
| 无 website 会话黑盒 | bin/tests/ 无对应 target |
Acceptance criteria:
- 新集成 target 存在且文档化前置(compose profiles、env)
- 用例:登录成功 →
/api/v1/user返回映射后的username/website_user_id - 用例:无 cookie → 会话路径拒绝(非 200 带 admin)
- CI:
config-validation.yml(或专段)在 sibling website 可用时拉起--profile web并跑本 target;不可用时 job 策略书面化(本卡选:要求 CI checkout website,与 orbit 类似,缺则失败) -
docs/refactoring/integration.md覆盖矩阵登记本 target
Verification:
-
source .env.test && WEBSITE_IT=1 cargo test -p mega2 --test integration_website_auth -- --test-threads=1(2026-08-01:live 运行通过) - 输出含本卡具名用例且 ok;禁止仅见 SKIP 当作通过(2026-08-01:1 passed)
-
rg -n 'integration_website_auth' docs/refactoring/integration.md docs/refactoring/test-infra.md
Dependencies: ITW-02, AU-05
Implementation write set: bin/tests/integration_website_auth.rs、.github/workflows/config-validation.yml(若改)、docs/refactoring/integration.md、docs/refactoring/test-infra.md
Release write set: N/A
Rollback mode: revert
Security and privacy: 测试用户邮箱/口令仅为 IT 抛掷值;日志脱敏 cookie
Performance budget: 单 target wall-clock 建议 ≤ 10min(含已构建镜像)
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=真实cookie栈级黑盒; recovery=revert; complete=yes; self-contained=yes; AC=5/8; VER=5/8; landing=1; prod-files=2; scope=M; deps=ITW-02,AU-05; writeset=序列化于ITW-02; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: docs
Lifecycle / Acceptance: done / complete
Description: 新建 docs/refactoring/website-mail.md(或作为 website-auth.md 专章——本卡选独立文件以免会话文档膨胀),固化 ADR-WA-08:website 内部邮件 API 路径/鉴权/JSON、本仓删除清单、dispatcher primary 迁移、与 auth 事务邮件的边界,以及 compose / mailpit / env 拓扑(消费方、端口、与会话 IT 的关系)。
Out of scope:
- 不改代码(MN-02+)
- 不在 website 仓实现 API(DEP-06;契约由本卡定义)
- 不直接改
docker-compose.test.yml(MN-05/MN-06 落地;本卡只定拓扑)
Current evidence:
| 事实 | 证据 |
|---|---|
| 本仓 email-primary | notification/dispatcher.rs;src/mail/ |
| website 仅认证邮件 | website libs/email/ |
| compose 仍挂本仓 mail env | docker-compose.test.yml MEGA_MAIL__ENABLED |
Acceptance criteria:
- 文档存在且含:API 路径与方法、鉴权(shared bearer)、请求/响应 JSON、错误码、幂等键建议
- 列出本仓 DELETE 清单与 KEEP(in-app/slack/webhook/triggers)
- 写明
delivery_mode=email兼容映射 - 写明 chat 邮件不迁(随 RM)
- 写明 compose 拓扑:
mailpit保留/profile 策略、mega2 去掉MEGA_MAIL__*、website-next SMTP→mailpit(若用)、mega2→website mail API 基址与 bearer 配置键 - 链接到
notification.md/mail.md/test-infra.md/development.md的「将废止或改写」要点 - 无悬空链接;无生产代码改动
Verification:
-
test -f docs/refactoring/website-mail.md -
rg -n 'internal/notifications|bearer|email_jobs|in_app|ADR-WA-08|mailpit|MEGA_MAIL|test-infra' docs/refactoring/website-mail.md -
libra status --short --branch仅本卡产物
Dependencies: AU-01
Deliverables: docs/refactoring/website-mail.md
Implementation write set: docs/refactoring/website-mail.md
Release write set: N/A
Rollback mode: revert
Estimated scope: S
Version increment: N/A
Release boundary: no-release
C/D coverage from: REL-01
Granularity: type=docs; axis=website邮件契约落盘; recovery=revert文档; complete=yes; self-contained=yes; AC=7/20; VER=3/20; landing=1; prod-files=1; scope=S; deps=AU-01; writeset=no-overlap; release=no-release; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 将通知编排与 [mail] 解耦;primary 改为 in_app(或文档选定的等价方案);triggers 停止依赖 mail 模板入队 email_jobs(可暂时只写 in-app / 跳过 email,website 调用在 MN-05 接上);NOTIFICATION_DELIVERY_MODES 更新。
Out of scope:
- 不删除
src/mail/文件(MN-03) - 不 DROP 表(MN-04)
- 不调用真实 website API(MN-05)
Current evidence:
| 事实 | 证据 |
|---|---|
启动依赖 [mail] |
context/mod.rs |
| 扇出在 email 成功后 | dispatcher.rs |
Acceptance criteria:
- 无
[mail]时仍可启动 in-app(及已配置的 slack/webhook)通知服务 - primary 不再是 email;email 成功不再是扇出门槛
- CL/issue/reference triggers 不再
enqueue_email_job(或该函数已删除且编译通过) - prefs:
delivery_mode=email有明确映射(见 MN-01)并有测试 - chat 触发器已不存在(依赖 RM-03)
-
notification::focused 测试更新且绿
Verification:
-
source .env.test && cargo test -p mega2-core 'notification::' -
rg -n 'enqueue_email_job|EmailChannel|primary.*email' src/notification按预期零命中或仅注释(默认零命中) - 无 mail 配置的启动冒烟(手工或单测):NotificationService 可 start
-
cargo build -p mega2-core0 警告 0 错误
Dependencies: MN-01, RM-03, AU-05
Implementation write set: src/notification/、src/context/mod.rs(启动路径)、相关 config delivery_mode
Release write set: N/A
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=dispatcher去email-primary; recovery=revert; complete=yes; self-contained=yes; AC=6/8; VER=4/8; landing=3; prod-files=8; scope=M; deps=MN-01,RM-03,AU-05; writeset=no-overlap; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: removal
Lifecycle / Acceptance: done / complete
Description: 删除 src/mail/、src/email/、EmailChannel、[mail]/MailConfig、mail.password secret 支持、admin email-jobs/mail-templates 路由与 OpenAPI;清理 lettre 依赖(若无残留引用)。
Out of scope:
- 不 DROP DB 表(MN-04)
- 不改 website(DEP-06)
Current evidence:
| 事实 | 证据 |
|---|---|
pub mod mail |
src/lib.rs |
| admin 路由 | admin_router.rs email-jobs / mail-templates |
config secret mail.password |
commands/config.rs |
Acceptance criteria:
- 符合 ADR-WA-06:无单独弃用窗口;breaking 由 REL-01 发布说明覆盖(本卡不设 shim)
-
src/mail/、src/email/删除;lib.rs无mod mail -
[mail]从 model/validate/template/config.toml 移除;含 mail 的配置 validate 失败或键被拒 - admin 无
/email-jobs、/mail-templates -
config secret不再支持mail.password -
Cargo.toml无仅服务于 mail 的lettre(若仍被其它模块使用则保留并注释理由) -
rg -n 'SmtpMailer|MailConfig|mail\\.password|/email-jobs' src config零命中(允许 migration/docs 历史)
Verification:
- 零命中守卫(上条)
-
cargo test -p mega2-core 'commands::config' -
cargo run -p mega2 -- --config config/config.toml config validate - OpenAPI 无 email-jobs / mail-templates(sanitized)
Dependencies: MN-02
Implementation write set: src/mail/、src/email/、src/lib.rs、src/api/router/admin_router.rs、src/config/、config/config.toml、Cargo.toml/Cargo.lock、src/commands/config.rs
Release write set: N/A
Docs and compatibility impact: breaking;REL-01 聚合
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=removal; axis=删除mail模块与admin邮件API; recovery=revert; complete=yes; self-contained=yes; AC=7/8; VER=4/8; landing=4; prod-files=12; scope=M; deps=MN-02; writeset=序列化于MN-02; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: migration
Lifecycle / Acceptance: done / complete
Description: 新增 migration DROP email_job_attachments、email_jobs;从 callisto/storage 移除实体与 API;down no-op。
Out of scope:
- 不 DROP
user_inbox_notifications - 不删历史创建这些表的旧 migration 文件
Current evidence:
| 事实 | 证据 |
|---|---|
| 表存在 | m20260224_*、m20260618_064500_* |
Acceptance criteria:
- 新 migration 登记于
migrations();DROP 顺序先 attachments 后 jobs(或等价 FK 安全顺序) - callisto/storage 无 email_jobs 实体引用
- 集成测试:up 后两表不存在
-
downno-op;forward-only
Verification:
-
source .env.test && cargo test -p mega2-core 'migration::runner::tests::test_drop_email_jobs_schema' -
rg -n 'email_jobs|email_job_attachments' src/callisto src/jupiter/storage零命中(允许 migration 历史目录) -
rg -n 'drop_email' src/jupiter/migration/mod.rs
Dependencies: MN-03
Implementation write set: src/jupiter/migration/、src/callisto/、src/jupiter/storage/
Release write set: N/A
Rollback mode: forward-only
Migration and rollback: up=DROP;down=no-op;生产前备份
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=migration; axis=DROP email_jobs表; recovery=forward-only备份恢复; complete=yes; self-contained=yes; AC=4/8; VER=3/8; landing=2; prod-files=3; scope=M; deps=MN-03; writeset=序列化于MN-03; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 实现 mega2 → website 内部邮件客户端(配置基址 + bearer);CL/issue/reference triggers 在需要邮件时调用该 API;失败可观测(日志/度量)且不阻断主请求(与现触发器异步语义对齐)。同步 compose: mega2 注入 website mail base URL + bearer(IT 测试值);website-next(若已存在)注入接收内部邮件所需的 env;需要 SMTP 捕获时 website-next→mailpit。契约与配置键写入 website-mail.md。
Out of scope:
- 不在本仓实现 SMTP
- 不删除
MEGA_MAIL__*/ 不改 Mailpit 登记文案的收口(MN-06;本卡可先加新 env,旧MEGA_MAIL__*由 MN-06 删除) - 不在 website 仓实现 API 若由他人交付——但契约测试可用 wire mock;栈级绿依赖 DEP-06
Current evidence:
| 事实 | 证据 |
|---|---|
| triggers 原 enqueue email | triggers.rs CL/issue 路径 |
| website 无产品 API | GAP-09 |
| compose 无 website mail 接线 | docker-compose.test.yml |
Acceptance criteria:
- 配置项存在(
notification.website_mail_base_url+ bearer / bearer ref)并校验 - CL comment/merge、issue comment/close、item referenced 在 prefs 要求邮件时调用 website API
- website 4xx/5xx 不导致 API handler 500(记录 warn/error;本卡选「best-effort + 日志」)
- IT/mock:至少一次成功调用断言
- compose(
--profile app --profile web)含 mega2→website mail 基址/bearer 占位;website-mail.md同步客户端配置键与 compose 变量名 - 日志不打印 bearer / 完整邮件 PII 超限字段
Verification:
-
source .env.test && cargo test -p mega2-core 'notification::triggers' -
rg -n 'website_mail|WEBSITE_MAIL|internal/notifications' src/notification src/config docker-compose.test.yml docs/refactoring/website-mail.md -
cargo run -p mega2 -- --config config/config.toml config validate
Dependencies: MN-04, DEP-06, ITW-02
Implementation write set: src/notification/、src/config/、config/config.toml、docker-compose.test.yml(新增 website mail 接线,可暂留旧 MEGA_MAIL__*)、docs/refactoring/website-mail.md
Release write set: N/A
Rollback mode: revert
Security and privacy: bearer 走 SecretRef;日志不打印 token/邮件全文 PII 超限字段
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=triggers改调website邮件API; recovery=revert; complete=yes; self-contained=yes; AC=6/8; VER=3/8; landing=4; prod-files=8; scope=M; deps=MN-04,DEP-06,ITW-02; writeset=序列化于ITW-02; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: implementation
Lifecycle / Acceptance: done / complete
Description: 按 ADR-WA-08 §7:同一卡完成 (1) 删除/改写依赖 SmtpMailer/Mailpit 本仓投递的用例;(2) 更新 docker-compose.test.yml / .env.test* / CI;(3) 更新相关文档。Mailpit 默认保留但消费方改为 website;mega2 去净 MEGA_MAIL__*。
Out of scope:
- 不删 in-app/slack/webhook 非邮件断言
- 不实现 Playwright
- 不完成 plan-long 全量收口(DOC-01 复核)
Current evidence:
| 事实 | 证据 |
|---|---|
| Mailpit 多渠道 IT | bin/tests/integration_vault.rs integration_multichannel_notification |
| mail password seed | integration_vault.rs seed_mail_password |
| compose 本仓 mail env | docker-compose.test.yml MEGA_MAIL__ENABLED: "false" |
| 开发手册本仓 SMTP | docs/development.md mailpit 表;根 README.md [mail] |
Acceptance criteria:
- 无测试要求本仓 SMTP 成功投递到 Mailpit
- fail-closed「缺 mail.password 进程退出」门删除或改为「无 [mail] 段仍可启动」
-
docker-compose.test.yml:mega2零MEGA_MAIL__*;不depends_on: mailpit -
mailpit:保留或改profiles: ["mail"](按 MN-01 拓扑);test-infra.md登记消费方 = website / 非 mega2 -
.env.test与.env.test.example:MAILPIT_* 注释改为 website IT(若保留);删除本仓mail.passwordseed 说明;含 website mail client IT 占位键(若 MN-05 已定名) - CI workflow:去掉仅服务于本仓 SMTP 的强制步骤;mailpit 用途注释与
test-infra.md一致 -
mail.md标明废止并链接website-mail.md;同时notification.md/integration.md/config.md/test-infra.md/docs/development.md/ 根README.md去掉「本仓 SmtpMailer→Mailpit /[mail]必配」现行门表述 -
rg守卫:生产路径与 compose 无MEGA_MAIL;文档允许「废止/历史」语境
Verification:
-
source .env.test && cargo test -p mega2 --test integration_vault -- --test-threads=1 -
rg -n 'MEGA_MAIL' docker-compose.test.yml零命中 -
rg -n 'Mailpit|seed_mail_password|SmtpMailer' bin/tests src/notification按 allowlist 审查 -
rg -n '废止|website-mail' docs/refactoring/mail.md docs/refactoring/notification.md docs/development.md -
docker compose -p mega2-it -f docker-compose.test.yml --profile app config成功且渲染结果无MEGA_MAIL
Dependencies: MN-05, ITW-03
Implementation write set: bin/tests/、docker-compose.test.yml、.env.test.example(及本地 .env.test 若入库策略允许只改 example)、.github/workflows/、docs/refactoring/{mail,notification,integration,config,test-infra,website-mail}.md、docs/development.md、根 README.md
Release write set: N/A
Rollback mode: revert
Docs and compatibility impact: breaking 运维面:无 [mail]、无本仓 Mailpit 门;见 ADR-WA-06 / REL-01
Estimated scope: M
Version increment: N/A
Release boundary: family child of REL-WA-01
C/D coverage from: REL-01
Granularity: type=implementation; axis=compose测试CI文档去本仓邮件门; recovery=revert; complete=yes; self-contained=yes; AC=8/8; VER=5/8; landing=6; prod-files=10; scope=M; deps=MN-05,ITW-03; writeset=序列化于ITW-03; release=family child of REL-WA-01; split-from=N/A; exception=N/A
Task type: docs
Lifecycle / Acceptance: done / complete
执行后注记(2026-08-06 完成度复审): 收口后入库的
docs/refactoring/augmentcode.md(mega2ad61934,2026-08-05;内容为 2026-06-21 快照)曾以现在时引用已删除的docs/refactoring/chat.md并把 chat/mail 描述为现状,使本卡「chat 文档零悬空引用」守卫(VER-2)在现行树上失效。复审已为该文件补「现状注记」头并把 chat.md 引用改标「已随 DOC-01 删除」;VER-2 的零命中口径自此排除历史快照类文档中已标注删除的提法。本卡收口日验收不受影响。
Description: 同步 plan-long.md(chat 退出、PT-10/12/09、日期索引)、删除 chat 独立改进文档、复核 MN-06/ITW 已改的 notification.md / mail.md / config.md / test-infra.md / integration.md / development.md / README.md、确认 website-auth.md + website-mail.md;更新 docs/plan/README.md。补齐 MN-06 未覆盖的遗漏交叉引用。
Out of scope:
- 不改生产代码 / 不改 compose(应已由 MN-06/ITW 完成;若发现漂移则开 FIX 或退回 MN-06)
- 不完成 PT-12 功能对照表(DEP-03)
Current evidence:
| 事实 | 证据 |
|---|---|
| chat 退出当前基础;日期索引含本计划 | plan-long.md 当前基础 / 日期计划索引 |
| PT-09 / PT-10 / PT-12 已注明本计划切片 | plan-long.md 总览与专章 |
| README 计划列表 | docs/plan/README.md |
Acceptance criteria:
-
plan-long.md日期索引含本计划;chat 不再列为在维护基础能力 - PT-10 注明
[oauth]由本计划落地 - PT-12 注明会话信任路径与 compose 同栈 IT 已由本计划实现,全量对照仍候选
- PT-09 注明本仓邮件投递已移除、投递归属 website(ADR-WA-08);compose/mailpit 消费方说明与
test-infra.md一致 - chat 独立改进文档删除并零悬空引用
-
notification.md/mail.md/config.md/development.md/ 根README.md与 MN/ITW 一致(无现行本仓 SMTP 门) -
test-infra.md/integration.md已含 website-next / integration_website_auth / 邮件门变更 / mailpit 消费方 -
docs/plan/README.md登记本计划(含 MN 与 compose/文档同步) - 无悬空链接到已删 chat 独立文档;
website-mail.md拓扑与 compose 现状一致
Verification:
-
rg -n 'plan-20260731|website-auth|website-mail|website-next|ADR-WA-08' docs/plan docs/refactoring docs/development.md -
bash -c 'set -uo pipefail; if hits=$(rg -n "docs/refactoring/chat\.md" docs | rg -v "已随[^\n]*DOC-01[^\n]*删除|已删除|2026-08-06|历史快照"); then echo "FAIL: unannotated dangling chat.md reference:"; echo "$hits"; exit 1; else rc=$?; [ "$rc" -eq 1 ] || exit "$rc"; echo "OK"; fi'(2026-08-06 完成度复审改写:原命令为无过滤rg … 零命中,在收口日成立;augmentcode.md(收口后入库的历史快照)及本计划注记合法地以「已删除」标注引用该路径,零命中口径改为「排除已标注删除/历史快照的行后零命中」,与 DOC-01 执行后注记一致) -
rg -n 'MEGA_MAIL|SmtpMailer→Mailpit|mail\\.password seed' docs/development.md docs/refactoring/test-infra.md仅允许废止/历史语境 -
libra status --short --branch仅文档路径
Dependencies: AU-05, RM-06, ITW-03, MN-06
Deliverables: docs/plan/plan-long.md、docs/plan/README.md、docs/refactoring/{notification,mail,config,test-infra,integration}.md、docs/development.md、根 README.md(若 MN-06 已改则复核);删除重构目录中已退场的 chat 独立文档
Implementation write set: 上列 docs
Release write set: N/A
Rollback mode: revert
Estimated scope: M
Version increment: N/A
Release boundary: no-release
C/D coverage from: REL-01
Granularity: type=docs; axis=长期重构文档收口; recovery=revert文档; complete=yes; self-contained=yes; AC=9/20; VER=4/20; landing=8; prod-files=8; scope=M; deps=AU-05,RM-06,ITW-03,MN-06; writeset=no-overlap; release=no-release; split-from=N/A; exception=N/A
Task type: release
Lifecycle / Acceptance: done / complete
Description: 作为 REL-WA-01 唯一发布点:在 AU/RM/ITW/MN/DOC 子卡均 locally-accepted 且 review PASS 后,做版本面 minor bump、三门、提交推送,并写出 breaking 兼容说明(ADR-WA-06)。聚合 AU-01/MN-01/DOC-01 文档提交。
Out of scope:
- 不引入新行为
- 无 tag/artifact(本仓 N/A)
Current evidence:
| 事实 | 证据 |
|---|---|
| 当前版本 | 0.2.0(Cargo.toml:6;相对窗口入口 0.1.183 minor +1) |
Acceptance criteria:
- 版本面两处一致且相对进入窗口时权威版本 minor +1(例如
0.2.0,以进入窗口时读取为准) - breaking 列表写入提交说明或
docs/短发布说明(本卡选提交说明正文 +website-auth.md/website-mail.md「兼容」节若尚无则补) - AU-01、MN-01 与 DOC-01 产物已在同一发布提交集或紧邻提交中进仓;ITW/MN 代码与 compose 变更已含于发布树
- 推送成功;适用 D 组全绿后本卡与全部家族子卡
Acceptance=complete - 确认窗口内无子卡曾独立 bump/推送
Verification:
- 版本 parity:
Cargo.toml与bin/Cargo.toml的version相等且为 minor bump - 提交说明含
/api/v1/chat、website_user_id、chat-migrate、隐式 admin、[mail]/email_jobs五类 breaking 关键词
Dependencies: DOC-01
Deliverables: 版本面两处 + Cargo.lock;提交/推送证据
Implementation write set: N/A(发布动作)
Release write set: Inherited
Rollback mode: immutable-release
Estimated scope: S
Version increment: minor
Release boundary: family release point of REL-WA-01
C/D coverage from: self
Granularity: type=release; axis=minor发布点; recovery=immutable-release前滚; complete=yes; self-contained=yes; AC=5/12; VER=2/12; landing=0; prod-files=0; scope=S; deps=DOC-01; writeset=N/A; release=family release point of REL-WA-01; split-from=N/A; exception=N/A
| 类别 | 必须覆盖 | Target / command |
|---|---|---|
| 单元 | Cookie 解析、字段映射、banned、空 name | cargo test -p mega2-core 'api::oauth' |
| 集成(DB) | DROP chat + DROP email_jobs migration up | cargo test -p mega2-core 对应 migration 测试 |
| CLI | chat-migrate 已移除;config secret 无 mail.password |
cargo test -p mega2-core 'commands::' + cli::tests |
| HTTP API | 无 /chat;无 admin email-jobs;会话拒绝/成功;/user 仍可用 |
api:: + OpenAPI 证据 |
| 配置 | oauth 必填基址;无 [chat]/[mail];无遗留键 |
config validate |
| Git 协议 | token 路径未回归 | 既有 integration_git_cli / smoke(REL 三门覆盖) |
| 安全 | 无隐式 admin;token/mail bearer 不进日志 | AU-05、MN-05 守卫 |
| 通知 | 无 chat 事件;无 email-primary / enqueue_email_job | notification:: |
| 邮件 | 本仓无 SMTP;compose 无 MEGA_MAIL;website API 客户端(mock/IT);mailpit 仅 website |
MN-05/MN-06;docker compose … config;integration_vault 多渠道去邮件断言 |
| 栈级会话 IT | next-app 登录 + cookie → /api/v1/user |
cargo test -p mega2 --test integration_website_auth -- --test-threads=1(需 --profile app --profile web) |
| compose | website-next 登记与健康 |
docker compose -p mega2-it … --profile web |
| 任务 | 来源/证据 | mega2 落点 | 文档/兼容动作 | 指定测试 |
|---|---|---|---|---|
| AU-01 | website Better Auth;GAP-07/08 | docs/refactoring/website-auth.md |
新建事实源含 compose 拓扑 | 结构守卫 |
| AU-02 | GAP-02;PT-10 | src/config/、config/config.toml |
config.md | config validate + config:: |
| AU-03 | GAP-01/03;Mega SessionUser | src/api/oauth/、http_server |
website-auth.md | api::oauth |
| AU-04 | GAP-04 | LoginUser、gpg_router |
breaking 字段名 | oauth + gpg |
| AU-05 | GAP-01 | oauth 测试 | — | 新会话用例(mock) |
| ITW-01 | GAP-08;ADR-WA-07;Mega demo 形态 | docker-compose.test.yml |
test-infra.md | compose up website-next |
| ITW-02 | ADR-WA-07 | compose env / CORS | website-auth.md、test-infra.md | 同网络 get-session |
| ITW-03 | GAP-08 | bin/tests/integration_website_auth.rs |
integration.md、CI | integration_website_auth |
| RM-01 | GAP-05 | api/commands/server | OpenAPI | cli/commands/OpenAPI |
| RM-02 | GAP-05 | api/notes |
OpenAPI | api:: |
| RM-03 | GAP-06 | notification/triggers.rs |
notification.md | notification:: |
| RM-04 | GAP-05 | chat/callisto/storage/config | config.md | build --tests |
| RM-05 | GAP-05/06 | 新 migration | forward-only | migration tests |
| RM-06 | sidebar 默认 | config + SidebarConfig | — | validate |
| MN-01 | GAP-09;ADR-WA-08 | docs/refactoring/website-mail.md |
契约事实源 | 结构守卫 |
| MN-02 | GAP-09 | notification/、context |
notification.md | notification:: |
| MN-03 | GAP-09 | src/mail/ 删除、admin、config |
mail.md 废止 | config + OpenAPI |
| MN-04 | GAP-09 | DROP email_jobs migration | forward-only | migration tests |
| MN-05 | GAP-09;DEP-06 | website mail client + triggers + compose 接线 | website-mail.md | triggers + mock/IT |
| MN-06 | GAP-09;ADR-WA-08 §7 | compose/env/CI/测试/文档去本仓邮件门 | test-infra、development、README、mail 废止 | integration_vault + compose config 守卫 |
| DOC-01 | plan-long / chat 文档退场 / PT-09 / ITW/MN 文档 | docs | README 索引 | 链接守卫 |
| REL-01 | ADR-WA-06 | 版本面 | 提交说明 | 三门 + D |
| 里程碑 | 完成条件 | 发布/证据 | 回滚或前滚 |
|---|---|---|---|
| M0 | AU-01 + MN-01 locally-accepted + review PASS | 文档随 REL-01 进仓 | revert 文档 |
| M1 | AU-05 locally-accepted + review PASS | 本地提交;不独立 patch 推送 | revert 各卡;会话回退会恢复 stub——禁止在生产长时间停留 |
| M1b | ITW-03 locally-accepted + review PASS | 本地提交;不独立推送 | revert compose/测试;不影响生产 IdP |
| M2 | RM-06 locally-accepted + review PASS;RM-05 后不可 schema 回滚 | 本地提交;不独立推送 | RM-05 前可代码 revert;之后仅备份恢复 |
| M2b | MN-06 locally-accepted + review PASS;MN-04 后 email 表不可 schema 回滚 | 本地提交;compose/env/docs 已就绪待 REL-01 | MN-04 前可代码 revert;之后仅备份恢复;website API 故障时产品邮件静默失败(见故障矩阵) |
| M3 | REL-01 complete;家族子卡 Acceptance=complete;计划完成判据全勾 | 唯一 minor 推送 | immutable-release;前滚修复 |
| 故障点 | 可接受残留 | 恢复动作 | 禁止结果 |
|---|---|---|---|
| website get-session 超时 | 请求失败 | 拒绝会话;Git token 仍可用 | 回退到隐式 admin |
| RM-05 中途失败 | 部分表已 DROP | 停机、从备份恢复或手工完成剩余 DROP 后标记 migration | 半套表 + 代码已删仍查询 |
| MN-04 中途失败 | email 表部分 DROP | 同 RM-05:备份恢复或完成剩余 DROP | 代码已删仍写 email_jobs |
| website 邮件 API 不可达 | 产品邮件未送达;in-app 仍可写 | 修复 website/DEP-06;日志告警;不回退 SMTP | 在本仓重新启用 [mail] |
| 发布后发现非 chat 误 DROP | 数据丢失风险 | 立即停写;从备份恢复;开 FIX 卡 | 继续服务 |
| website-next 镜像构建失败 | 无 web profile | ITW blocked;数据面 / app profile 仍可用 | 用 FixedUser 冒充 ITW-03 完成 |
sibling ../website 缺失 |
无法 build web | 按 DEP-05 停工 | 改指向任意远程未 pin 镜像 |
| 风险 | 影响 | 缓解 | 任务 |
|---|---|---|---|
| Cookie 跨站被拒 | 高:浏览器 API 全 401 | 文档部署拓扑;CORS credentials;同站/反代;IT 用容器网络 URL | AU-01、AU-03、ITW-02 |
name 非唯一 |
中:actor 碰撞 | 文档约束;后续 unique handle(ADR revisit) | AU-01、ADR-WA-02 |
| DROP 误伤非 chat 表 | 高 | ER-02 复核 reactions 消费方;RM-05 禁止 DROP email_jobs(由 MN-04 单独做) |
RM-05 |
| DEP-06 未就绪 | 高:MN-05/06 blocked | 契约先落盘(MN-01);website 并行;本仓不得回退 SMTP | MN-01、MN-05、DEP-06 |
| 去 email-primary 拖死扇出 | 高 | MN-02 先改 primary=in_app 再删 mail | MN-02、MN-03 |
| 测试仍假定 admin / Mailpit | 中:假绿/假红 | AU-05 清 stub;MN-06 去邮件门 | AU-05、MN-06 |
| 每请求外呼延迟 | 低-中 | 超时有界;缓存延后 DEFER-WA-02 | AU-03 |
| next-app 镜像构建慢/失败 | 中:ITW 阻塞 | profile web 可选;CI 缓存;SQLite 减依赖 |
ITW-01、ITW-03 |
| website 契约漂移 | 中:栈 IT / 邮件 IT 红 | DEP-01/06 pin + ITW-03 + MN-05 | ITW-03、MN-05 |
| 操作 | 单次成本 | 累积成本 | 预算/上限 | 验证 |
|---|---|---|---|---|
| get-session 外呼 | 1× HTTP RTT | 每会话请求 1 次 | 客户端超时 ≤ 配置默认(建议 ≤ 3s,AU-03 写定) | 单元 mock;无基准强制 |
| website 邮件 API 外呼 | 1× HTTP RTT | 每需邮件的触发 1 次 | 超时有界;失败不阻断主请求 | MN-05 mock/IT |
| DROP migration | O(表数) DDL | 一次(chat + email) | 维护窗口执行 | 集成测试 |
| website-next 镜像构建 | 数分钟级 | 每 CI/本地首次 | ITW-01 登记上限(建议 ≤ 20min) | compose build 计时 |
| integration_website_auth | 登录 + 2× HTTP | 每 target 一次 | 建议 ≤ 10min | ITW-03 |
-
docs/errors.md已同步,或说明 N/A(若无新 MegaError 变体)。 -
docs/refactoring/website-auth.md与website-mail.md已创建;chat.md已删;mail.md废止并改引;notification.md/config.md/test-infra.md/integration.md/docs/development.md/ 根README.md已同步。 -
config/config.toml示例与注释已同步(无[mail];含 website mail 客户端配置若适用)。 - 运行时 OpenAPI 证据已取得(无
/chat、无 notes sync、无 admin email-jobs/mail-templates)。 -
README.md/AGENTS.md相关漂移已同步或登记。 - callisto / storage / migration(含
migrations())已同步;email_jobs已 DROP。 - 新引入的
docs/*.md引用全部真实存在。 -
plan-long.md日期索引与 PT-09/10/12/chat 状态已同步。 -
docker-compose.test.yml含website-next;--profile app --profile web同栈可启;无MEGA_MAIL__*;mailpit 消费方已文档化。 -
.env.test.example与 CI 不再要求本仓mail.password/ SmtpMailer→Mailpit 门。
Result 只允许 PASS 或 FAIL。
| Round | Scope | Result | P0/P1 | P2 处置 | Evidence |
|---|---|---|---|---|---|
| R1 | 计划成稿 | FAIL | 未完成模板合规审查(Result 曾非法占位) | 并入后续轮次 | 本文件 |
| R2 | 补录 next-app compose IT | FAIL | 未闭环审查 | 并入后续轮次 | ADR-WA-07;ITW-01..03 |
| R3 | 补录邮件退场改接 website | FAIL | 未闭环审查 | 并入后续轮次 | ADR-WA-08;MN-01..06;GAP-09;DEP-06 |
| R4 | 强制 compose + 文档与邮件退场同步 | FAIL | 未闭环审查 | 并入后续轮次 | ADR-WA-08 §7;MN-05/06/DOC-01 扩写 |
| R5 | Codex 计划成稿审查 | FAIL | P1:G-10 写集(ITW↔MN compose/docs)未闭合 | P2:AU-01 deps、MN-06 VER、REL-01 AC 审计、Review log 占位——已改 | /tmp/mega2-plan-review/r1-last.txt |
| R6 | Codex 复审 | FAIL | P1:独立发布 vs REL-01 minor 矛盾;AU↔RM/MN G-10 | P2:removal 弃用窗口——已改家族发布+依赖边+ADR-WA-06 | /tmp/mega2-plan-review/r2-last.txt |
| R7 | Codex 复审 | FAIL | P1:Phase/里程碑仍写子卡 complete/patch 发布;AU-02/MN-01 deps 误写 AU-05;MN-02 granularity 漏 AU-05 | 已改 | /tmp/mega2-plan-review/r3-last.txt |
| R8 | Codex 复审 | FAIL | P1:MN-06 AC=9/12 违反 G-03 代码卡分母 8 | 已合并 AC→8/8、VER→5/8 | /tmp/mega2-plan-review/r4-last.txt |
| R9 | Codex 计划成稿审查 | PASS | 无 | — | /tmp/mega2-plan-review/r5-last.txt |
| AU-01 | website-auth.md 落盘 |
PASS | 无(R1 悬空 website-mail 链接已修) | — | /tmp/mega2-plan-exec/au01-r2.txt |
| AU-02 | OAuthConfig 类型化 | PASS | 无(R1–R2 P2/P3 已修:legacy env 硬拒 + base URL Url 校验) | — | /tmp/mega2-plan-exec/au02-r3.txt |
| AU-03 | SessionUser 真接通 | PASS | 无 | — | /tmp/mega2-plan-exec/au03-r1.txt |
| AU-04 | website_user_id 重命名 | PASS | 无 | — | /tmp/mega2-plan-exec/au04-r1.txt |
| AU-05 | 会话路径验收测试 | PASS | 无 | — | /tmp/mega2-plan-exec/au05-r1.txt |
| ITW-01 | 登记 website-next compose | PASS | 无 | — | /tmp/mega2-plan-exec/itw01-r1.txt |
| ITW-02 | 同栈 oauth/CORS 接线 | PASS | 无(子代理中断后已补 curl 200/null + down) | — | /tmp/mega2-plan-exec/itw02-r1.txt |
| ITW-03 | 真实 cookie 栈级黑盒 | PASS | R1–R2:401 断言、pin 政策/守卫 YAML;R3 PASS | — | /tmp/mega2-plan-exec/itw03-r3.txt |
| RM-01 | Chat HTTP/CLI 退场 | PASS | 无 | — | /tmp/mega2-plan-exec/rm01-r1.txt |
| RM-02 | Notes API 退场 | PASS | R1 空目录残留已 rmdir | — | /tmp/mega2-plan-exec/rm02-r2.txt |
| RM-03 | Chat 通知触发器退场 | PASS | 无 | — | /tmp/mega2-plan-exec/rm03-r1.txt |
| RM-04 | 模块/实体/ChatConfig 删除 | PASS | R1–R2 FAIL 后恢复 sidebar、收窄 Note 判定;R3 PASS | — | /tmp/mega2-plan-exec/rm04-r3.txt |
| RM-05 | DROP chat/notes schema | PASS | ER-02 修订后保留 reactions/custom_reactions | — | /tmp/mega2-plan-exec/rm05-r1.txt |
| RM-06 | Sidebar 默认项清理 | PASS | 无 | — | /tmp/mega2-plan-exec/rm06-r1.txt |
| MN-01 | website-mail 契约落盘 | PASS | R1:配置键写死;脏树按 write set 解释 | — | /tmp/mega2-plan-exec/mn01-r2.txt |
| MN-02 | dispatcher 去 email-primary | PASS | R1:slack/webhook 扇出与 notification.* 死配置;R2 已修 | — | /tmp/mega2-plan-exec/mn02-r2.txt |
| MN-03 | 删除 mail 模块与 admin API | PASS | R1–R3:MEGA_MAIL env 硬拒 + IT/compose 去播种;R4 PASS | — | /tmp/mega2-plan-exec/mn03-r4.txt |
| MN-04 | DROP email_jobs 表 | PASS | R1:缺 down no-op 测试证据;R2 已补 | — | /tmp/mega2-plan-exec/mn04-r2.txt |
| MN-05 | 产品事件改调 website 邮件 API | PASS | R1:payload 契约偏离 + locale;R2 已修 | — | /tmp/mega2-plan-exec/mn05-r2.txt |
| MN-06 | compose/测试/CI/文档去本仓邮件门 | PASS | R1:CI 仍跑 mail.password 门 + test-infra/website-mail 现状漂移;R2 已修 | — | /tmp/mega2-plan-exec/mn06-r2.txt |
| DOC-01 | plan-long 与重构文档收口 | PASS | R1–R2:refactoring/README 仍写本仓 mail 主线;R3 已修 | — | /tmp/mega2-plan-exec/doc01-r3.txt |
| REL-01 | minor 发布点 v0.2.0 | PASS | R1:缺 fmt 硬证据 + 完成判据过早勾选;R2 已补 | — | /tmp/mega2-plan-exec/rel01-r2.txt;push e213371 |
| ID | 延后内容 | 原因 | 重启条件 | 承接位置 |
|---|---|---|---|---|
| DEFER-WA-01 | mega2 签发 JWT / service account 调 website | 本计划只做 cookie introspection | 机机集成需求书面化 | 后续日期计划 |
| DEFER-WA-02 | get-session 结果短 TTL 缓存 | 先保证正确性 | 延迟/website QPS 成为瓶颈 | 后续计划 |
| DEFER-WA-03 | 已有 DB 动态 sidebar 中 chat/notes 行的数据迁移 | 默认配置已清;存量可用 API | 运营需要批量清理 | 运维脚本或小卡 |
| DEFER-WA-04 | PT-12 全量 moon↔next-app 功能对照 | 超出本计划 | PT-12 排期 | plan-long.md PT-12 |
| DEFER-WA-05 | Playwright/浏览器 E2E;website 账户库改 Postgres(后半已落地,2026-08-06 注记:plan-20260803 期间 mega2 39f7433 已把 website IT 账户库切为隔离 Postgres website 库;Playwright/浏览器 E2E 仍延后) |
本计划最小栈为 HTTP API + SQLite IdP(收口日快照) | 需要 UI 级回归或共享 Postgres 运维 | 后续日期计划 |
| DEFER-WA-06 | 将 Mega moon/campsite 拉进同一 compose | 与 website IdP 架构冲突 | 明确双前端同栈对照需求 | PT-12 / 独立计划 |
| DEFER-WA-07 | 将 CL/issue 通知编排整体迁到 website 通知中心 | 本计划只迁邮件投递 | website 通知中心与事件源契约成熟 | 后续日期计划 |
| DEFER-WA-08 | 本仓邮件失败本地重试队列 | MN-05 选 best-effort + 日志 | 投递 SLA 要求可恢复重试 | 后续小卡或 website 侧重试 |
| DEFER-WA-09 | DROP reactions / custom_reactions |
ER-02:CL/Issue conversation 仍消费 reactions;FK 保留 custom_reactions |
conversation 反应迁表或确认无非 chat subject | 后续日期计划 |
- 所有任务卡满足 G-*;粒度审计表已填齐;无未登记 L/XL、无 EX 缺口。
- 所有非延后任务
Lifecycle=done且Acceptance=complete(含 ITW-01..ITW-03、MN-01..MN-06);子卡 complete 仅在 REL-01 推送后取得。 - 所有 Verification 已运行并记录。
- 计划完成门:
cargo +nightly fmt --all --check、cargo clippy --all-targets --all-features -- -D warnings、source .env.test && cargo test --all全绿;cargo build与cargo build --tests0 错误 0 警告。 - 文档/配置/OpenAPI/测试矩阵已更新;
test-infra.md已登记 website-next 与 mailpit 消费方;website-mail.md已落盘;mail.md已废止说明;development.md/ 根README.md无现行本仓 SMTP 门。 - RM-05 / MN-04 forward-only 已验证;无声称可 down。
-
--profile app --profile web同栈会话黑盒已绿(ITW-03)。 - 本仓无 SMTP/
[mail]/email_jobs;compose 无MEGA_MAIL;产品邮件走 website(MN-06)。 - Review 最终
PASS;P0/P1 关闭。 - REL-01 minor 已推送;无 artifact 要求写 N/A。
- 修订历史完整。
-
plan-long.md已同步(含 PT-09)。