Commit Graph

58 Commits

Author SHA1 Message Date
wangjia 6f232d4043 fix(routing): 堵住 ip_cidr direct 旁路系统层 + 客户端保存失败可见提示
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (push) Successful in 19s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 18s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (push) Failing after 13m6s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 13m16s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Failing after 13m25s
ci-pangolin / Go — build + test (push) Failing after 13m35s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (push) Failing after 13m45s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Failing after 13m54s
ci-pangolin / Flutter — analyze + test (push) Failing after 14m5s
ci-pangolin / OpenAPI Sync Check (push) Failing after 14m16s
ci-pangolin / Lint — shellcheck (push) Failing after 14m27s
分支审核发现两处 Important,合并前修复。

① [安全] direct 的 ip_cidr 用户规则可自伤式旁路整条隧道:
   Validate 原先只校 CIDR 语法。用户提交 ip_cidr=0.0.0.0/0 action=direct
   (或 172.16.0.0/12,含隧道 DNS 172.19.0.2)会并入 TUN 入站
   route_exclude_address(OS/auto_route 层,位于系统强制层之下),被排除的
   流量根本不进 sing-box → hijack-dns 与整条隧道被静默旁路,违反「系统层
   用户不可越」铁律。
   - Validate: direct 的 ip_cidr 拒绝 catch-all(/0)及与保留段 172.16.0.0/12
     重叠(写入闸)。
   - clientconfig 渲染层:新增 routing.SafeToExclude 守卫,只有安全的 direct
     ip_cidr 才并入 route_exclude_address(纵深防护,兜底写入闸之前的历史坏行)。
   - 测试 TestValidateDirectIPCIDRReservedGuard 钉死:拒 catch-all/隧道段重叠、
     放行 proxy catch-all 与不重叠 direct。

② [健壮性] 客户端保存失败静默回滚 + 抛未捕获异步异常 + 对话框无字段校验:
   _persist 失败会 rethrow(约定调用方 catch),但屏幕层所有回调
   (setMode/setBuiltin/addRule/removeRule/reorder/resetToDefault)均未 catch,
   规则闪现即消失、无提示,且 rethrow 变 zone 未处理异常。
   - 新增 _guardSave 守卫:await + 失败弹 SnackBar(AuthApiException 显服务端
     双语文案含校验错,其余回退通用「保存失败」),包裹全部变更类回调。
   - 添加规则对话框:_valueError 字段级预校验(ip_cidr 用 InternetAddress
     校验、geo 白名单仅 cn),非法即禁用保存并内联红字提示;语义级(保留段)
     仍由服务端权威判定经 SnackBar 呈现。
   - l10n 单源新增 routingSaveFailed / routingRuleValueInvalid(6 语),regen。

go test ./... 全绿;flutter analyze 无 error;flutter test 265 全过无 golden 回归;
codegen 幂等、原型 i18n 无漂移。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-08-01 00:32:52 +08:00
wangjia 2930d76cf3 feat(routing): 域名级系统锁冲突提示 + 重置默认按钮 + 客户端 follow-up 清理
承接 FT-A(GET /v1/me/routing 含只读 system_locked_domains)。

- RoutingProfile 加只读 systemLockedDomains(fromJson 读/toJson 不输出);
  routing_screen 冲突检测扩展到域名类规则(domain/domain_suffix/domain_keyword
  命中锁定域名 → systemLocked),ip_cidr 私网启发式保留。
- RoutingProfile.defaults() + RoutingProfileNotifier.resetToDefault()(复用
  _persist:乐观更新/失败回滚/存成功后自动重连,保留只读 systemLockedDomains
  不丢)+ routing_screen 加「重置默认」按钮与二次确认弹层(新增 3 个 l10n 键)。
- RoutingRule.copyWith 用哨兵支持 note 显式清空为 null;RoutingRule/Builtin/
  RoutingProfile 加值相等 operator==/hashCode。
- T8 smartRouteSub 清理:grep 全仓发现 design/prototype/i18n/alias.json →
  gen_proto_i18n.mjs(CI 漂移闸)仍有活引用,按计划口径不删,详见
  .superpowers/sdd/task-FTB-report.md。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 06:57:58 +08:00
wangjia 3159dd75c1 refactor(routing): 暴露 system_locked_domains + 服务端 follow-up 清理(FK/Validate/dedup/exclude单源/共用Store/Builtin保留) 2026-07-29 06:38:52 +08:00
wangjia 4c76c2a701 feat(routing): 存档案后连接态自动重连使新规则生效
Task 9: RoutingProfileNotifier._persist() 保存成功后,若 connectionProvider.phase
== on,触发 ConnectionController.reapplyRoutingProfile()(disconnect→connect,
不改选中节点)重连,让服务端按新档案渲染的规则生效;off 态不触发。

新增 l10n 键 routingRulesReconnecting(单源 design/i18n/strings.json → codegen),
「规则已更新,正在重连…」区别于既有 nodeReconnecting(弱网抖动语义)。

reapplyRoutingProfile 内先置 _userDisconnect=true 再 disconnect,避免其触发的
kernel off 事件被 _onKernelStatus 误判「意外掉线」、再抢跑一次 watchdog 自动重连。
2026-07-28 09:17:32 +08:00
wangjia d73b6da110 feat(routing): 分流规则子屏 UI(模式/内置/我的规则/添加/冲突提示)
- 新增 RoutingScreen(ConsumerWidget):代理模式段选(全局/智能/直连)→setMode、
  内置规则卡(国内直连开关 + LAN 强制锁定行)、我的规则 ReorderableListView
  (拖动排序→reorder、删除→removeRule)、添加规则弹层(类型 chip + 目标输入 +
  动作段选→addRule)、FINAL 兜底行。非智能分流模式「我的规则」区灰化+忽略提示。
- 冲突提示:①同 type+value 被更靠前规则遮蔽 →「已被上面规则覆盖」(纯本地计算);
  ②自定义 ip_cidr 规则落在私网/回环地址段 → 系统锁定提示(启发式,详见文件头注释
  ——真正的私有服务域名清单未经 API 下发给客户端,是已知缺口)。
- l10n 新增 9 个 key(routingTypeDomain/DomainKeyword/IpCidr/Geoip、
  routingRuleShadowed、routingModeNote、routingRuleValueHint、routingNoRules),
  经 design/i18n/strings.json 单源 + gen_l10n_dart.mjs 生成六语。
- 补生成 pangolin_icons.dart 的 plus 图标(design/prototype/icons.js 已有,
  codegen 之前未跑过)。
- 新增 widget 测试 test/widget/routing_screen_test.dart:模式段选/规则行/添加
  按钮可见、非智能模式灰化、重复规则遮蔽提示,共 3 例。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 08:51:40 +08:00
wangjia 49f62d9b14 feat(routing): GET/POST /v1/me/routing 端点 + openapi 2026-07-28 07:49:03 +08:00
wangjia c99a9b1106 Merge branch 'main' into feat/configurable-proxy
# Conflicts:
#	.gitignore
#	client/lib/l10n/strings_es.dart
#	client/lib/l10n/strings_ja.dart
#	client/lib/l10n/strings_ko.dart
#	client/lib/l10n/strings_ru.dart
#	docs/index.html
#	scripts/local_test.sh
2026-07-28 07:17:34 +08:00
wangjia fae73ff656 feat(proxy): 设置行模式 pill 反映当前分流模式(两端,随模式+语言联动)
设置页「Routing rules」行的模式 pill 之前静态显「智能分流/Smart routing」,不随实际
所选模式变。改为动态:
- pill 加 id=routeModePill,renderRouting 按 state.routeMode 设其 data-i18n(rr.modeGlobal/
  Smart/Direct)+ textContent(经 _ri 从 I18N 单源取)。切模式(seg 点击→renderRouting)即时更新。
- data-i18n 保留:切语言时 applyLang/applyI18n 用 pill 当前模式 key 重译 → 模式+语言双联动。
- pill 文案与 seg 一致(全局代理·Global / 智能分流·Smart / 全部直连·Direct)。

验收:两端语法通过、check-proto 全 resolve(rr.mode* 三态)、原型 --check 无漂移。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 11:37:12 +08:00
wangjia 64b1ec10c2 feat(i18n): 分流规则页静态标签接单源 + 修 mobile 设置行模式 pill 语言
路由页此前静态标签硬编码中文,EN 模式混语。全部接进 strings.json 单源:
- 新增 26 个 routing* 产品 getter(6 语):代理模式/内置规则/国内直连/我的规则/
  添加规则/从文本导入/重置默认/最终/直连·走隧道·拒绝/域名后缀/GeoSite 规则集/返回设置…
  (复用 smartRoute;seg 三项 EN 取短词 Global/Smart/Direct 适配段宽)。
- app_text.dart +26 抽象声明;重生成 6 份 strings_*.dart;alias.json desktop +24 / mobile +19。
- markup 加 data-i18n;JS pill(直连/走隧道/拒绝、FINAL)统一改从生成的 I18N 单源取(_ri),
  与静态 pill 同源。JS-owned 的模式说明 rtModeNote 保留 _t 双语(不加 data-i18n)。
- desktop LAN 行(此前未接)补接 rr.lan/rr.lanSub + 新 routingForcedPill。
- 修 mobile 设置行「Routing rules」的模式 pill:缺 data-i18n → EN 显中文,补 setSmartRoute
  (en=Smart routing,与 desktop 一致)。

验收:l10n 重生成+analyze 0 issue、原型 0 unresolved、生成器零 diff、244 测试全绿、无红线词。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 11:09:03 +08:00
wangjia a78364ebec fix(proxy): 添加规则「规则类型」改 chip 选择器(替原生 select)
原生 <select> 展开的是 OS 原生下拉(深色蓝高亮),浏览器不让改样式、与暖色设计
系统冲突(铁律 §14 禁原生默认外观)。改为设计一致的可选 chip 组:
域名后缀 / 域名 / IP-CIDR / GeoSite / GeoIP,选中=accent-subtle 底 + clay 字。两端同步。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 10:44:28 +08:00
wangjia 4a912b5af3 feat(proxy): 分流规则页交互 — 代理模式切换 + 添加/导入/重置(两端)
原型路由页此前段选与三按钮无事件、不重画。补齐(desktop + mobile 同步):
- 代理模式段选(全局代理/智能分流/全部直连)点击切换 + renderRouting 重画:
  非智能分流时「国内直连 + 我的规则」灰掉禁点、FINAL 兜底按模式变(全局/智能→走隧道、
  全部直连→直连)、模式说明随之更新。
- 添加规则→弹层表单(规则类型/目标/动作段选),提交插入规则行(首命中置顶)。
- 从文本导入→textarea,按「目标,动作」逐行解析插入。
- 重置默认→确认弹层,还原出厂规则表。
- 弹层内容 JS 双语渲染(state/S.lang),避免再造「EN 显中文」;复用现有 .dl-overlay/
  .rt-sheet + segswitch 范式;图标全取 icons.js 单源(refresh-cw/x/plus/download)。

注:路由页静态标签(段选/内置/FINAL 等)的整体 i18n 仍是独立后续(subagent 已标记的
19 个未接 rr.* 词汇 key)。本次聚焦交互,未改 I18N 生成块(--check 绿)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 10:35:49 +08:00
wangjia 75d23023e3 feat(i18n): ③ 原型接单源 — I18N 块由 strings.json 生成,消除重复翻译
原型 design/prototype/screens/{ui-desktop,ui-mobile}.html 的 I18N 数据块不再手写,
改由 strings.json 生成(marker 包裹、生成器唯一写):
- alias.json:protoKey → flutterKey(产品串取单源 zh/en,单源赢);desktop 130 / mobile 143。
- overlay.json:原型专属(开发挡板 + app 没有的串,zh/en);desktop 98 / mobile 104。
- new-strings.json:4 个新产品串(分流规则/自定义/局域网直连/强制),6 语,已并入
  strings.json + app_text.dart 抽象声明 + 重生成 6 份 strings_*.dart。
- gen_proto_i18n.mjs:strings.json+alias+overlay → 两份 HTML 的 I18N 块;--check 只比对
  marker 块(unrelated HTML 编辑不误报)。
- check-proto-i18n.mjs:两份 HTML 所有 data-i18n key 的 zh/en 必须 resolve。
- ci/check-codegen-drift.sh:加原型 i18n 段(--check 漂移 + resolution 验收)。

同带入之前路由原型 WIP 的 i18n 收口:私有服务内置行→局域网/私网直连行、rr.* 接 data-i18n
(rr.lan→routingLanDirect 等)。路由页其余 UI(段选/添加规则页)仍为独立后续。

验收(自复核全绿):生成器跑通、data-i18n 0 unresolved、两生成器重生成零 diff、
flutter analyze lib/l10n 0 issue、flutter test 244 全绿、new-strings 无红线词。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 09:59:18 +08:00
wangjia f46191ef4d feat(i18n): ③ 底座 — serve.mjs 暴露 canonical strings.json 给原型
原型与 Flutter app 共用同一份 design/i18n/strings.json(不在原型内复制):
- serve.mjs 加路由 /i18n/strings.json(及别名 /strings.json)→ 直读 ../i18n/strings.json。
- 原型 JS 可 fetch 同源翻译;完整 data-i18n key remap(3 套 key 空间对齐)为后续工作。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 08:57:47 +08:00
wangjia 13e0ba6d47 feat(i18n): ④ l10n 漂移闸 + codegen 改纯 node 确定性输出
- gen_l10n_dart.mjs 去掉 dart format:其输出依赖包解析状态、跨环境不稳(首次 4 空格、
  重跑 8 空格),会让漂移闸误报。改为确定性终态格式(list 单行 const [])。
  analyze 不校验格式,不影响;gen 现零 dart 依赖、纯 node 确定。
- ci/check-codegen-drift.sh 增 l10n 段:重生成 strings_*.dart → git diff 非空即 fail
  (与 token 段同法,纯 node)。
- 验证:往返无损、重生成零 diff(闸稳定)、flutter analyze 0 issue、244 测试全绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 08:55:21 +08:00
wangjia f76e3cdffd feat(i18n): l10n codegen — strings.json 单源生成 6 份 strings_*.dart
② 单源 codegen 落地:
- strings.json 补全 lists 段(days7/featsFree/featsPro/featsTeam),
  之前 extraction 漏了 4 个 List<String> getter;现 246 getter+4 list+5 method×6 语。
- design/codegen/gen_l10n_dart.mjs:strings.json → strings_{zh,en,ja,ko,ru,es}.dart,
  getter 转义 \$、method 保留 $var 插值,dart format 定型(保证漂移闸零 diff)。
- app_text.dart 保持手写(enum/abstract 声明/AppLangMisc 逻辑),编译器强制 concrete⊆abstract 兜底。
- 往返无损:生成的 Dart 重新抽取 == strings.json 逐字节一致;flutter analyze 0 issue、flutter test 244 全绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
2026-07-27 08:47:44 +08:00
wangjia 9ab550d398 feat(i18n): l10n 单源地基 — 6 份手写 Dart 抽成 design/i18n/strings.json
i18n 单源第一步(用户要求:原型与实际程序必须一份数据)。
- 246 getter + 5 带参方法 × 6 语(zh/en/ja/ko/ru/es),抽取校验 0 缺失
- 抓到真漂移:strings_en.dart 原缺 quotaExhaustedNotice/openAlipayFailed
  两个 key(双引号+EN漏维护),单源后六语强制对齐
- migrate_l10n_to_json.py 一次性迁移脚本(单/双引号 + getter/带参方法)

下一步:codegen(JSON→app_text.dart+strings_*.dart,替换手写)+ 原型读同源 + CI 漂移闸。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 02:48:39 +08:00
wangjia f1292b757c design(configurable-proxy): 修图标(补 plus/私有服务用 shield)+ 桌面补齐 + 模式语义
- icons.js 补 'plus'(原缺失致「添加规则」+ 空);私有服务图标 server(不存在)→ shield
- 桌面 routing 视图:内置规则加图标框(与移动一致)+ 从文本导入/重置默认已在
- 移动 routing 子屏:补「从文本导入/重置默认」
- 两端加模式说明:用户规则仅「智能分流」生效;全局/直连忽略(系统层仍强制)
- 说明文档加三模式语义表 + 系统层解释

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 02:26:48 +08:00
wangjia 27b9f0965a design(prototype): 分流规则深度嵌入真实 ui-kit(桌面+移动屏)+ 登记设计系统
不再用单独页,直接嵌进真实交互原型:
- ui-desktop: Smart routing 开关行→分流规则入口→ data-view=routing 子视图(setView 接线+i18n)
- ui-mobile: 智能分流行→分流规则入口→ data-sub=routing 子屏(subOpen 接线+i18n+返回回设置)
- 复用现有 .pill 语义(直连 is-success/走隧道 is-warning/拒绝 is-danger),不造新原子
- index.html 登记「分流动作」胶囊场景
- 删单独 routing-rules.html;搬入配置说明文档
全走 v2 真原子,设计系统闸绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 02:14:36 +08:00
wangjia f10e887c2a design(configurable-proxy): Settings页衔接(Smart routing→分流规则入口)+ 默认/自定义规则冲突处理
- Settings 的 Smart routing 二元开关演进为「分流规则」入口行(显示模式+chevron)
- 冲突处理:系统层永远赢>用户规则(有序首命中)>智能分流>FINAL;
  UI 主动标记①被遮蔽永不命中②撞锁定系统目标 两类冲突
原型加 before/after 对照 + 冲突可视化例;说明文档加对应章节。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 01:57:38 +08:00
wangjia 51317e9f43 design(prototype): 分流规则屏用 v2 真 ui-kit 重建 + 搬入配置说明文档(Task 3)
用 v2 设计系统真原子(.segswitch/.setting-row/.toggle/.card/.pill/.btn)建
screens/routing-rules.html(移动子屏 + 桌面设置窗口),替代独立 docs mockup。
配置说明文档搬入本分支 docs/。设计-first,待确认 4 取舍后出实现计划。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 01:48:22 +08:00
wangjia 542954e4ea design(prototype): 通知视图两端统一(pill式)+ reward/version/promo 示例与展开态 2026-07-13 13:36:16 +08:00
wangjia 3d24451835 fix(nodes): 桌面 Nodes 页统一 600 宽度(原型挂 view-body + Flutter PageBody)+ 双列网格改单列镜像原型
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 10:13:48 +08:00
wangjia e95995f20f fix(prototype): 桌面补 redeem 兑换视图 + accRedeemRow 接线改指 redeem(原为误指购买页) 2026-07-13 09:53:25 +08:00
wangjia fa9a5c2d5e design+client: 抽 .view-body/PageBody 统一桌面内容页宽度(600/wide 840)——stats·contact 补约束,settings·contact 560→600,九页收口
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 09:46:57 +08:00
wangjia b88921a030 fix(prototype): ui-desktop 补 [hidden] display:none 守卫——登录静态屏 signup 表单不再与 signin 并排溢出
.login-form{display:flex} 作者样式覆盖了 hidden 属性的 UA display:none,致带 hidden 的
signupForm 被顶出来与 signin 并排、溢出 760px 分屏卡被裁。补 ui-mobile.html:93 同款
[hidden]{display:none!important} 全局守卫;已审计全部 hidden 元素均用 .hidden 属性切换,
无 style.display 依赖冲突。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 09:29:39 +08:00
wangjia a48e38cac0 design(prototype): 回填邀请屏——战绩三格+TG任务卡两态+具体天数(镜像 invite_page.dart,补原型先行欠账) 2026-07-13 09:23:14 +08:00
wangjia 040e715479 fix(prototype): 桌面内容视图宽度统一 600 居中(账户/设置/设备/订单/通知/邀请一致)
设置原全宽、账户/通知/邀请原 600 左对齐、订单/设备 600 居中 → 全部 600 居中,去除设备内联冗余(靠 account-view 类)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 17:07:08 +08:00
wangjia 576e9ee5a5 design(prototype): 设备⋮弹出菜单(重命名/强制退出/清除登录信息) + 设备管理页宽度收窄600居中
- 设备行 ⋮ 加弹出菜单(本机仅重命名/他机三项,清除为 danger),复用 .menu 原子,外部点击关闭
- 设备管理页内容 max-width:600 居中(对齐订单/账户页,不再全宽)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 17:01:28 +08:00
wangjia 18858b33d4 design(prototype): 设备管理改下钻页 + 桌面登录页注册表单切换
- 我的设备:账户页内联列表 → 一行入口(计数+chevron)→ 独立设备管理页/子屏(完整列表+⋮操作),对齐真实 DevicesScreen + IA spec
- 桌面登录静态帧:「没有账户?免费注册」→ 切换到注册表单(邮箱/密码/确认密码 + 已有账户?登录 返回)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 16:47:10 +08:00
wangjia 53426bd4c1 fix(ds): .plan-banner 窄宽度按钮换行 + 名字保底宽度(修 Renew/Upgrade 覆盖用户名)
pbn-row flex-wrap + pbn-info min-width:96px:窄容器下按钮换到下一行、
名字不再被挤成 me…;宽屏按钮仍靠右。容器驱动,桌面/移动/手机框一并生效。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 16:44:52 +08:00
wangjia 7700c43216 design(prototype): 设备超限整合为全窗口挡板 overlay + 演示语言控件改 6 语言下拉
- 设备超限从脱离主窗口的独立静态帧 → 盖满可交互窗口的根级 overlay(还原真实 client 登录后挡板),桌面+移动,演示控制触发
- 顶栏演示段 LANGUAGE 从中/EN 两档 seg → 6 语言 langsel 下拉(与 Settings 一致;非中英回退英文内容)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 16:37:21 +08:00
wangjia 6ff048967e chore(prototype): 移除 setting-row 冗余 inline width(原子已带,防重复源) 2026-07-12 16:22:02 +08:00
wangjia 6f4be57ab8 fix(ds): .setting-row 加 box-sizing:border-box(width:100%+padding 出界修复)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 09:31:29 +08:00
wangjia 5002a4f35d fix(ds): .setting-row 原子按钮安全化(border/background/width/text-align 重置)
作 <button> 用时浏览器默认粗边框穿透 → 账户卡各行显重黑边。原子内重置,
保留 border-bottom 细分隔线。单源修复,所有 setting-row-as-button 一并生效。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 09:27:21 +08:00
wangjia 6f5a805536 design(prototype): 渲染新 IA 视觉稿(桌面+移动)— 含 bell 图标单源 + 通知/邀请预留
- icons.js 加 bell(codegen→pangolin_icons.dart,L1 同集 59)
- 侧栏提 Account 为一级/顶栏通知铃铛/Account 重排(购买&订单&兑换 + 邀请好友)
- Settings 归三组(连接/外观/关于)+ Web 链接降级;Contact 单源;兑换码仅码
- 通知收件箱 + 邀请好友 占位屏(细节各自 Spec ②③)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 09:08:25 +08:00
wangjia bcd3a0bbb1 design: 订单详情收据式布局重构(三屏一致)— 单卡+粘土条+撕裂线+去冗余
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-12 06:54:18 +08:00
wangjia f6ce5267d5 feat(design): 支付渠道 switch 原型 + segswitch 原子 + 图标/语言同源闸
- .segswitch 段控原子入 atoms.css + 登记 index.html
- purchase/ui-mobile/ui-desktop 三屏:购买页支付渠道 switch(USDT→crypto 默认 / 人民币→alipay),套餐价随渠道分币种显示,删两步弹层 + nezha
- 订单列表/详情集成进移动+桌面主框架
- icons.js 58 图标 sprite 单源 + gen_flutter_icons codegen + check-l1-sync 同源闸(图标同集 + l10n 完整)
- pay-v2 开发决策日志 docs/pay-v2-dev-log.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-11 23:45:55 +08:00
wangjia f37f1f3b59 feat(web): 修语言下拉漂移(class 化)+ 主页登录态用户中心按钮 + 用户中心返回主页
ci-pangolin / Lint — shellcheck (pull_request) Successful in 10s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 29s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 32s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 21s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 24s
ci-pangolin / Flutter — analyze + test (pull_request) Failing after 21s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 10s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 8s
ci-pangolin / Go — build + test (pull_request) Successful in 10s
Deploy Site / deploy-site (push) Successful in 2m33s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m33s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Successful in 19s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 13m16s
#1 官网语言下拉漂移:根因=官网 CSP 无 unsafe-inline,Header.jsx 下拉全用内联
style= 被浏览器拦→菜单飘视口右边。修:搬进 website.css 的 .langwrap/.langsel
/.langmenu/.langmenu a(全走 var(--token),right:0 锚按钮下方,min-width 160
加宽),Header.jsx 删净内联 style。

#2 主页登录态右上角「用户中心」按钮:Header.jsx 读同源 localStorage
'pg_uc_refresh',有则 .linklogin 位显「用户中心」(→ /user/)、无则「Log in」。
i18n nav.center 6 语言。

#3 用户中心「返回主页」按钮:UserCenter.tsx 顶栏加 <a href="/">(home 图标),
i18n backHome 6 语言。

顺带堵同源闸漏洞:check-l1-sync ③ 原只匹配带引号图标键('refresh-cw'),漏了
裸标识符键(home),导致新加的 home 未被校验就通过。修解析器匹配裸键;并按
ds-flow 把 home 登记进 design/prototype/icons.js。同源闸复跑绿(裸键现全受检)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:16:13 +08:00
wangjia 14a9836882 feat(ds-flow): Phase 5.1-5.2 — Flutter 裸色闸 + 原型校验闸
5.1 client/tool/check_ds_code.mjs(照 jiu):禁 Flutter 业务代码裸 Color(0x)/
具名 Colors.x;豁免 token 生成层(pangolin_tokens.gen.dart)+ 实现层
(pangolin_theme.dart);--changed(pre-commit)/--strict(CI)/全量三模式;
剥行尾注释防误报。现状 --strict 通过(0 违规,UI 层零裸色)。

5.2 design/prototype/tools/check-ds.mjs:原型单源守门,5 道——硬编码色(仅严格
扫 atoms.css)/未定义 token/font-family 走 var(--font*)/图标走 icons.js sprite/
组件原子在 index.html 登记;剥 CSS+HTML 注释防误报,SVG fill/stroke 豁免。
现状通过(serve.mjs 改动时自动跑)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 01:39:44 +08:00
wangjia 39324c46a7 feat(ds-flow): Phase 3 — Web 硬编码色清零 + 原子台账收敛
「各自实现 + 同源闸」决策落地(不建跨端组件包):

- website.css 页脚恒暗区灰阶就近吸附主题无关 sand 原色阶(cfc6b8→sand-300、
  a89e8e→sand-400、8a8070→sand-500),消除 5 处硬编码。
- check-l1-sync 白名单加品牌 logo 色 f4efe8(Brand.astro 内联 SVG fill)。
- usercenter 13 处硬编码全为 #fff(白名单),已干净。
- CONTRACT.md 增「§6 ds-flow Web 原子清单 + 屏级三态台账」:公用原子两端映射表、
  图标三端⊆原型、L2 屏级三态(Flutter 快照/Web 代码先行/原子层同步)、硬编码白名单。

同源闸 4 道全绿(token 值 · 图标⊆原型 · Web 无硬编码色 · 幂等零 diff)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 01:09:16 +08:00
wangjia f69696daae feat(ds-flow): Phase 2 — Web token 同源闸 check-l1-sync.mjs
tools/check-l1-sync.mjs:L1 跨端同源闸(纯 Node 零依赖),4 道:
① website tokens.gen.css token 值 ≡ 原型 tokens.css(:root+dark)
② usercenter public/colors_and_type.css 同上
③ 三端图标 ⊆ 原型 icons.js sprite(usercenter LUCIDE 键+路径、Flutter
   _byName 键)
④ Web 硬编码色扫描(白名单 #fff/#000+品牌 logo 色,ds-allow 行内豁免,
   排除生成的 token 定义文件)

现状:①②③ 全过(Web token 与原型一致、Web token 幂等零 diff、图标已收敛);
补原型 icons.js 的 'chart' 别名(Flutter barChart 用,先登记原型)。
④ 余 6 处 website.css 页脚灰阶/Brand.astro 近白 —— Phase 3 清理 worklist。
CI 接线见 Phase 5。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 01:03:36 +08:00
wangjia 83fce75c8c docs(ds-flow): Phase 1.6-1.7 — ui_kits 标 DEPRECATED + 真源指针收敛
用户定:ui_kits 暂留(整屏布局尚无 HTML 替代,重建属 L3 不在本轮),标废弃
不删。

- design/CLAUDE.md:顶部加「真源对照」横幅(令牌→prototype/tokens.css、原子
  →atoms.css+index.html、图标→icons.js、Flutter→client/lib/widgets、Web→
  web/*;colors_and_type.css 降级别名、design/flutter 已删、ui_kits DEPRECATED、
  _ds_manifest/_ds_bundle 历史派生物);§6「修改设计系统时」重写为 ds-flow 流程。
- design/ui_kits/DEPRECATED.md:醒目废弃标记 + 真源指引 + 暂留理由。
- 1.7:确认无构建/CI 消费 _ds_manifest/_ds_bundle/_adherence,登记职责交
  index.html,旧工具产物标历史派生物(不删,无消费者)。

Phase 1(原型单源三件套)完成。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:59:26 +08:00
wangjia ad845328fb feat(ds-flow): Phase 1.5 — 原型活登记页 index.html
design/prototype/index.html:设计系统组件登记簿(照 jiu 骨架,light/dark 双主题)。
顶栏主题切换(持久化 localStorage)+ 左侧 dnav scrollspy 导航 + 分区:
① 色板(clay/sand 色阶 + 语义 token,data-swatches 声明式随主题刷新)
② 字号梯度(display-xl→caption,中英分行不并排)
③ 圆角/间距/阴影比例尺
④ 公用组件(atoms.css 每个 class 一张展示卡,全变体全态含 disabled)
⑤ 图标库(icons.js 全 57 图标网格)

链 tokens.css + atoms.css + icons.js(相对路径,自包含)。
验证:每个 atom 类均登记、57 图标全展示、主题切换正常、文案脱敏无红线词。
评审:node design/prototype/serve.mjs → http://localhost:5180/

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:16:47 +08:00
wangjia 6def3edaed feat(ds-flow): Phase 1.4 — 原型图标 SVG sprite 单源 icons.js
design/prototype/icons.js:57 个 Lucide 图标的 SVG sprite 单源(零依赖,注入
隐藏 <svg> + <symbol id="i-*">,用法 <svg class="ic"><use href="#i-power"/>)。

路径全部来自权威来源、零手写:35 个取自 usercenter icons.tsx 内联路径、
22 个从 web/website/node_modules/lucide-react 包提取。覆盖三处并集
(usercenter 全键 ∪ Flutter pangolin_icons.dart ∪ website lucide 用量);
别名(loader-circle/chart-no-axes-column/play-circle/more-vertical 等)已解析。

供 Phase 2 check-l1-sync ③「三端图标 ⊆ 原型 sprite」同源闸校验。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:10:57 +08:00
wangjia 56f673791e feat(ds-flow): Phase 1.3 — 原型公用组件原子层 atoms.css
design/prototype/atoms.css:把分散在 preview 规格 / usercenter shared.tsx /
website css / Flutter widgets 的组件样式沉淀成 canonical 原子类,只引
var(--token)。含 .btn(primary/ghost/subtle/danger + 尺寸)、.card、.input
/.field、.pill/.badge(success/warning/danger/neutral 状态 + accent/outline)、
.langsel/.menu(对齐刚统一的自控语言下拉)。

明暗双主题靠语义 token 自动适配,文件内无 [data-theme] 分支。
验证:零硬编码色;45 个 token 引用全部在 prototype/tokens.css 有定义。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:04:52 +08:00
wangjia 805bf8e2ca feat(ds-flow): Phase 1.1-1.2 — 原型单源目录 + tokens.css 迁为真源
- design/prototype/serve.mjs:零依赖热重载预览服务器(照搬 jiu,check-ds
  存在性守护,Phase 5 前静默跳过)
- design/prototype/tokens.css:token 真源(现结构已满足 ds-flow 的
  base :root + [data-theme=dark],字节迁移保证 codegen 零 diff)
- design/colors_and_type.css:退化为薄 @import 别名(供历史 preview/*.html
  浏览器内引用;codegen 不再读它)
- 三个 codegen(Flutter gen_flutter_tokens / website+usercenter build-tokens)
  + drift 检查全部重指向 prototype/tokens.css
- 生成产物 diff 仅头注释源路径行,token 数值零变化(已验证)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:00:38 +08:00
wangjia 277d1c6e97 feat(client): toast 限定主显示区/自适应宽/上限80%/超长多行居中(1.0.26)
按真相源新规:toast 改为自定义 Overlay 实现(widgets/pangolin_toast.dart),完全控制布局——
不覆盖左侧栏(left=侧栏宽 desktop204/tablet232/mobile0)、宽度自适应内容上限主区80%、超长文本
多行、主区内水平居中贴底、淡入轻起;仍走语义 token 明暗适配。自动连接改用 showPangolinToast。
同步 design/CONTRACT.md §2 toast 规格(canonical=showPangolinToast)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 19:50:33 +08:00
wangjia 143104b861 docs(design): toast 规格入真相源 + 铁律14「UI 组件必须取自真相源」
- design/CLAUDE.md §1 加铁律 14:新增/改 UI 组件必须用真相源已定义的组件与令牌;
  真相源没有的先补规格再用,绝不在业务代码凭空造样式(如 Material 默认外观);须符合当前设计。
- design/CONTRACT.md §2 加 Toast/SnackBar 组件规格(surface 底/fg1 字/border 描边/md 圆角/floating,
  明暗自动适配),canonical 实现=pangolin_theme snackBarTheme。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 19:43:54 +08:00
wangjia b98ad9dce4 chore(design): stats-overhaul 设计 WIP — CONTRACT + ui_kits 统计页规格
stats-overhaul 的设计稿(CONTRACT.md + mobile/tablet/desktop ui_kits)。

注:这批 ui_kits 描述的是统计页「上聚合·下分设备」原方案;统计页后续已
重设计为「月/周/日 周期卡 + 设备下拉 + 两周折线」(见 client/lib/screens/
stats_page.dart)。设计稿与新页布局有出入,待更新到新布局(单列 TODO 跟踪)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 18:13:49 +08:00
wangjia e25649cd27 feat(client/ios): iPad tablet 正式适配——断点≥900 对齐设计源 + tablet golden 回归闸
- form_factor 触屏 tablet 阈值 600→900,对齐 design/ui_kits/tablet(1180×820 横屏
  侧栏):iPad 横屏/12.9″竖屏走侧栏,标准/11″竖屏回落 mobile 底 Tab,避免双栏挤压
- form_factor_test 补全断点边界(900/899)与各 iPad 尺寸用例
- 新增 tablet_pages_golden_test:四视图×明暗×中英 12 张 golden,注入演示数据
  (6 节点/周流量/30 天用量)让 2 列网格与周柱满渲染,作回归闸
- design/CONTRACT.md:tablet 像素契约(取自 tabapp.jsx)+ 逐屏验收清单
- 真机 iPad mini 6 视觉签核通过;141 测试全绿

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 10:00:14 +08:00