Blizzard
3db2de1ef6
feat(billing): 支付 P5.3 —— 掉单补偿定时器 + admin 订单流 + 日终对账
...
支付线封口。此前 pending 单只在「用户开着账单页轮询」时才查单确认——用户扫完码
关页面,钱付了、积分永不到账。
- 掉单补偿定时器(payment_reconcile.go):gateway 内每分钟扫 pending 微信单,
逐单 reconcileOrder 主动查单落态。把「用户在不在场」从入账链路摘掉。
reconcileOrder 从 BillingOrderStatus 抽出、前端轮询与定时器共用一份幂等
落态逻辑(不重蹈 GenerateReport/SubmitTask 的漂移)。渠道未配置时空转不炸。
- admin 订单流 GET /admin/orders(状态计数+全平台订单,可筛)。
- 日终对账 GET /admin/orders/reconcile:paid 单 ↔ 账本 grant 分录逐单比对,
抓 order_without_ledger(钱到了积分没给,最严重)/ ledger_without_paid_order。
- admin 计费页「充值订单与对账」块:计数卡片+订单流+一键对账。
⚠️ live 抓到并修掉一个真 bug:OrderStats 复用同一个 gorm.DB 链式 Count 三次,
WHERE 累加成 status=A AND status=B → 恒 0(订单流显示 2 单但计数全 0)。
改成每次起新 query builder。—— 又一次只有 live 才暴露的。
验证:go 6 包测试+tsc+41 vitest 全绿;live 造差异单对账正确抓出
order_without_ledger、清账后回零差异;补偿器启动日志+渠道未配置空转不炸;
浏览器验订单流卡片+一键对账绿条。TTL 过期路径需真渠道触发,部署后自然覆盖。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-18 11:25:37 +08:00
Blizzard
5d7eca5de3
fix(billing): 微信支付钉死「微信支付公钥」验签体系 —— 商户 2025-09 开户没有平台证书
...
用户拿旧项目代码对出来的真问题:我此前用 WithWechatPayAutoAuthCipher(平台证书
模式,APIv3 密钥自动下载平台证书验签),但 2024 起新注册商户只发「微信支付公钥」
(PUB_KEY_ID_ 开头)、没有平台证书——在该商户号上初始化/回调验签都会挂。
- 改 WithWechatPayPublicKeyAuthCipher(商户私钥+公钥ID+公钥文件);回调验签用
NewSHA256WithRSAPubkeyVerifier;平台证书模式不留双模式赘肉(YAGNI)。
- Config 增 public_key_path/public_key_id(必填,公钥文件同样只存路径);
admin 卡片补两字段;env 兜底加 WECHAT_PUBLIC_KEY(_ID)。
- 顺手修 live 撞出的真 bug:sundynix_setting.value 是 varchar(255),
支付配置 JSON(含加密密钥)一条就超(SQLSTATE 22001)→ 改 text。
live:列类型已迁 text;缺公钥两项报「配置不全,缺: public_key_path,
public_key_id」;GET 回显含新字段。go 6 包测试+tsc+41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-17 11:12:26 +08:00
Blizzard
d1e1e0fc4a
feat(billing): 微信支付配置进 DB —— admin 控制面保存即热生效
...
用户定的形态:配置存数据库、密钥文件放服务器磁盘(库里只存路径)。
env 降级为兜底(DB 优先 → env → 隐藏,与 tokens_per_credit 同一约定)。
- payment 包重构:Config(6 字段)+ Manager(RWMutex 热重载,学 prompt 控制面
改完即生效不重启);未启用原因人话化(未配置/缺哪些字段/初始化失败具体错)。
- APIv3 密钥入库前 AES-GCM 加密(shared/secrets,与模型 API Key 同一把
SUNDYNIX_SECRET_KEY);GET 只回 has_apiv3_key 不回显;PUT 留空=沿用旧密钥
(只写不回显语义,同模型 Key)。
- admin GET/PUT /admin/payment/wechat;业务路径全部改经 Manager.Current()
取快照(BillingPacks/下单/查单/回调)。
- admin 计费页「微信支付配置」卡片:状态徽章(已启用/未启用+原因)+六字段
+保存并热生效。
live:无配置→「未配置」;存假配置→热重载报「私钥加载失败:decode err」;
去掉 appid→「配置不全,缺: appid」;密钥留空沿用(has_apiv3_key 保持 true);
psql 复核库内密文 enc:1: 前缀、不含明文子串。go/tsc/41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-17 10:55:30 +08:00
Blizzard
929bbf334b
feat(admin): 计费页长出「充值渠道」块 —— 兑换码生成/台账 + 积分包定价
...
P5.1 收尾:此前生成码只有 API。计费页现在从上到下 = 计费规则(积分→token
汇率) → 充值渠道(钱→积分:兑换码 + 微信定价用的积分包) → 用量观测,
两层汇率在同一页可见、各管各的。
- 兑换码:面额/张数/备注生成;**明文码只在生成响应显示一次**(等同现金,
台账 GET /admin/redeem-codes 服务端脱敏只露首尾,丢码重生成、不提供找回
——顺手把接口这个第二明文出口堵了);台账含核销状态。
- 积分包:新增/上下架(微信 P5.2 上线前把定价面备好);admin api.ts 补
packs/redeem-codes 四个函数。
- launch.json 加 admin-console-alt(:5176)——5174 被用户自己的 sundynix-site
占着,不动别人端口。
live:5176 登录→生成 5 张(绿色一次性面板+复制全部)→配「入门包 1000分/¥9.9」
在售可下架→台账脱敏 curl 复核;tsc+41 vitest 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-17 10:28:03 +08:00
Blizzard
b388915fff
feat(admin): 租户页加「共享计费」开关(每租户)
...
TenantRow 带 shared_billing;选定租户成员区上方加共享计费开关(PUT
/admin/tenants/:id/shared-billing):开=成员消耗计本租户池、关=各计个人池。
live 验证:公司A 开关随真实状态回显为勾选。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-08 10:56:21 +08:00
Blizzard
aa10037511
feat(admin): 「租户 & 用户」页接真实成员管理(删掉 mock)
...
此前整页是硬编码 mock(假租户/假用户/假 API key/假日预算)。重写为真数据:
- 左:租户目录(listTenants:名称/slug/plan/成员数/积分余额)+ 建租户表单
(名称/slug/可选 owner 邮箱)。
- 右:选定租户成员表(listMembers)——按邮箱加成员+选角色、行内改角色、移除;
owner 受保护(不可改角色/移除)。api 加 listTenants/createTenant/listMembers/
addMember/setMemberRole/removeMember。
live 验证(preview):14 个真实租户带成员数/余额;UI 加 demoB→Dexter「2 成员」、
成员表 owner 保护 + 成员可改角色/移除、移除后回 1 成员,全过;tsc + 41 测试全过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-08 10:20:11 +08:00
Blizzard
b46382817c
feat(admin): 计费页加「余额硬拦截」开关 + 各租户「充值」按钮
...
闭合积分环的配置/操作端,接到 P4 后端:
- 计费规则区:加「余额硬拦截」开关(credit_enforce),与汇率合成一个「保存规则」。
- 用量观测·租户排行:每行加「充值」按钮(正=充值、负=校正),调 /admin/credits/grant,
充值后即时刷新余额。
- api:getBillingConfig/saveBillingConfig 带 credit_enforce;新增 grantCredits。
live 验证(preview):开关渲染+可存;点公司A「充值 10」→余额 5.92→15.92、账本落对租户;
tsc + 41 vitest 全过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 13:53:52 +08:00
Blizzard
11d321f218
feat(admin): 计费 & 用量合成一页 —— 顶部配规则、下方看结果(闭环)
...
按"配置和观测放一个页面"收口:删掉重复的「计价 & 预算」页(其预算区块是 mock),
把真·计价配置并入「计费 & 用量」,形成 规则→扣费→观测 一页闭环。
- 新组件 BillingRules:全局 token→积分汇率 + 每模型 单价/币种/积分权重(读写
/admin/pricing + /admin/billing-config),改完对后续任务实时生效。
- UsagePage:顶部「计费规则」(配置端) + 下方「用量观测」(按规则折算后的实际消耗)。
- 删 PricingPage + /pricing 路由;api 加 credit_weight / getBillingConfig / saveBillingConfig。
live 验证(preview):改汇率保存→持久化→新任务按新汇率扣→用量观测反映;
tsc + 41 vitest 全过;无 PricingPage 残引。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 13:26:33 +08:00
Blizzard
54de95aa53
feat(admin): 用量 & 计费页 —— SaaS P2 计量观测面(读 /admin/usage)
...
管理端「分析」组新增页:全平台 / 单租户的 token · 积分 · 成本口径。
- api.adminUsage():拉 /admin/usage(含 trend / totals / tenants 排行 / 单租户余额);
微单位(×10⁻⁶)前端 ÷1e6 展示。
- UsagePage:租户下拉 + 近7/30天切换;KPI 卡(积分/Token/成本/余额或活跃租户);
积分消耗按天条形趋势(补零连续);全平台口径下各租户排行表(点名下钻单租户)。
- routes 注册 /usage(HashRouter)。
live 验证(preview):全平台两租户排行 + KPI + 趋势条渲染正确;点租户下钻→
单租户口径 + 当前余额卡;数值与后端自洽;无 console 错误;tsc + 41 vitest 全过。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 12:38:33 +08:00
Blizzard
55d50417a9
feat: 模型健康/熔断态 surface 到管理端(T4.F 可观测)
...
failover/熔断的运行时态原来只在 dispatcher 日志、admin 看不到 —— 本次接到概览可见:
- harness: CircuitBreaker.Snapshot() 只读观测访问器(state + fails,不动状态机)
- llm: Pool.ModelHealth() 上报主备链每模型 {provider,model,role,state,fails};
buildWithFallbacks 把模型名↔breaker 配对(同包直接读 failoverModel.breakers);
newFailoverModel 改返回具体类型以便读 breakers
- dispatcher 心跳 payload 加 models[]
- gateway /admin/overview 独立超时 Ping dispatcher,合并进 models.health
- admin 概览「模型路由」新增「运行时链路态(实时)」:逐模型状态点
(🟢 在线/🔴 熔断中+失败数/🟡 半开探测/单点)
- 单测:Snapshot、Pool.ModelHealth(名字↔态配对/单点/空)
- live:配坏主→提交任务打熔断→概览显示 broken-demo「熔断中·失败3」,备用在线
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-06 12:00:13 +08:00
Blizzard
a830ae2a04
feat(admin): 审计 & 安全事件页(T4.B 收尾)
...
- 新增「审计 & 安全」页(/audit,运维组):接 /admin/audit + /admin/guardrail-events
- 安全事件:护栏拦截/灰区放行(kind 徽标 + 原因 + method/path + actor/ip/时间)
- 操作审计:变更操作(方法配色徽标 + 路径 + 状态码着色 + actor/ip/时间)
- 顶栏统计(操作留痕/护栏拦截/灰区) + 30s 自刷 + 手动刷新
- api.ts 增 listAudit / listGuardrailEvents + 类型
- 风格对齐重做后的服务状态页(中性克制)
- T4.B 整组完成(剩 HITL 审批明细可选小项)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-02 09:43:41 +08:00
Blizzard
30e80c0eed
feat(admin): 提示词控制面页 + 概览/状态页重做 + 接入 vitest
...
- 新增「提示词」页(/prompts):接 /api/v1/prompts,建版本/激活热下发/
对比激活版行级 diff/撤销,挂到配置组
- 概览页重做为系统控制塔:吃 admin/overview(全平台口径)——平台任务/
评测/用户规模/服务在线 + 模型路由态 + 提示词覆盖态 + 健康拓扑 + 30s自刷
- 服务状态页重做:中性克制风 + 请求链路做成深色实时数据管道(流动光点/
节点辉光) + MCP 工具改能力域配色小卡片
- 接入 vitest(此前零测试):41 单测(api 控制面/lib diff/路由派生)
- api.ts 增 statsOverview/adminOverview/prompt 控制面四接口 + groupPrompts
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-02 08:59:40 +08:00
Blizzard
2d9695e940
feat: admin端UI
2026-06-27 12:06:29 +08:00
Blizzard
a5fd251fc0
feat(deploy): 容器化 + 一键独立部署 —— 5 服务镜像 + prod compose + 安装/备份/许可
...
此前应用服务只是本机裸二进制、无 Dockerfile、无法交付。本提交把项目从"只能在我笔记本
跑"变成"任何人一条命令起一整套",是「演示 / 拉投资 / 卖给客户独立部署」的可交付基础。
- Dockerfile ×5:gateway/dispatcher/mcp-go 多阶段(distroless static, 36–55MB);
mcp-py(python-slim, 268MB);admin(node 构建→nginx 托管 SPA + 反代 /api,76MB)。
Go 构建上下文为仓库根以兜住 replace ../sundynix-shared;.dockerignore 瘦上下文。
- docker-compose.prod.yml:应用 + 基建一把起;经服务名互连(顺带避开 localhost DNS 坑);
基建端口不对宿主暴露;depends_on 健康检查保序(mcp-go 待 Milvus healthy);
APP_ENV=production 强制密钥校验 + 锁 CORS + 管理员白名单。
- .env.example + DEPLOY.md:两类密钥分层(引导密钥走 .env,模型 key 控制台加密存库);
首次管理员流程;安全建议。LICENSE 专有(授权模型可后定)。
- scripts/backup.sh + restore.sh:PG 逻辑备份 + 各数据卷快照 / 恢复。
- .gitignore 挡 .env*(密钥不入库)。
live:5 镜像全构建通过;独立 project 起整套 → nginx→gateway→NATS→dispatcher→mcp 全链路
注册+提任务 running→done,depends_on 保序生效。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-26 15:23:36 +08:00
Blizzard
075d41f5b3
feat(llm): 本地模型接入 vLLM / Ollama + reasoning 思考过程入轨迹
...
vLLM 与 Ollama 都暴露 OpenAI 兼容 API(底层 go-openai 请求 {base}/chat/completions),
故统一走 openai 客户端,按 provider 归一化连接参数:
- Ollama/vLLM 的 OpenAI 端点固定在 /v1,BaseURL 漏写自动补全(否则打到 /chat/completions 404)
- 本地后端默认不校验 api_key → 缺省补占位(ollama→"ollama",vllm→"EMPTY";openai 客户端要求非空)
- 显式 key 一律尊重(vLLM --api-key 启动);在线 provider 原样不动(DeepSeek 两种都收)
reasoning_content 适配:ChatStream 增 onReasoning 回调,捕获 reasoning 模型
(本地 Qwen3 思考 / DeepSeek-R1 / QwQ、在线 deepseek-v4-pro)的思考分片。思考阶段分片
Content 为空本就不污染答案;runAgent 把思考累计后 surface 到 exec 轨迹「推理过程」事件。
控制台 ModelManager 加 ollama 选项;llm 包补 normalizeBaseURL / apiKeyOrPlaceholder 单测。
四模块全绿。live:经 admin 配 ollama qwen2.5:0.5b → dispatcher 热切(日志 base 自动 .../v1)
→ POST /v1/chat/completions 200 端到端出答案;切回 deepseek-v4-pro → exec 轨迹现「推理过程:思考26字…」。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-26 11:10:18 +08:00
Blizzard
8bcb90cdb2
feat(admin): 服务状态面板(基建/服务探活 + MCP 工具注册)+ mcp-go 工具注册表
...
管理端新增「运维 › 服务状态」:总览横幅 + 摘要数字 + 请求链路拓扑
(客户端→网关→NATS→调度→MCP,按健康三态着色)+ 应用服务卡(含探针
延迟)+ 基建磁贴 + MCP 工具按能力域分组(中文名/作用)。
探活机制(全走 NATS,无 HTTP):
- mcp-go/mcp-py 新增 list_tools 自省工具,能应答=在线 + 上报工具清单
- dispatcher 无端点 → 新增 NATS 心跳主题 sundynix.health.dispatcher
(ServeHealth 应答 model/ready/uptime),网关用 bus.Ping 探
- 网关 GET /api/v1/admin/status 并发聚合四探针 + 各项延迟
mcp-go 重构:switch → map 注册表(buildRegistry),dispatch 与 list_tools
共用单一事实源,杜绝漂移;每个工具带中文名 + 作用描述。mcp-py 同样补元信息。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-22 16:38:10 +08:00
Blizzard
597665f3c8
feat(admin): 计价配置(按模型·分输入/输出单价)—— 计费比率配置落地
...
计费需 token↔真钱比率,配置归管理端。本次落地"按模型·分输入/输出"粒度:
后端(gateway):
- store.Pricing 模型(BaseModel + model_id 唯一 + input_per_1k/output_per_1k + currency),
AutoMigrate 建 sundynix_pricing;ListPricing/UpsertPricing(OnConflict model_id 覆盖)。
- admin handler:GET /admin/pricing 列表、PUT /admin/pricing 设置(校验非负,币种默认 CNY),
挂在 RequireAdmin 组下。
前端(admin):
- api:listPricing/savePricing(带 Bearer)。
- PricingPage:列出所有已登记模型(chat+embedding),每行可编辑 输入/输出每1K单价 + 币种,逐行保存。
- routes 新增「计价」页(配置组)。
实测:PUT→ok;GET 返回正确行;重复 PUT 同 model_id 仍 1 行且值更新(upsert 生效);表自动迁移。
前端 tsc 干净。下一步可做用量计量 × 单价折算(真正计费)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 11:25:24 +08:00
Blizzard
030dcda9b4
feat(admin): 管理端接登录 + Bearer 鉴权 + 修雪花ID/探活(适配硬化后的网关)
...
/admin 加 RequireAdmin 后管理端原来无鉴权会 401。本次打通:
- api.ts:JWT token 存 localStorage + 所有 /admin 调用带 Bearer + 401 清令牌广播登出;
login/me;gatewayOnline 改用公开 /healthz(原 /billing 已转受保护会误判离线)。
- 修类型:Model.id number → string(模型 id 早已迁雪花字符串)。
- Login 登录门 + App 鉴权门(启动校验 me,无则登录页)+ AppShell 显示用户/登出。
实测(硬化网关):无 token /admin/models → 401;登录拿 token → 200 返回模型(string id)。
dev 未配 ADMIN_USER_IDS 时任意登录账号放行;生产须在白名单。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 11:09:02 +08:00
Blizzard
3b54e59ecf
feat: embedding 配置搬上控制面 — 数据源页可视化配置 + 热更新
...
embedding 从 env 改为控制面驱动(持久化+可视化),复用 chat 模型同套范式:
配置控制面泛化为按 kind(chat/embedding),加 embedding kind。
- shared: 配置 subjects 泛化 sundynix.config.<kind>.get/.updated;bus 方法改 kind 参数
(RequestConfig/ServeConfig/PublishConfigUpdated/SubscribeConfigUpdated)
- gateway: sundynix_model 加 kind 列(每 kind 唯一激活)+旧行回填 chat;admin 按 kind
增删改/激活/列表,测试连接 embedding 走 POST /embeddings;main 按 kind ServeConfig;
变更广播各 kind
- dispatcher: 取 chat 配置(kind 化)
- mcp-go: rag.Engine.SetEmbedding 热更新(RWMutex);main 取/订阅 embedding 控制面配置
(覆盖 env)
- admin 控制台: api 按 kind;抽出复用 ModelManager;ModelsPage(chat)+新 DatasourcesPage
(embedding + 向量/图库占位);routes 数据源页就绪
- 验证: 全模块 build✓ + e2e PASS + 控制台 npm build✓;live 全跑通——chat(DeepSeek 回填
kind 仍工作);mcp-go 不带 EMBED env 启动→控制台配 embedding(百炼)→测试连接✓→激活
→NATS 热更新 mcp-go→入库+语义检索'存向量的数据库'→Milvus;浏览器数据源页拉到激活配置
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 17:25:54 +08:00
Blizzard
f6a669070d
refactor(admin): 控制台改为路由表驱动的动态路由 (react-router)
...
控制台从 useState 切 tab + 硬编码条件渲染,改为路由注册表驱动 + 真实 URL 路由,
加页面只需在 routes.tsx 加一条,不动外壳。
- 依赖 react-router-dom v7;App=HashRouter(静态托管/桌面内嵌都能深链)
- routes.tsx:路由注册表(单一事实源,导航+内容都派生);real 页面 lazy 懒加载(代码分割)
- shell/AppShell:NavLink 分组导航(配置/平台) + Routes + Suspense + 健康灯,全从注册表派生
- 页面归入 pages/(ModelsPage 移入),components/Soon 占位复用
- 验证:npm build✓(ModelsPage 独立 chunk=懒加载生效);真实浏览器——默认重定向 #/models、
nav 切换改 URL hash、深链 #/guardrails 直达、浏览器后退回 #/datasources、active 高亮
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 16:09:07 +08:00
Blizzard
6f5b98f186
feat: 独立运维控制台 (sundynix-admin) — LLM 模型配置控制面前端
...
新增独立 Vite+React 控制台(:5174),运维在此配置控制面,区别于桌面端构建者 UI。
- sundynix-admin: 模型页(列表[激活徽标/脱敏key] + 登记表单 + 测试连接 + 激活/删除)
→ 调 Gateway /api/v1/admin/models*;数据源/租户/护栏 占位(规划中);Gateway 健康灯
- gateway CORS 补 DELETE(控制台删除模型用)
- Makefile admin 目标(Vite :5174); .claude/launch.json 加 admin-console
验证: npm build✓; 真实浏览器跑通——控制台拉到真实模型列表, 填表→测试连接
✓连接成功(HTTP 200,browser→GW→mock), 保存→表格新增行。激活会经 NATS 热更新
Dispatcher(上一提交已证)。控制台↔控制面↔Dispatcher 全链路打通。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-10 15:54:01 +08:00