浅念
|
3681999667
|
feat(api): scheduled user sync with mock source (T30 semantics)
P4a Task 7 —— cn 侧用户定期同步(mock 源先行,G4 真实接口到位后仅替换
UserSourcePort provider,引擎/契约/表不变)。
数据模型(db-cn 迁移 20260920114149,utf8mb4_0900_bin 逐表校对):
- user_sync_runs:批次账本(trigger cron|manual、state running|success|
partial|failed、cursor 水位、counts JSON、起止时间与错误摘要);
- user_sync_errors:单批次坏行明细(runId 索引);
- external_user_mappings:本地↔外部 ID 映射(@@unique([sourceSystem,
externalUserId]),sourceVersion 逐行高水位);
- user_sync_state:单行状态(lastRunAt/lastSuccessAt/cursor/runCount)。
同步引擎(UserSyncEngine):
- Redis SETNX 分布式互斥(TTL 10min,锁值=runId,Lua CAS 释放);
定时 tick 与手动触发共用,运行中批次复用 runId(202);
- 游标增量 + 周期全量对账(RECONCILE_EVERY_N_RUNS 默认 10);
- 逐页单事务提交(run counts+cursor / state cursor),分页中断→failed
且水位不前进、会话不动;
- 红线遵守:sync 不写 password_hash/role/album_members/localLocked;
空/部分页不误伤停用;上游恢复不解除本地锁定;
- 新用户按 pending 建(随机不可用哨兵哈希,激活+重置后方可登录);
- 停用即撤销该用户全部会话;本地预建同名账号走关联而非重建。
Admin API(/admin/user-sync):GET status|runs|errors?runId=、POST runs
(202 {runId});runs 为 startedAt+ID 倒序游标分页。
auth.service:登录对哨兵/损坏哈希加固(等代价 dummy verify,
401 而非 500,时序平坦)。
测试:user-sync.e2e-spec 12 用例(首轮全量/改名幂等/停用撤会话/
恢复不解锁/新增/空页/分页中断/部分无效/手动互斥/增量+对账/API 形状
与权限/pending 登录门);api e2e 22 套件 239 用例全绿。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-20 20:01:17 +08:00 |
|
浅念
|
4937eeecff
|
feat(api): usage summary with threshold alerts
P4a Task 5(A23 后台侧):用量统计与阈值告警后端全链。
- cn 迁移(校对手决 utf8mb4_0900_bin):usage_thresholds 单行配置表
(迁移内种子行,storageBytes/perAlbumBytes BigInt?,null=维度停用)+
usage_alerts 告警账本(kind storage|perAlbum、albumId?、resolvedAt?
索引)。「同 kind+albumId 活跃告警唯一」为应用级约束(MySQL 无部分
唯一索引):评估事务以单行配置 FOR UPDATE 作串行化锚点闭合竞态。
- 共享核心 packages/db-cn/src/usage.ts:computeUsageAggregates(非
deleted 口径实时 SUM:photos groupBy + 变体 JOIN raw)+ evaluateUsage
(storage/perAlbum 两维超阈 ensure、回落/停用 resolve、去重)+
evaluateUsageSafe(自开事务、失败仅记日志不拖垮业务主流程)。api 与
worker 共用(放置原因见文件头)。
- api:GET /admin/usage/summary(相册聚合 + totals + 阈值 + 告警:活跃
在前、近期解除补位,合计 100)与 PUT /admin/usage/thresholds(缺省
保持/显式 null 清除 + 契约「即刻重新评估」);仅 admin。BigInt 运输
决策:库内 BIGINT、JSON 出入口 Number() 收敛(2^53≈9PB 上限,DTO 以
MAX_SAFE_INTEGER 拒绝超界输入杜绝静默失真)。
- 检查点(提交后评估):worker 发布事务后(仅真实 published)、worker
水印任务完成后、api photos 可见性迁移(PATCH/软删除)与批量隐藏后、
阈值 PUT 后。
- tests:usage e2e +6(汇总数学/降序/标题、403/401、400 校验矩阵、
perAlbum 告警产生-去重-上调解除、storage 告警-null 清除解除、hidden
计入+deleted 回落且穿过 api 检查点);两侧 reset 增补 usage 表截断 +
单行重种。全量回归:api e2e 214/214、api 单测 51/51、worker 单测
14/14 + e2e 13/13。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-20 19:01:41 +08:00 |
|
浅念
|
2801e4f158
|
feat(api): identity and audit schema with mysql semantics tests
packages/db-cn:@photo/db-cn(prisma 5.22,api/worker 共享 client)+
schema(users/sessions/audit_logs,DateTime(6)、cuid、账号唯一)。
迁移 SQL 手工改写表级 collation 为 utf8mb4_0900_bin——Prisma 生成的 MySQL
DDL 固定 utf8mb4_unicode_ci 会覆盖库级 bin collation,账号/token 大小写
敏感语义依赖它(后续迁移需同样复核)。services/api:@Global PrismaModule
(PrismaService 封装 $connect/$disconnect,池上限仍由
DATABASE_URL_CN ?connection_limit=10 承担);reset.ts 落地 FK 包裹式
TRUNCATE;e2e 语义复核 4 例(UTC 往返/大小写敏感/audit Json+actor/
session FK Restrict P2003)。pnpm 10 未拦截 prisma engines(平台包内置),
无需 onlyBuiltDependencies。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-17 19:51:56 +08:00 |
|