Files
pangolin/todo/todo.json
T
wangjia e333f59cb3
ci-pangolin / Lint — shellcheck (push) Successful in 8s
ci-pangolin / OpenAPI Sync Check (push) Successful in 19s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 6s
ci-pangolin / Flutter — analyze + test (push) Failing after 14s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 6s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 4s
ci-pangolin / Go — build + test (push) Successful in 11s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 14s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m8s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 15s
feat(stats): #10 第②层 —— 统计页按设备过滤(per-device 本地日曲线)
镜像账户级时区曲线到「按设备」:
- migration 000018 `usage_device_hourly`(每设备 UTC 小时桶,稀疏)。
- ReportUsage deviceID>0 时加 AccumulateDeviceHourly;NodeStore 接口+impl+mock。
- usage.Store.DeviceHourlyRange(JOIN devices 校验归属+解析 uuid→id);UsageCurve
  增 deviceUUID 形参:空=账户级,非空=该设备本地日曲线(分桶逻辑复用)。
- /v1/usage?device=<uuid>;客户端 account_api.usage(device)、usageProvider key 改
  记录 (days,device)、stats_page 接 statsDeviceProvider → 选设备即重取该设备曲线。
测试:per-device 曲线隔离+归属校验(A的设备不进B)、UsageCurve(deviceUUID)、
migration v18、客户端 widget(选设备→/v1/usage 带 device=)。全量 go/flutter 绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 08:04:33 +08:00

194 lines
9.0 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"meta": {
"title": "feature+windows — 项目 TODO",
"updated_at": "2026-06-29T00:04:33.913Z"
},
"seq": 12,
"items": [
{
"id": 1,
"title": "macOS 原生 KillSwitch 补齐 L0→L3",
"desc": "现状 L0(stub)VpnChannel.swift:69 setKillSwitch 直接 result(nil)、includeAllNetworks()→false。天花板 L3。改 NetworkExtensionincludeAllNetworks=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
},
{
"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
},
{
"id": 3,
"title": "Windows KillSwitch L1→L2 (WFP 防火墙强制)",
"desc": "现状 L1desktop_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
},
{
"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
},
{
"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
},
{
"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
},
{
"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": "done",
"created_at": "2026-06-28T00:26:44.498Z",
"done": false,
"completed_at": null,
"version": null
},
{
"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
},
{
"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": "done",
"created_at": "2026-06-28T09:32:26.008Z",
"done": false,
"completed_at": null,
"version": null
},
{
"id": 10,
"title": "统计页设备下拉接真实设备数据(依赖#上条)",
"desc": "统计重设计的设备下拉,先只挂「全部」上线;每设备归因打通后,把下拉填上「全部 + 近30天用过的设备名」,选设备走 /v1/usage/devices 过滤。依赖每设备归因 TODO。",
"level": "low",
"tier": 2,
"tags": [
"前端"
],
"status": "done",
"created_at": "2026-06-28T09:32:26.080Z",
"done": false,
"completed_at": null,
"version": null
},
{
"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": "open",
"created_at": "2026-06-28T11:27:56.637Z",
"done": false,
"completed_at": null,
"version": null
},
{
"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
}
]
}