4a0c5c4921
ci-pangolin / Lint — shellcheck (pull_request) Failing after 42s
ci-pangolin / OpenAPI Sync Check (pull_request) Failing after 36s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 16s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 15s
ci-pangolin / Flutter — analyze + test (pull_request) Failing after 3m35s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Failing after 24s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Failing after 24s
ci-pangolin / Go — build + test (pull_request) Failing after 1m18s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 27s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 19s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 28s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
323 lines
15 KiB
JSON
323 lines
15 KiB
JSON
{
|
||
"meta": {
|
||
"title": "feature+windows — 项目 TODO",
|
||
"updated_at": "2026-07-07T17:45:18.036Z"
|
||
},
|
||
"seq": 19,
|
||
"items": [
|
||
{
|
||
"id": 1,
|
||
"title": "macOS 原生 KillSwitch 补齐 L0→L3",
|
||
"desc": "现状 L0(stub):VpnChannel.swift:69 setKillSwitch 直接 result(nil)、includeAllNetworks()→false。天花板 L3。改 NetworkExtension:includeAllNetworks=true + NEOnDemandRule 常开 + enforceRoutes,由 neagent 系统级强制、扛 app 崩溃。性价比最高的跨端缺口。依据见 docs/killswitch-design.md §4-6。",
|
||
"level": "mid",
|
||
"tier": 2,
|
||
"tags": [
|
||
"mac"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-22T09:32:42.340Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"title": "Android KillSwitch L1 + 引导系统 Always-on",
|
||
"desc": "现状 L0(stub):MainActivity.kt setKillSwitch 只打日志(TODO 11G)。目标:app 内做到 L1(config TUN strict_route,复刻 Windows 的 applyKillSwitchToConfig 语义) + 深链引导用户开系统设置「始终开启 VPN + 无 VPN 时阻止连接」拿 L3,UI 诚实标注「彻底防泄漏需在系统设置开启」。属 Android 客户端 11G。依据见 docs/killswitch-design.md §4-6。",
|
||
"level": "mid",
|
||
"tier": 2,
|
||
"tags": [
|
||
"Android"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-22T09:32:56.098Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 3,
|
||
"title": "Windows KillSwitch L1→L2 (WFP 防火墙强制)",
|
||
"desc": "现状 L1:desktop_vpn_bridge.dart strict_route + 子进程重载,进程被硬杀仍泄漏。目标 L2:app 装 WFP(Windows Filtering Platform) 过滤器阻断非隧道流量,做成系统服务持久化才能扛崩溃。工作量较大,backlog。依据见 docs/killswitch-design.md §4-6。",
|
||
"level": "low",
|
||
"tier": 1,
|
||
"tags": [
|
||
"Windows"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-22T09:32:56.169Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 4,
|
||
"title": "线上启用 TOTP 两步验证并验 2FA",
|
||
"desc": "pangolin1 的 /etc/pangolin/server.env 配 USER_TOTP_ENC_KEY(32字节或64位hex)并重启 pangolin-server,启用后验 A.1 客户端 2FA:绑定 Authenticator→重登 6 位码校验→备份码可用。当前该键未设置,/auth/login/totp 与 /me/totp/* 未挂载,2FA 无法测。属 A.1 手动验证清单第 4 项的前置。",
|
||
"level": "mid",
|
||
"tier": 3,
|
||
"tags": [
|
||
"后端",
|
||
"运维"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-27T16:39:31.549Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 5,
|
||
"title": "SendCode 发信失败记日志 + 测试",
|
||
"desc": "auth/service.go 异步发信把错误静默吞了(:157 SendCode 的 _=s.mailer.SendCode(...),:133 SendAlreadyRegistered 同样),导致 SMTP 故障日志无痕、本次 587 被封难排查。改为发信失败时记日志(slog.Error,脱敏:只记 send failed:<err>,绝不记验证码,邮箱可打码,守 no-secret-in-logs)。并加测试:注入会失败的 mock Mailer,断言发送失败时确实记了一条错误日志(可用 LogMailer 思路/捕获 slog handler 验证)。",
|
||
"level": "mid",
|
||
"tier": 3,
|
||
"tags": [
|
||
"后端"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-27T23:37:24.980Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-28T13:19:24.207Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 6,
|
||
"title": "节点列表:正式名(地区·国家) + 国旗图标",
|
||
"desc": "客户端节点列表项展示改造:① 节点名改正式格式「地区 · 国家」(如 香港 · 中国),去掉测试名(当前 prod 节点 name_zh=单节点·测试);② 节点图标用国旗(按 region/国家码渲染 emoji 或 SVG 旗)。涉及:服务端 nodes 行的 name/region/国家码数据(可能需补国家码字段),客户端节点卡片渲染国旗+名格式。HK 节点国旗/国家标签需产品确认(🇭🇰香港 vs 🇨🇳中国)。",
|
||
"level": "mid",
|
||
"tier": 2,
|
||
"tags": [
|
||
"前端",
|
||
"后端"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-28T00:21:30.990Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-28T13:19:24.299Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 7,
|
||
"title": "节点健康绑定 agent 在线 + connect 校验凭证下发 + 掉线告警",
|
||
"desc": "本次 google 打不开暴露的架构漏洞:① 节点 status 是静态 DB 列(种子 up),只有 SCHED 健康循环会改、而单节点没开 → Hub 已知 agent 离线却不反映到节点状态/列表,客户端永远显示健康。应把 Hub 的 agent 在线状态接进 ListNodes/节点 status。② ConnectNode 把 hub.Push 错误吞了(_ = pushErr)且不校验 agent 在线 → 凭证没下发也返回 200,客户端误以为连上。应在 agent 离线/push 失败时降级或明确报错,并把推送结果纳入响应。③ agent 掉线无告警(本次停 6 天没发现),应在 Hub 检测到 agent stream 断开时告警。④ 通病:错误被 _ = 静默吞掉(今天邮件/连接500/此处共三处),需排查同类静默吞错。",
|
||
"level": "high",
|
||
"tier": 1,
|
||
"tags": [
|
||
"后端"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-28T00:26:44.498Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-30T14:44:35.082Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 8,
|
||
"title": "agent 掉线告警 + 静默吞错全量审计",
|
||
"desc": "TODO #7 的剩余两块:① Hub 检测到 agent gRPC 流断开时触发告警(alert 包),避免再像这次停 6 天没人知道;② 全仓审计 _ = err / 忽略错误的静默吞错点(今天已遇邮件/连接500/connect-push 三处),逐一改为记日志或上抛。",
|
||
"level": "mid",
|
||
"tier": 2,
|
||
"tags": [
|
||
"后端"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-28T00:38:22.413Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 9,
|
||
"title": "打通每设备归因(设备注册 + per-device dp_uuid)",
|
||
"desc": "现状:多设备共用账户级 dp_uuid,统计无法区分设备;usage_device_daily 永远空,统计页设备下拉只有「全部」。基础设施已具备(devices.dp_uuid / EnsureDeviceDpUUID / usage_device_daily / UserDeviceByDpUUID)但未激活——客户端没 POST /v1/me/devices 注册本机,连接时 EnsureDeviceDpUUID 查不到设备行→回退账户 uuid。需:① 客户端启动/登录时注册本机设备(稳定 uuid + name + platform);② 连接时带该 device_id;③ 或让 EnsureDeviceDpUUID 缺行时自动建设备行。打通后每设备统计 + 统计页设备下拉才有真数据。是统计重设计「设备下拉」的前置依赖。",
|
||
"level": "mid",
|
||
"tier": 2,
|
||
"tags": [
|
||
"前端",
|
||
"后端"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-28T09:32:26.008Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-30T14:44:34.810Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 10,
|
||
"title": "统计页设备下拉接真实设备数据(依赖#上条)",
|
||
"desc": "统计重设计的设备下拉,先只挂「全部」上线;每设备归因打通后,把下拉填上「全部 + 近30天用过的设备名」,选设备走 /v1/usage/devices 过滤。依赖每设备归因 TODO。",
|
||
"level": "low",
|
||
"tier": 2,
|
||
"tags": [
|
||
"前端"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-28T09:32:26.080Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-30T14:44:34.991Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 11,
|
||
"title": "清理旧命名 tablet golden 孤儿文件",
|
||
"desc": "client/test/golden/goldens/ 下未被引用的 tablet_connect.png/tablet_connect_dark.png/tablet_servers.png/tablet_stats.png/tablet_account.png(旧命名,已被 _light_/_dark_zh 矩阵取代),git rm 清掉。(从本地 main todo 合并而来)",
|
||
"level": "low",
|
||
"tier": 3,
|
||
"tags": [
|
||
"前端"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-28T11:27:56.637Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-30T14:47:39.343Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 12,
|
||
"title": "协议选择(REALITY/Hysteria2/自动)端到端",
|
||
"desc": "让用户选数据面隧道协议:auto(服务端自决)/reality(TCP443隐蔽)/hysteria2(UDP443弱网更快)。客户端 settings 加 ProtocolChoice 枚举+持久化+三段选择器、connect 时下发。关键:protocol 必须走 query(?protocol=)不走 body(与 split_cn 一致,nodes.go:183),旧 WIP 误移 body 会破坏分流。服务端 nodes.go connect 读 query + clientconfig BuildClientConfig 按 proto 渲染。(从本地 main todo 合并而来)",
|
||
"level": "mid",
|
||
"tier": 1,
|
||
"tags": [
|
||
"前端",
|
||
"后端"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-28T11:27:56.708Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 13,
|
||
"title": "数据面故障韧性:节点健康上报+客户端连通看门狗",
|
||
"desc": "agent 心跳带 sing-box 健康(clash_api /version)→控制面 effectiveNodeStatus 标 down(列表置灰+connect拦截);客户端连上后 HTTP 204 看门狗,连续失败:智能选择自动切节点/手动只提示断开。plan: crystalline-exploring-lerdorf.md",
|
||
"level": "high",
|
||
"tier": 1,
|
||
"tags": [
|
||
"后端",
|
||
"前端",
|
||
"gRPC"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-29T04:55:46.733Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-29T16:59:39.926Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 14,
|
||
"title": "移动端真·常连:Android Always-on + iOS/iPad On-Demand(无UI自连)",
|
||
"desc": "系统在 app 未开时拉起隧道:Android Always-on VPN(系统设置开启+VpnService 支持 onStartCommand 无UI拉起+配置缓存)、iOS/iPad On-Demand(NEOnDemandRule + PacketTunnelProvider 用缓存 lastConfigJson 自连)。难点:paid 凭证 TTL 仅24h,长期常连需原生侧刷新配置/凭证。桌面自启+全平台自动连接已在另一轮做(plan crystalline-exploring-lerdorf)。",
|
||
"level": "mid",
|
||
"tier": 1,
|
||
"tags": [
|
||
"Android",
|
||
"iOS",
|
||
"后端"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-29T09:36:14.004Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 15,
|
||
"title": "iOS/iPad 实时统计+urltest 延迟与 macOS 对齐",
|
||
"desc": "移植 macOS 已验证的统计架构:扩展注入 clash_api + StatsCollector(clash 取 urltest),app StatsClient 改 sendProviderMessage 轮询;前置生成 iOS Libbox.xcframework。Dart 侧已对齐(共用 VpnNativeBridge)。",
|
||
"level": "mid",
|
||
"tier": 2,
|
||
"tags": [
|
||
"iOS",
|
||
"前端"
|
||
],
|
||
"status": "accepted",
|
||
"created_at": "2026-06-30T10:56:48.894Z",
|
||
"done": true,
|
||
"completed_at": "2026-06-30T14:44:34.900Z",
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 16,
|
||
"title": "启用设备数量限制 + 超限 UX(踢旧/选择移除,非硬拒登)",
|
||
"desc": "现状:plans.max_devices(free1/pro5/team10)+ devices/service.go:216 强制逻辑 + DEVICE_LIMIT_EXCEEDED 错误码 + 账户API DevicesMax 都在,但 main.go:534 登录注册传 MaxDevices:0(不启用)。原因:free 用户重装会换 device UUID,登录硬卡会把人锁外面。需:① 登录/注册从套餐读 max_devices 传入 RegisterIfAbsent;② 超限不直接拒登,改为'踢最旧设备/让用户选哪台下线'的 UX(客户端弹窗 + 设备管理页操作);③ 处理 free 重装 churn(同机复用而非每次新增)。tier-1:涉及登录接口 + 跨后端/前端 + 策略设计。",
|
||
"level": "mid",
|
||
"tier": 1,
|
||
"tags": [
|
||
"后端",
|
||
"前端"
|
||
],
|
||
"status": "open",
|
||
"created_at": "2026-06-30T14:33:48.996Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 18,
|
||
"title": "看门狗后台唤醒误判节点死→假重连",
|
||
"desc": "app/Mac 后台或睡眠一段时间再打开,连通看门狗路径A(urltest stale)用墙上时钟算陈旧度,_lastUrltestOk 在挂起期冻住→唤醒时误判>45s→_onNodeUnhealthy 触发 disconnect+connect 假重连(智能模式还自动切节点),但隧道没掉。修:_onStats 记 _lastStatsAt,路径A 仅在 stats 仍在流但 urltest 停更时才判死;stats 整体停(挂起)则跳过。connection_provider.dart 一处。",
|
||
"level": "mid",
|
||
"tier": 3,
|
||
"tags": [
|
||
"mac",
|
||
"前端"
|
||
],
|
||
"status": "done",
|
||
"created_at": "2026-06-30T23:00:25.193Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"owner": "agent"
|
||
},
|
||
{
|
||
"id": 19,
|
||
"title": "前端设计系统治理重构(ds-flow 全端)",
|
||
"desc": "用 ds-flow 把 Flutter 五端+官网+用户中心收口到设计单源。补原型三件套(atoms.css/icons.js/index.html)+Web共享原子层去重(各自实现+同源闸)+硬编码色/fidelity闸+启用pre-commit。6阶段。计划见 docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md",
|
||
"level": "mid",
|
||
"tier": 1,
|
||
"tags": [
|
||
"前端",
|
||
"Web",
|
||
"mac",
|
||
"iOS",
|
||
"Android",
|
||
"Windows",
|
||
"CI/CD"
|
||
],
|
||
"owner": "agent",
|
||
"status": "done",
|
||
"created_at": "2026-07-07T15:41:25.760Z",
|
||
"done": false,
|
||
"completed_at": null,
|
||
"version": null,
|
||
"gate": {
|
||
"kind": "plan",
|
||
"note": "6 阶段 ds-flow 治理重构:Phase0 CLAUDE.md+计划落库 / Phase1 原型三件套(atoms.css/icons.js/index.html,收敛ui_kits) / Phase2 Web token同源闸 / Phase3 Web共享原子层去重(各自实现+同源闸,★工作量最大) / Phase4 Flutter收尾+golden补齐 / Phase5 静态闸挂满+启用pre-commit+fidelity体检。已定决策:Web各自实现+同源闸、ui_kits收敛纯HTML、先定稿再逐刀。主题保持light/dark。",
|
||
"ref": "docs/superpowers/plans/2026-07-07-frontend-ds-refactor.md",
|
||
"approval": "granted",
|
||
"proposed_at": "2026-07-07T15:41:36.536Z",
|
||
"approved_at": "2026-07-07T15:54:54.386Z"
|
||
}
|
||
}
|
||
]
|
||
}
|