Commit Graph

765 Commits

Author SHA1 Message Date
wangjia 6f183ff0df feat(agent): SIGHUP 重读节点本地配置并热重渲染,不踢在线用户
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 02:15:27 +08:00
wangjia d216e157c3 test(agent): 覆盖 acl.json 被删时仍走 last-good 兜底
删文件走的是 LoadACLConfig 返回 (nil,nil) 的分支,与坏 JSON 的
err!=nil 分支不同,此前无回归覆盖。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 02:09:02 +08:00
wangjia 87d5afa703 feat(agent): 渲染时读取 ACL,内存+磁盘 last-good 保证 fail-closed 跨重启
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 02:01:45 +08:00
wangjia 4155fc8542 refactor(agent): route 块改由 buildRoute 统一产出,合并 ACL 与 WARP
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:52:39 +08:00
wangjia 597d6ab68b feat(agent): ACL 渲染放行/拒绝规则对,空白名单仍拒绝
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:40:11 +08:00
wangjia d4156b81e2 refactor(agent): cleanDomains 委托 cleanHosts,消除同包重复逻辑
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:32:43 +08:00
wangjia 6df7c9de44 docs(agent): 修复计划未闭合代码块 + Task 6 改用常驻测试校验样例
未闭合的 ```go 让 Task 4-6 的标题落进代码块,task-brief 无法提取;
Task 6 原用 go run 校验样例文件,该文件在 module 外无法解析 import,
改为常驻测试 TestACLExampleFileStaysValid,并断言样例 uuid 为占位符
以防真实 dp_uuid 入库。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:12:06 +08:00
wangjia e4d014ba99 feat(agent): 私有目的地 ACL 配置类型与 fail-closed 加载语义
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:07:15 +08:00
wangjia b71f6038ae chore: gitignore superpowers 执行暂存目录
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:02:37 +08:00
wangjia 9cbffbb727 docs(agent): 私有目的地 ACL 设计方案与实现计划
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 01:01:19 +08:00
wangjia dd721fafc8 fix(scripts): local_test.sh ipad 改走公司分发证书(ad-hoc),装机前核验签名主体
原 `ipad` 子命令用 `flutter run --release` 装真机,走的是 Xcode 工程的**开发**
签名。Apple 只把 Development 证书签发给团队里的**个人成员**(不存在组织版),
于是装到机上「设置→通用→VPN 与设备管理」里开发者显示成个人姓名,而不是
Yanmei (beijing) Technology Co., Ltd。

改为 ad-hoc 分发(Xcode 15+ 的 method=release-testing)+ 自动签名:
- 新增 write_ios_export_options() 生成 ExportOptions.plist(teamID=BYL4KQHMTN);
- `flutter build ipa --release --export-options-plist=…` 导出时由 Xcode 用
  **Apple Distribution: Yanmei…** 重签;
- 装机前解包 IPA 逐字比对签名主体(IOS_EXPECT_SIGNER),不符即中止 —— 防止
  以后无声退回个人证书;
- 用 devicectl 安装;仅当覆盖安装失败(旧包签名主体不同)才卸载重装,不无条件
  先卸(卸载会清空 app 数据要重新登录);
- 构建失败时提示新设备注册命令:光给 -allowProvisioningUpdates 不够,必须同时
  给 -allowProvisioningDeviceRegistration。

另外两处顺手修:
- 取 IPA 路径原写 `ls … | head -1`,在 set -o pipefail 下 head 提前退出会让 ls
  吃 SIGPIPE、管道返回 141,被 set -e 当失败终止脚本(实测复现,退出码 141)。
  改用数组 glob。签名主体提取的 `codesign | grep -m1` 同一个坑,改成整段捕获
  后用 awk 读完全部输入。
- API_URL 支持 env 覆盖(默认值不变),便于装生产地址的包做验证。

验证:bash -n 通过;shellcheck 无新增告警;
API_URL=https://api.yanmeiai.com bash scripts/local_test.sh ipad 无字天书
端到端 exit=0,日志确认"签名核验通过: Apple Distribution: Yanmei…"并装机成功。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-22 11:59:08 +08:00
wangjia e38c7e7c1c chore: gitignore 用全局通配兜住签名私钥/证书
签名私钥 pangolin-release.jks 实际躺在**仓库根目录**,而原规则只写了
client/android/*.jks 一层,根目录那份既未被 git 跟踪、也未被忽略 ——
一次 `git add -A` 就会把 release 私钥提交进库。

改为全局通配 *.jks / *.keystore / key.properties,并一并兜住 Apple 侧的
*.p12 / *.mobileprovision / *.provisionprofile(CI 与 local_test.sh 都会
在工作区落盘这些材料)。

已核对:仓库当前没有任何**已跟踪**文件匹配这些模式,不会把在库文件变成
untracked。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-22 10:57:10 +08:00
wangjia d5fc9c1c07 fix(client): 补 es/ja/ko/ru 支付文案 + 去掉 pubspec 重复依赖键
HEAD 上客户端编译不过,两处:

1. pay-v2 给 AppText 加了 28 个支付相关 getter,只补了 zh/en,
   es/ja/ko/ru 四个 Strings* 实现类没跟上 → non_abstract_class_
   inherits_abstract_member,flutter analyze/test/build 全挂。
   本次按 zh/en 原文补齐四语(购买/支付方式/USDT 收款/支付宝跳转/
   订单态等 28 条),用词沿用生命周期中文词的对应译法。

2. pubspec.yaml 里 url_launcher 声明了两次(line 23 与 line 30),
   yaml Duplicate mapping key 直接让 flutter 工具链抛异常。删掉
   后加的那条重复声明,保留带原注释的首条。

验证:flutter analyze 仅剩 3 条既有 info;flutter build ios --release
成功并已装到 iPad Pro 真机。(test/golden 34 个失败是既有 UI 漂移,
与本次改动无关——goldens 不涉及 es/ja/ko/ru。)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-22 10:38:27 +08:00
wangjia 74d8c857be feat(server): 私有服务域名分流(PANGOLIN_PRIVATE_SPLIT_DOMAINS)
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Failing after 11s
ci-pangolin / Cleartext Scan — Android 禁明文 (push) Failing after 9s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Failing after 9s
ci-pangolin / Lint — shellcheck (push) Has been cancelled
ci-pangolin / OpenAPI Sync Check (push) Has been cancelled
ci-pangolin / Flutter — analyze + test (push) Has been cancelled
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Has been cancelled
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (push) Has been cancelled
ci-pangolin / Go — build + test (push) Has been cancelled
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Has been cancelled
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Has been cancelled
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (push) Has been cancelled
家庭内网穿透域名(nas/git/win.yanmeiai.com)的客户端配置渲染:
- DNS 面: 系统解析器(type=local,底层网络)+私有域名规则置顶+reverse_mapping
- 路由面: 私有域名→强制走隧道,钉在 LAN 直连之后、国内分流(geoip-cn)之前
在家: 局域网 DNS 覆盖→私网IP→LAN直连零绕行; 在外: 锚点(frps@ali,国内IP)
不再被 smartRoute 分流成直连、避开安全组限源。env 不配置=行为零变化。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 07:22:16 +08:00
wangjia 4a98bccedc docs: iOS 绕过 App Store 分发 VPN 渠道调研(官方七渠道+国内灰产梯度+落地建议)+ 索引登记
ci-pangolin / Lint — shellcheck (pull_request) Successful in 10s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 23s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 20s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 37s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 25s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 6s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 10s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m49s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
ci-pangolin / OpenAPI Sync Check (pull_request) Failing after 12m23s
2026-07-13 20:31:35 +08:00
wangjia 6d22127210 fix(client/pay): 修 Android 拉起收银台失败(couldn't open ali)——AndroidManifest 加 <queries>(https/alipays 包可见性)+ _openRedirectUrl 去 canLaunchUrl 误判改外部→app内浏览兜底
ci-pangolin / Lint — shellcheck (pull_request) Successful in 13s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 28s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 21s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 38s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 12s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m42s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
ci-pangolin / OpenAPI Sync Check (pull_request) Failing after 14m51s
2026-07-13 20:14:03 +08:00
wangjia 68608d6471 feat(server/auth): 新用户注册欢迎通知——注册同事务插 reward 类到账(零孤儿)
ci-pangolin / Lint — shellcheck (pull_request) Successful in 13s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 24s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 20s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 34s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 36s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 11s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m37s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
CreateUserWithTrial 新增本地 Noticer 接口(同 InsertNoticeTx 签名,参照 reward
包做法避免 notices→auth 循环依赖);SQLStore 加 noticer 字段 + SetNoticer,
nil-safe。注册事务插完 trial 订阅、commit 前,若已注入 noticer 则同事务插一条
type=reward 的双语欢迎通知(标题/正文按 trialDays 参数化),失败即整事务回滚,
与 reward/pay 到账钩子同语义、零孤儿。main.go 在 noticesStore 构造后装配
authStore.SetNoticer(noticesStore)(authStore 提升到 if-block 外声明以跨块可见)。

顺带修复 isDuplicateKey 只认 MySQL 错误文案的 dialect 缺口——sqlite 下重复邮箱
注册此前会落入错误分支返回不透明的「auth: insert user」,而非 ErrEmailTaken;
现同时匹配 sqlite 的 "UNIQUE constraint failed"。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 19:03:18 +08:00
wangjia 70b950a084 chore(windows): installer 版本 1.0.72→1.0.73 对齐 pubspec
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 24s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 18s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 36s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 35s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m39s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 20s
ci-pangolin / Lint — shellcheck (pull_request) Failing after 14m37s
2026-07-13 18:24:40 +08:00
wangjia 823cae8e6e chore: bump 1.0.72+73 → 1.0.73+74(安全修复批测试包:设备override连接闸/promo TOCTOU/macOS自更新韧性/switchMethod)
ci-pangolin / Lint — shellcheck (pull_request) Successful in 14s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 22s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 40s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 36s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 6s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m42s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 21s
2026-07-13 18:14:03 +08:00
wangjia a62a2b1797 fix(server/pay): promo 限购 settle 侧幂等复查 + 000027 部分唯一索引(TOCTOU)
ci-pangolin / Lint — shellcheck (pull_request) Successful in 11s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 19s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 41s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 20s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 5s
ci-pangolin / Go — build + test (pull_request) Failing after 14s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 11s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m44s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 20s
ci-pangolin / Flutter — analyze + test (pull_request) Failing after 11m55s
CreateOrder 下单时的 HasPaidPurchase 只是裸 SELECT 无锁,并发/多挂起单可绕过
promo SKU「每账号限购一次」。两层修:
① webhook.go settle 在锁行、开通前对 item.Promo 的 SKU 复查一次(排除本单),
   命中说明另一笔同 user+SKU 订单已抢先 settle,跳过发放(不二次 +N 天)、
   仍 ack(否则 pay 无限重投)。新增 store.HasPaidPurchaseExcludingTx /
   MarkDuplicatePromoTx——重复单标记 canceled 而非 paid,避免自撞下面的
   唯一索引、也避免整笔 500 触发死循环重投。
② migration 000027(sqlite):部分唯一索引 ux_pay_promo_paid ON
   pay_purchases(user_id, sku) WHERE status='paid' AND sku='pro_month_promo',
   兜底防止任何路径把同一用户的 promo 单二次写成 paid。mysql 8 不支持部分
   索引,000027 mysql 侧是 no-op 占位(仅对齐编号),该场景 mysql 只靠①的
   应用层复查兜底——两库防线强度不同,已在迁移文件与代码注释中记录。

副作用:新增迁移把 sqlite 迁移顶点从 26 推到 27,同步更新
internal/store/sqlite_migrate_test.go 的版本断言,以及
internal/store/codes_lib_migrate_test.go 手动 Steps(-1) 序列(补一步跳过
000027,才能精确落在 000022 边界,这条测试是硬编码步数的)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 15:53:56 +08:00
wangjia ec4b3e0f22 fix(web): 注册卡片 async 回调加卸载守卫(I8);核实 I7 res.text() 已在 try 内(无需改)
RegisterCard.jsx onSendCode/onRegister 里 await callApi 期间组件若已卸载(用户导航离开
注册页),之后的 setState 会打到已卸载组件——加 mountedRef 守卫,对齐文件内既有
cooldownRef/redirectRef 的 unmount 清理写法。InviteCard.jsx onCopy 的 1.5s setTimeout
从未 clear,存 ref 并在卸载时 clear。

I7(callApi 里 res.text()/res.json() 读 body 阶段断连,声称在 try 之外)经核实:
callApi 自创建(65ce266)起,res.text()+JSON.parse 就已在独立 try/catch 内(279-286行),
断连会被捕获、data 置 null,不会产生 unhandled rejection;未做改动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 15:53:40 +08:00
wangjia 301e13f477 fix(client/payment): switchMethod 补 catch-all 兜网络/超时错(与 start/resume 对齐)防卡 awaitingPayment
switchMethod 的首个 retry() 调用只 catch AuthApiException,网络/超时/未知异常会穿出到
无 try/catch 的 _pickAndSwitch,UI 卡在 awaitingPayment 无任何提示。补一个 catch-all,
与 start()/resume() 同一处理形状落 failed 相位(自动经 build() 切到 _failed() 呈现);
payment_page.dart 的 _pickAndSwitch 再加一层防御性 try/catch + toast,防任何逃逸异常
变成无提示的 unhandled rejection。补单测覆盖非 Auth 异常路径。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 15:53:30 +08:00
wangjia 3acd3ca59d fix(client/update): macOS 自更新失败韧性——回滚校验/提权自愈防换丢+codesign验签闸+超时不硬动+退出码检
- C3(critical): swap_plain 静默回滚后校验 $APP 是否真的复原(引入返回码语义 0/1/2/3),
  提权 ROOT_SH 改为自愈式(优先从 $BACKUP 复原、$NEW_APP 兜底直接就位),不再假设 $APP
  一定存在;新增终检,任何失败组合下都保证 /Applications 里最终有一个可用 app,不再
  出现"app 消失、零提示"。
- I1: PID 等待超时(~30s)后追加 5s 宽限,仍未退出则放弃换装、不硬动运行中的 bundle。
- I2: 换装前对 $NEW_APP 跑 codesign --verify --deep --strict,验签不过拒绝换装(回退访达)。
- I3: open "$APP" 检退出码,失败记日志(Gatekeeper/TCC 拦截时不再误记 relaunched)。
- M1: Dart 侧 helper chmod +x 检退出码,失败清理半截暂存目录;shell 侧 ROOT_SH chmod
  同样检退出码。

正常成功路径行为不变;helper 抽出后 sh -n/bash -n 语法检查通过;flutter analyze 0 issues。
逐失败分支(自愈从 BACKUP 复原、仅剩 NEW_APP 兜底就位、彻底不可恢复诚实失败)已用隔离目录
跑真实 mv 逻辑人工核对,报告见 .superpowers/sdd/fix-macos-updater-report.md。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 15:52:35 +08:00
wangjia 1e102a5a79 fix(server/nodes): 连接设备上限闸读 max_devices_override(登录闸已读,连接闸漏)
EntitlementForUser 是每次连接 backstop(httpapi/nodes.go DEVICE_LIMIT_EXCEEDED)
唯一读的设备上限来源,但订阅命中分支与 free 兜底分支都从未读 users.max_devices_override
(migration 000025)——运营设 override 只对登录闸(devices.ResolvePlan)生效,一连 VPN
仍按套餐默认上限被拒。两分支统一叠加 override(NULL/<=0 不生效,正值覆盖,语义与
devices/store.go:GetMaxDevicesOverride 一致),新增 sqlite 用例覆盖 free 无覆盖/
free 覆盖/pro 覆盖收紧/NULL-0 不生效四种场景。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 15:47:15 +08:00
wangjia ed99e2943e fix(openapi): Notice.id string/uuid→integer/int64 + body_zh/en 移出 required(对齐实际实现,终审建议)
ci-pangolin / Lint — shellcheck (pull_request) Successful in 9s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 27s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 17s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 40s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 37s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 3s
ci-pangolin / Go — build + test (pull_request) Failing after 12s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 9s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 8m9s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:22:00 +08:00
wangjia 5e9bb9e611 docs: 通知机制实现计划 HTML 阅读版 + 索引登记 + 设计互链 2026-07-13 14:15:05 +08:00
wangjia 2b4350cfc4 feat(server): 装配 notices(路由替换空壳+reward/pay 注入)+ 发版联动插 version 公告
main.go 挂载 notices.Store/Handler:注入 rewardSvc/payWebhook 到账通知钩子,
/v1/notices 路由由 accountAPI 空壳换成真实 List/MarkRead,删除 account.go
的 TODO 空壳方法。补齐 pangolin-nodectl 到编译/部署产物链
(compile-backend.sh + deploy-server.sh),release-client.sh 在
version.yaml 推送成功后追加一步用 nodectl 插入 version 类型站内公告
(失败不阻断发版)。
2026-07-13 14:09:54 +08:00
wangjia 78fd600522 feat(client/notices): 通知页真实化+铃铛红点接 provider+进页清读+三类型标签六语
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 14:05:47 +08:00
wangjia 84b162e834 feat(nodectl): notice add/list/revoke 子命令(校验+审计+可选邮件) 2026-07-13 14:01:50 +08:00
wangjia 75ec361542 feat(server/notices): Service — 发布校验/审计/important 邮件兜底(幂等) 2026-07-13 13:51:28 +08:00
wangjia e1e198e169 feat(server): 到账通知四接缝(邀请注册/首充/TG/购买开通)——与发放同事务零孤儿 2026-07-13 13:49:09 +08:00
wangjia 6a782a07fd feat(client): notices api + provider(未读计数/markAllRead/延迟首拉)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 13:48:12 +08:00
wangjia 0325603470 feat(server/notices): GET /v1/notices(合并+unread_count)+ POST /read + openapi 扩展 2026-07-13 13:43:50 +08:00
wangjia ed1f805cbc feat(server/notices): Store — 广播∪定向合并查询/已读水位/事务内插通知
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 13:36:32 +08:00
wangjia 542954e4ea design(prototype): 通知视图两端统一(pill式)+ reward/version/promo 示例与展开态 2026-07-13 13:36:16 +08:00
wangjia 21a30aa4c8 feat(server/migrate): 000026 notices 表 + users.notices_read_at 已读水位
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 13:32:23 +08:00
wangjia 0657a830d0 docs(plan): 系统通知机制实现计划(11 任务 TDD)
ci-pangolin / Lint — shellcheck (pull_request) Successful in 12s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 24s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 19s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 39s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 18s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 32s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 3s
ci-pangolin / Go — build + test (pull_request) Failing after 10s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 5m7s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 20s
迁移000026 → notices.Store → handler+openapi → 四事件钩子(同事务) → Service邮件兜底
→ nodectl notice → main装配+发版联动 → 原型统一 → client api/provider → 通知页+红点+l10n → 文档。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:30:28 +08:00
wangjia e195d037a4 docs: 系统通知机制设计文档(Spec ③)
ci-pangolin / Lint — shellcheck (pull_request) Successful in 15s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 28s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 21s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 36s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 20s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 11s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m36s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 21s
ci-pangolin / Flutter — analyze + test (pull_request) Failing after 11m37s
App 内统一通知收件箱,六类(重要/新特性/新闻/到账/版本/活动)。
单 notices 表+user_id(NULL=广播);已读服务端 last_read_at 水位;
GET /v1/notices(合并+unread_count)+POST /read;生产三路(nodectl/
事件钩子同事务/发版联动);邮件仅 important+显式 --email。
含数据流 SVG;登记 docs/index.html;与 Spec② 奖励事件接缝正式接通。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:21:26 +08:00
wangjia ab84a3542a refactor(website): 邀请/注册页语言跟随站点路由(六语变体),移除卡内 zh/EN 切换
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 22s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 8s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 22s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 9s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Go — build + test (pull_request) Failing after 17s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 9s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m30s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 20s
ci-pangolin / Flutter — analyze + test (pull_request) Failing after 12m46s
ci-pangolin / OpenAPI Sync Check (pull_request) Failing after 12m57s
ci-pangolin / Lint — shellcheck (pull_request) Failing after 13m6s
2026-07-13 12:50:24 +08:00
wangjia b48097469e fix(website): 落地页/注册页标题防孤字折行(text-wrap:balance + 字号收档)
ci-pangolin / Lint — shellcheck (pull_request) Successful in 13s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 17s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 37s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 21s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 32s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 3s
ci-pangolin / Go — build + test (pull_request) Failing after 12s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 9s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m31s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 20s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:39:01 +08:00
wangjia 94266804bc fix(server/reward): 邀请发放审计 target 带对方 id(invite:reg:invitee=N 等,替换静态占位串)——审计可回答「因谁而发」
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 24s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 22s
ci-pangolin / Lint — shellcheck (pull_request) Successful in 6s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 34s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 31s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 9s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 11s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m37s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Failing after 14m46s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:24:27 +08:00
wangjia 65ce2664ee feat(website): 独立注册页 /register(邮箱/邀请码预填+验证码注册+平台匹配下载)+ 主页/落地页跳转接入 + 登录态隐藏注册入口
ci-pangolin / Lint — shellcheck (pull_request) Successful in 13s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 23s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 34s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 21s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 34s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 8s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 8s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m34s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 12:20:32 +08:00
wangjia 254db4f40d feat(website): 邀请落地页 /i/<code> —— 显码+复制+奖励说明+下载引导(CF Pages _redirects 重写)
App 分享的邀请链接 /i/<8位邀请码> 此前回落主页;CF Pages 静态托管加 _redirects
把 /i/* 统一重写到 /i/ 的静态产物,邀请码本身由 InviteCard.jsx 在浏览器端从
location.pathname 解析并按 server/internal/reward/service.go 的字母表校验格式。
奖励文案对齐客户端 strings_zh/en.dart 的 inviteReward* 措辞;因邀请码只在运行时
可知,该页正文用 .langseg 胶囊做 zh/en 单显运行时切换,Header/Footer 仍走全站
i18n 惯例整页单显中文;下载按钮指向主页 #download 锚点。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 12:04:45 +08:00
wangjia 2c94b53a9e fix(server/reward): TG bot 回复区分已领取/未加入两态 + 按 Telegram language_code 中英双语
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 24s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 23s
ci-pangolin / Lint — shellcheck (pull_request) Successful in 6s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 36s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 34s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 3s
ci-pangolin / Go — build + test (pull_request) Failing after 11s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Failing after 10m52s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m33s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 11:46:55 +08:00
wangjia 66422f92ce fix(client): created 单详情补「取消订单」按钮(原型 pending 双按钮早有规格,代码漏)+ 自动连接 toast 3s→1.5s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 19s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 23s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 19s
ci-pangolin / Lint — shellcheck (pull_request) Successful in 6s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 34s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 36s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 5s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m42s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 21s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10m19s
ci-pangolin / Go — build + test (pull_request) Failing after 10m26s
- orders 详情 created 态:继续支付(主)+ 取消订单(ghost)——orders.html/ui-desktop 原型
  pending 态早已登记双按钮,Flutter 侧漏实现(代码落后原型)。取消走远程 cancel,
  失败(如其实已付,pay 409)不报错,统一 invalidate 刷新以最新状态为准。
- 自动连接「正在自动连接到 X」toast 缺省 3s 用户反馈偏长 → 1.5s(与「已复制」1.4s 同量级)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 11:43:48 +08:00
wangjia 1c2ec2844d feat(server/pay): 优惠套餐(Promo SKU)每账号限购一次——已付过再下单 409 PROMO_ALREADY_USED
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 23s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 17s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 18s
ci-pangolin / Lint — shellcheck (pull_request) Successful in 6s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 35s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 32s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 10s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 9s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m40s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 21s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 11:36:24 +08:00
wangjia 92943258ab fix(client/orders): 继续支付改为 retry 恢复原单会话(原误进购买页致重复下单);409 已付自纠刷新
ci-pangolin / Lint — shellcheck (pull_request) Successful in 12s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 20s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 32s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 21s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 38s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 2s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 5s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 4m50s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 20s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 11:29:25 +08:00
wangjia 07c339c18e feat(server/devices): users.max_devices_override 单用户设备上限覆盖(NULL走套餐默认)+ 迁移000025
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 23s
ci-pangolin / Cleartext Scan — Android 禁明文 (pull_request) Successful in 16s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 39s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 19s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 36s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 3s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Failing after 13s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 10s
ci-pangolin / Go — integration (mysql/redis testcontainers) (pull_request) Failing after 5m8s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (pull_request) Failing after 19s
ci-pangolin / Lint — shellcheck (pull_request) Failing after 13m37s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P9G7E3wmAYL9KeYCVZVsqu
2026-07-13 10:15:07 +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 a61641b53b refactor(client): SubScaffold 六合一(视觉零变化)+ tablet 注释订正 + 平板通知铃入口(#20) 2026-07-13 10:07:18 +08:00