Rodger-Wang
|
37817f2e96
|
会员与算力:VIP 管准入、算力管计量;补上线落地文档
VIP 与算力两层权益各管一件事,判定与记账统一走 comm/compute.go:
- VIP 管功能准入(无 VIP 时 user_translate / echomeet_starttask 返回 VipRequired);
自购记 user.vipexptime,设备赋予记在 device_mac 行上(激活日 + 天数),
两者在 ResolveUserVip 合并成有效值下发,库里仍只记自购——以前绑定礼把天数
累加进用户表,解绑时拆不开。
- 算力管用量计量,按后台系数折算,先扣设备赠送再扣用户余额。
三个旧额度桶停用,存量余额由 home 启动时一次性折进 computebalance。
- 闸门 COMPUTE_GATE 默认关:user_usages 是用完才上报、没有预扣,
现在开闸门形同虚设。
另含本次「阿龙测试服 → 正式服」上线落地文档(docs/),
以及 admin 侧商品/设备/产品/用户页的配套改动。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
4 weeks ago |
Rodger-Wang
|
0b0ac16b3c
|
记忆中心后端:memory 模块 + 会议待办抽取 + 周报月报
按设计文档一~三期的后端部分落地。全量 go build / go vet 通过,新增 22 个测试。
memory 模块(modules/memory,由 home 装载,路径 /api/home/memory_*)
11 个接口:list / today / add / update / del / complete / upcoming / stats /
getreport / confirmreport / listreports。
表由 proto + gorm tag 生成(不是手写 DDL——本仓所有业务表都走
mysql.CreateTable + AutoMigrate)。protobuf 没有 DECIMAL/DATE/DATETIME/null,
逐个落成:金额 int64 存分(与 pay/结算同口径,绝不用 double)、happen_date
string + gorm type:date、next_remind_at int64 unix 秒(0=无)。
几处刻意的选择
- 建表失败只 Errorln 不外传。lego.Run 里 Init 返回非 nil 就 Panicf,而五个服务
同镜像、entrypoint 见任一 pid 退出就全杀,一次建表失败等于全站 502。
allhelp/model.go 那段用命名返回值 err,第二张表失败时会漏出去,是反例。
- client_key 服务端保证非空。它参与 (uid, client_key) 唯一索引,而 MySQL 的唯一
索引不像放行 NULL 那样放行空串,留空会让同一用户的第二条记录直接插不进去。
用 crypto/rand 生成:这个值是去重依据,可预测就可被抢占。
- 重复项的提醒改成「就地展开」。设计文档 v0.1 写的「remind_at 服务端算好客户端
直接用」对重复项不成立——一个字段表达不了「每天」,且没人在它过去后往前推。
现在 memory_upcoming 按项自己的 tz 展开成绝对时刻列表返回,不落库。
单条项按自己的 tz 算而不跟着请求方走:「今天有哪些事」是视图问题可以跟着人走,
「明早 8 点响」是承诺问题不能。
- 花销按币种分行统计,不做汇率换算。把 CNY 和 JPY 加成一个数是错的。
- 统计全部走 SQL,LLM 只把 stat_json 组织成一段适合朗读的话。明细截断到 20 条
(重度用户一周两百条未完成,全塞进 prompt 会顶爆上下文,播报也没人听得完)。
- 查询/删除/更新一律带 uid 作条件,报告确认校验 uid 归属。
- 更新字段走白名单而不是黑名单,漏挡一个 uid/id 就是越权改别人的数据。
选路走编排,不再写死服务商
新增 comm.IEchomeet.ChatLLM,由 echomeet 用它的 PickLLM/GetSummarizer 实现。
memory 的报告生成与会议抽取都经它选模型。allhelp/summary.go 直接 import
sys/doubao 是历史债:绕过后台编排,海外应用照样调国内豆包、后台换模型也换不掉。
新模块不复制这个写法。
会议纪要 → 待办抽取(第三路)
挂在 AIProcess 写完 summary、状态置 Completed、出队之后,另起 goroutine。
prompt 内置代码不放 echomeet_template(1189 条模板改不齐,且输出要被程序 parse)。
输入用已生成的 summary 而非转写全文。注入 <meeting_date>,服务端二次校验
due_date:解析不出或早于会议当天的一律只留 due_raw、落会议当天并置
date_certain=false。抽取失败只记日志,绝不回头改 rec.State。
- gen_round 由 memory 按 source_id 现有最大值 +1 推出,不由调用方传。
echomeet 没有地方存轮次计数器,硬编码成 1 会让第二次「重新生成」的清理条件
gen_round < 1 一条都匹配不上,旧待办从此永远留在库里。
- 会议归属日期只能用 creationtime(上传时间)——DBEchoMeetRecord 上没有「会议实际
发生日期」字段,也没有客户端时区。补录历史录音会算错,是已知偏差,注释已记。
周报月报
cron 建单 → Redis 队列 → N worker。锁与队列 key 都过 redissys.RKey 加应用前缀:
测试机多应用共用一个 Redis,锁 key 不带前缀会让 A 应用挡住 B 应用整周不生成报告,
而且安安静静什么都不报。
补偿比防重更要紧:当前 compose 是单副本,多副本重复是前瞻性风险;真会发生的是
00:30 跑到一半容器重启、cron 不补跑、报告永远停在 pending。所以 memory_getreport
里做超时重新入队(同 echomeet 用 PollTranscribe 兜「转写回调丢了」的思路)。
文案生成失败不算整体失败——统计是完整的,宁可少一句话不可让报告整个没有。
顺带修的既有缺陷
- user 模块 cancel()(账号注销)补上 memory_item / memory_report 两张表,
以及既有遗漏的 useridverify(身份证掩码 + 加盐指纹)。这个清单是硬编码的,
漏了不报错,只是个人数据静静留在库里。
- errorcode.proto 新开 5201-5206 段。复用 ReqParameterError 会让客户端无法分流,
「报告还没生成好」该转圈重试而不是弹错。
测试
comm/memory_test.go 8 个:周日在 Go 里是 0、Dart 里是 7 的换算(错了不报错,
只会让每周日的闹钟在周一响)、ISO 跨年周、闰年二月、非法时区必须回退 time.Local
而不是 UTC(否则静默偏移 8 小时)、client_key 非空且不重复。
modules/memory 14 个:一次性/每天/每周展开、锚点在一年前仍能算出未来时刻、
过期项不排、灵感花销不提醒、全天项按 9:00 不落 0:00、展开结果必须升序
(客户端要按 iOS 64 条上限截断,顺序错了会把明天的排掉留下一周后的)、
项按自己时区算、LLM 输出容错(代码块/前后解释文字)与真失败必须报错。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
1 month ago |
Rodger-Wang
|
d7fad60658
|
设备表合表:license_<pid> 分表 → 全局 device_mac,只按 MAC 校验
设备的身份是它自己的 MAC,本来就全局唯一,定位一台设备不需要 pid。
原先按产品切分表,pid 既是查询键、又得由客户端猜出来,猜错就报
"这台 MAC 没登记在该产品下"——提示指向数据缺失,实际数据好好的。
触发改造的事故:一台已正确导入的 DEEPVOICE 耳机(MAC 在 license_b022,
产品 45090,status=0 未绑过)连不上、弹"设备连接受限"。根因是产品 45090
的 devicetype 被配成 2(BLE双端)而不是 1(经典蓝牙):客户端
_resolveProductId 第一步就 where(devicetype==1) 把整个产品滤掉,候选只剩
Echo-one,名字互不包含 → 兜底退回 headsets.first.id = 45091,服务端拿错
pid 去 license_b023 查,自然查不到。而且就算 pid 猜对也过不去——服务端
只有 devicetype==1 才走 MAC 反查,2 会走 else 分支从空 code 反解 pid、
回退写死的 45058。
改动:
- 新增全局表 device_mac(comm.TableDeviceMac),主键 code = MAC;
productid 降为归属列,不再是查询键。TableLicense 标记废弃,只留给迁移读。
- registry.go 的 migrateLicenseToDeviceMac 每次启动跑、幂等:
① code := devicemac 修存量 → ② 按两表列名交集做 INSERT ... ON CONFLICT
DO NOTHING(不能 SELECT *:各分表建于不同时期,有的多 factoryid/probatch)
→ ③ productid 为空的用表名里的 pid 补上。孤儿分表里也是真实发出去的设备,
一并搬。搬完刻意不删旧表——不可逆数据,旧表是出问题时唯一的回退依据。
- binddevice / unbinddevice 改为先按 code 再按 MAC 全局定位,命中行的
productid 才是产品。req.Pid 不再采信。杰理链路也顺带不需要 devcode
反解 pid 了。
- 新增 comm.ScopeToProduct:合表后分表那层天然隔离没有了,每个"按产品"
的读写都必须显式带 productid,漏一处就跨产品操作——查询多列几行只是
难看,批量禁用 / 按批次删除漏掉就是删别人产品的数据。它会把调用方的
条件整体括起来,防止 "a=? or b=?" 让 or 把 productid 短路掉。
- 导入查重改成全局:同一个 MAC 出现在两个产品下会让按 MAC 反查出现歧义。
- 客户端删掉 _resolveProductId,binddevice 只报 MAC 不传 pid。
按需求明确不做应用隔离:MAC 存在即放行。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
1 month ago |
Rodger-Wang
|
db47e0f3f0
|
游客登录入口改为后台按版本控制
需求:后台一个开关控制游客登录按钮显隐,且只对指定版本号的客户端生效,
其余版本一律隐藏(应用商店送审场景:只给正在过审的那一版开)。
白名单语义(comm.ChannelApp.ShowTourists):
- tourists=false → 全部隐藏
- tourists=true 且 touristsversion 空 → 全部隐藏(没点名任何版本 = 谁都不放行)
- tourists=true 且 touristsversion=X → 只有版本号等于 X 的客户端可见
留空按"全隐藏"而非"全放行"是刻意选的失败方向:判宽的后果是不该露游客入口的版本
露了出去(过审风险、白嫖新用户开户礼),判严只是入口少显示。要全部隐藏就取消勾选,
后台 saveChannelApp 会拒绝"勾了开关却没填版本"这种等于没开的配置。
判定放在服务端,与 NeedForceUpdate/IsReviewing 同规矩:客户端在 user_getchannelapps
的请求里带 version,服务端把每条渠道配置的 tourists 换算成结论再下发。版本比较各端
各写一遍必然出现实现不一致,而这个开关直接关系到过审,判错代价高。
touristsversion 是 channel_app 的后加列,console 启动时用 ADD COLUMN IF NOT EXISTS
补上——CreateTable 对已存在的表跳过 AutoMigrate,不补就永远没这列。
注:db.proto / user_msg.proto / CLAUDE.md 里另有先于本次改动就存在的编辑,一并带上。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
1 month ago |
liwei1dao
|
948e368996
|
上传代码
|
2 months ago |
liwei1dao
|
18ffb48466
|
上传代码
|
2 months ago |
liwei1dao
|
e270cf89b6
|
上传新版本管理后台
|
2 months ago |
liwei1dao
|
a25b0c9fc0
|
上传最新的服务后台代码
|
3 months ago |
liwei1dao
|
715f8e3818
|
上传厨师版本
|
4 months ago |