浅念
|
aee4b7ac46
|
feat(api): embed slots with ov replica and public feed
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-20 22:22:19 +08:00 |
|
浅念
|
2bb6f291d3
|
feat(ov,viewer): two-tier download with wechat guidance
P4a Task 4(T12 收口):ov 域公开照片下载端点 + viewer 下载 UI。
- interactions 增 downloads:GET /public/albums/{token}/photos/{photoId}
/download?variant=browse|original。两级开关(A18):browse 需
downloadEnabled;original 需叠加 originalDownloadEnabled(级联,browse 关
则两者均 403 DOWNLOAD_DISABLED)。水印相册 browse 现签 watermark pattern
key(browse-key 解析抽取 shared/ov-browse-key 与 public-ov 复用);原图
现签 originalObjectKey(SIGNED_URL_TTL)。来源 IP 固定窗限速
(DOWNLOAD_WINDOW_REQUESTS/DOWNLOAD_WINDOW_SECONDS,env 可调);零浏览
计数写入(排除规则)。STORAGE_PORT_OV 经新 StorageOvModule 与 public-ov
共享同一实例。
- 契约微调登记:PublicAlbum 增 readOnly 必返 downloadEnabled/
originalDownloadEnabled(cn+ov 同形返回;public e2e 精确键断言同步)。
- viewer:lightbox 下载入口随开关渲染(无/单按钮/分体菜单两选项)、过期
凭证静默重取一次、微信内置浏览器(MicroMessenger UA)出保存图片指引
浮层(复制深链 + 反馈)替代直接下载;i18n zh/en 词条。
- tests:api e2e +7(开关矩阵 + URL/字节级断言、水印键一致、隐藏 404、
限速 429、零计数行);viewer vitest +9(UA/矩阵/菜单/重取/失败/指引/
复制);viewer Playwright +3(入口矩阵、微信 UA 浮层、真实端点 200 +
签名 URL 模式)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-20 18:32:34 +08:00 |
|
浅念
|
1f2a0c658f
|
feat(ov): windowed dedup visit counting with retention cleanup
Task 8 (P2): POST /public/albums/{token}/visits with visit_sessions
window dedup (VISIT_WINDOW_MINUTES), requestId idempotent replay
(echoes stored outcome; expired beyond VISIT_REQUEST_TTL_MINUTES
rejected), album_stats viewCount/statVersion authority + outbox_stat_events
views snapshots, WS stats.updated broadcast, visitorId+IP fixed-window
rate limit (VISIT_WINDOW_REQUESTS), and ov CleanupModule scheduler
(setInterval, CLEANUP_INTERVAL_MINUTES) deleting like_batches /
visit_requests / visit_sessions past their windows — totals never
touched. Contract prose aligned to replay semantics; constants
VISIT_WINDOW_REQUESTS / CLEANUP_INTERVAL_MINUTES added.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-18 18:14:01 +08:00 |
|
浅念
|
85b2da3db5
|
feat(ov): idempotent batched likes and realtime broadcast
P2 Task 7(点赞批次端点 + ov 实时网关):
- interactions 模块(仅 ov 装配):POST /public/albums/{token}/photos/
{photoId}/likes——相册不可见/照片未发布 404、delta 1..20 与
sessionId/batchId 1..64 校验 400;单事务 like_batches 唯一插入
(P2002=幂等重试,batchAccepted=true 不重加)→ photos_ov.likeTotal/
countVersion 原子自增回读 → outbox_stat_events(kind=likes) 兜底;
Redis ov(REDIS_URL_OV)INCRBY+TTL 会话/IP 双窗口限流(默认
500/2000,超限 429 RATE_LIMITED),幂等重试先于限流不耗额度
- 过期批次重放边界(24h 清理后的 batchId 重插会再次计入):接受该
边界——无永久账本可查(保留全量批次行违背清理策略),会话/IP 窗口
上限即重放天然封顶(同一 sessionId 重放挤占自身额度),偏差已在
likes.service 头注释登记,Task 8 统计侧按清理后语义处理
- realtime:ContractWsAdapter(契约 {type,...} 帧分发,ws 与 HTTP 同
端口挂 /v1/realtime)+ RealtimeGateway 相册房间模型——subscribe 逐
相册校验 isAlbumVisibleOv,失败回 error 帧且连接保持;应用层 ping→
pong 回显 ts;传输层 HEARTBEAT_MS 周期 ping 踢死连接;点赞提交经
EventEmitter2(单进程,多实例 Redis pub/sub 登记 P5)触发
likes.burst 500ms 合并窗(delta 聚合、originBatchIds 供客户端过滤
自身批次);sync-inbox 应用事务提交后发 OV_PHOTO_APPLIED →
photo.published/hidden/deleted 按房间广播(stale/duplicate/暂存/
缺席即撤下不转发)
- 契约:REALTIME_WS_PATH、ServerMessage 增 error 帧(穷尽锁 7 成员
+ 类型测试)、LIKE_SESSION_WINDOW_DELTA/LIKE_IP_WINDOW_DELTA/
LIKE_BURST_MERGE_MS 常量与 .env.example
- e2e(likes-realtime.e2e-spec.ts,6 用例):A09 三批累加/幂等重试/
outbox 行、小额度 429、ping/pong+幽灵 token error 帧连接保持、
A10 双房间隔离(先证非空调订)、合并窗单 burst(delta 求和+双
originBatchIds)、cn 隐藏→房间收 photo.hidden+隐藏后点赞 404;
凡进程内起 AppOvModule 的 spec(sync×2/public-ov/emergency)补装
ContractWsAdapter 与生产 main-ov 一致——api e2e 168(162+6)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-18 17:51:55 +08:00 |
|
浅念
|
0fcf18cc5c
|
feat(ov): public read api on replicas with hot sorting
P2 Task 6(ov 公开读 API + viewer 切换):
- ov 装配 PublicOvModule(仅 app-ov.module):/public/albums/{token}、
/photos、/photos/{id} 三端点同契约读 ov 副本——translations/categories
自 JSON 列解析(防御性过滤),banner 经 ov 侧 STORAGE_PORT_OV 预签名
(同本地 MinIO;只读属约定,真实 OSS 只读凭证 P5),viewCount 取
album_stats 权威累计(无行默认 0;计数端点 Task 8 接线)
- 排序:latest=发布时间 keyset(shared/cursor.ts 同 cn);hot=likeTotal
desc + photoId desc 决胜,顺序按 `${albumId}|${category}` 短期快照
(内存 TTL 默认 30s,HOT_SORT_TTL_MS 惰性读取)——计数逐请求现读、
顺序冻结窗口内一致,偏移游标(base64url 整数)在快照内严格稳定;
非法 sort 400 VALIDATION_FAILED(cn 不感知该参数)
- 契约:viewCount 放宽为 integer|null(cn null、ov 权威值);
listPublicPhotos 增 sort 枚举(latest|hot,缺省 latest);
PhotoPublishedPayload 增 categoryId——补上 Tasks 3/4 管线缺口
(payloads/publish.service/sync-inbox 投影 + 关联测试随改)
- e2e(services/api/test/public-ov.e2e-spec.ts,7 用例):双入口同进程
起 cn+ov,cn API 种子→真实发送管线投递;断言相册/列表/单图与 cn
深等(仅签名 URL 剔除)、banner 真字节、参数矩阵 400/404、hot 排序
TTL 内快照(计数新/顺序旧)+TTL 过期翻转+偏移翻页、隐藏/下线/紧急
停用逐态撤下
- viewer 切 ov:API 基址 VITE_API_BASE(缺省 http://127.0.0.1:8081,
空串=同源网关;Vite 只读 apps/viewer/.env*,根 .env 对前端无效),
移除 /v1 dev 代理(CORS_ORIGINS 增 127.0.0.1:5175 直连两形);
playwright webServer 增 dev:ov;e2e 夹具 flushSync(albumId)=cn
bootstrap 快照 + deliverPendingOnce(sender 新导出)经真实管线投影
种子,deleteSeededPhoto 改软删让墓碑可同步;14 个 Playwright 全绿
(journey 管理/staffB 腿仍走 cn 8080)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-18 17:05:56 +08:00 |
|
浅念
|
eac8da6d6c
|
feat(ov): emergency disable channel independent of sync
P2 Task 5(海外紧急停用入口):
- ov 新增 POST /v1/internal/emergency/disable|enable(InternalSyncGuard
HMAC,albumToken/albumId 恰好其一、都缺省 400;副本不存在 404
ALBUM_NOT_FOUND):直写 albums_ov.emergencyDisabled(唯一 ov 本地可写
位),独立于同步版本链——更高版本 album.updated 重放不解除(e2e 断言
entityVersion 推进而标志保持),恢复仅经显式 enable;幂等语义
(alreadyDisabled/wasDisabled 入审计行)
- cn 侧不感知:无对应 cn 状态位、无反向同步(契约描述文档化)
- 审计:pino child(audit=emergency 字段常驻每行)结构化日志——偏差
登记:计划原文「写 ov 侧日志文件」落地为字段标记而非独立文件通道
(免新增文件 transport 依赖,P5 运维按字段路由聚合);注入令牌
EMERGENCY_AUDIT_LOGGER,测试覆写为内存目的地断言字段
- isAlbumVisibleOv 共享判定(status=active && publicEnabled &&
!emergencyDisabled——镜像 cn 公开语义叠加本地停用位):Task 6 公开
API / Task 7 WS subscribe 的 404 ALBUM_NOT_PUBLIC 语义单一实现,
判定矩阵单测锁定
- 契约 [internal] 增 emergency disable/enable 操作与 schema(gen 已跑、
redocly 通过);e2e:token/id 定位、幂等、enable 恢复、未签名 401、
均缺省 400、未知相册 404、同步事件不解除
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-18 16:19:02 +08:00 |
|
浅念
|
65726702f3
|
feat(sync): cn event coverage, bootstrap and outbox sender
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-18 15:21:41 +08:00 |
|
浅念
|
3d6e9ce175
|
feat(ov): ov schema, entry skeleton and compose profile
P2 Task 2 ov 数据层:
- compose ov profile:mysql-ov(mysql:8.4,127.0.0.1:3309,库级
utf8mb4_0900_bin)+ redis-ov(6381),cn 侧默认 up 不受影响
(3307/3308 已被其它本机项目占用,端口决策 3309)
- @photo/db-ov:9 表 schema(albums_ov/photos_ov 副本、sync_inbox/
sync_state 同步账本(水位行同表标志位)、like_batches/album_stats/
visit_sessions/visit_requests 互动域、outbox_stat_events 回传队列);
迁移 20260918060102_init_ov 走固化校对手决流程,information_schema
复核全部业务表/列 utf8mb4_0900_bin(_prisma_migrations 同 cn 先例
保持 unicode_ci)
- generator 独立 output(包内 generated/):pnpm 将两包 @prisma/client
提升为同一 store 实例,默认 .prisma/client 输出会被双 schema 互相
覆盖,ov 客户端独立产出经 src/index.ts 转出口
- ov 入口骨架:main-ov.ts(PORT_OV 默认 8081)+ app-ov.module.ts
(仅管线骨架 + /v1/health,feature modules 后续任务装配);logger
装配选项抽取至 shared/logger-options.ts 供 cn/ov 双入口共用(行为
不变,P1 套件守护)
- test/reset-ov.ts:ov 库 truncate-if-exists 隔离工具(无 MinIO 清理)
- 根脚本:db:generate 双库齐跑,新增 db-ov:migrate/db-ov:generate/dev:ov
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-18 14:11:41 +08:00 |
|