feat(server/stats): stats-overhaul Phase2 — 每设备归因 + GB 综合配额

服务端记账从「账户」细到「每设备」(每设备独立 dp_uuid),配额单位分钟→GB
按账户综合卡控。000015_per_device_usage 迁移(mysql+sqlite 双份):devices.dp_uuid
+ usage_device_daily 表 + plans.daily_mb。handler_grpc 按 dp_uuid 回映射
(user_id,device_id) 双写账户+每设备;usage 服务/handler 暴露 /v1/usage(/devices)。
含 sqlite_per_device / usage handler 测试。

注:此迁移 prod 已 migrate up 运行、部署二进制已内嵌;本次补提交使 git 与线上一致。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-28 18:12:00 +08:00
parent 4f9d2d2cf3
commit 636a3bbf2f
14 changed files with 778 additions and 8 deletions
@@ -0,0 +1,5 @@
ALTER TABLE plans DROP COLUMN daily_mb;
DROP INDEX IF EXISTS idx_usage_device_user_date;
DROP TABLE IF EXISTS usage_device_daily;
DROP INDEX IF EXISTS idx_devices_dp_uuid;
ALTER TABLE devices DROP COLUMN dp_uuid;
@@ -0,0 +1,27 @@
-- 每设备归因 + GB 综合配额(todo #5 Phase 2
--
-- ① devices.dp_uuid:每设备独立的数据面凭证(替代账户级 users.dp_uuid 作为出网凭证)。
-- SQLite ADD COLUMN 不支持 UNIQUE 约束 → 列加完再建唯一索引(NULL 视为相异,存量设备
-- NULL 不冲突,待回填)。
-- ② usage_device_daily:按设备的每日用量;usage_daily 仍作账户综合 rollup。
-- ③ plans.daily_mb:每日综合流量配额(MB,与 daily_minutes 并存,按账户综合卡)。
-- 用 MB 而非 GB 以支持免费版 500MB。free 500 / pro 100GB / team 200GB(可调)。
ALTER TABLE devices ADD COLUMN dp_uuid TEXT NULL;
CREATE UNIQUE INDEX idx_devices_dp_uuid ON devices (dp_uuid);
CREATE TABLE usage_device_daily (
user_id INTEGER NOT NULL,
device_id INTEGER NOT NULL,
date DATE NOT NULL,
bytes_up INTEGER NOT NULL DEFAULT 0,
bytes_down INTEGER NOT NULL DEFAULT 0,
minutes_used INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (device_id, date)
);
CREATE INDEX idx_usage_device_user_date ON usage_device_daily (user_id, date);
ALTER TABLE plans ADD COLUMN daily_mb INTEGER NULL;
UPDATE plans SET daily_mb = 500 WHERE code = 'free';
UPDATE plans SET daily_mb = 102400 WHERE code = 'pro';
UPDATE plans SET daily_mb = 204800 WHERE code = 'team';