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
镜像账户级时区曲线到「按设备」: - 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>
194 lines
9.0 KiB
JSON
194 lines
9.0 KiB
JSON
{
|
||
"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。改 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
|
||
},
|
||
{
|
||
"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": "现状 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
|
||
},
|
||
{
|
||
"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
|
||
}
|
||
]
|
||
}
|