Commit Graph

151 Commits

Author SHA1 Message Date
浅念 eebf3b3334 feat(admin): standard pagination + synced profile columns on users list
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 18:10:53 +08:00
浅念 2f6b6afc92 feat(contracts,api): page-mode pagination + synced profile on admin users list
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 18:06:12 +08:00
浅念 91c85e196a feat(viewer,ui04): E05 realtime hearts + effect-demo alignment (initial offset, heart params, decode gate, bidirectional manual scroll)
- reactions.ts pure fns: delta->hearts sampling, burstId dedupe (TTL/capacity), pending-visible cache (5s/50), 250ms emission throttle with merge
- useEmbedReactions: read-only RealtimeClient subscription on album.publicToken (no viewer-page side effects, A15), rebind teardown, 10s grace disconnect, no fake bubbles on WS failure
- ReactionLayer: demo-frozen heart effect (12/16/20 sizes, two colors, 110px rise, 1.6s ease-out, 300ms stagger, max 8, drop-shadow) in unscoped block (created elements lack scoped hash)
- demo alignment: initial offset 32px, decode+500ms startup gate, 1:1 drag, arrows +-40, focus-tip, bidirectional manual scroll (manualScroll), loader handle 100x44 exact styles, <=599px offset default 12
- tests: +8 reactions unit (244 viewer), e2e E05: real cross-context like -> heart on correct photo (EMB-A09), zero likes/visits submission (EMB-A15), 16s hearts recording

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 17:38:02 +08:00
浅念 f6ff1d44f2 feat(api,db-cn): persist synced source profile snapshot on mappings
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 17:33:27 +08:00
浅念 ccf0c29659 docs(g4): test-server deployment evidence (230 users synced, ops notes)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 17:14:31 +08:00
浅念 3a8a1cf69e docs(g4): real-key live sync evidence (230 users, idempotent, V1.1 credentials verified)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 16:58:09 +08:00
浅念 e583575702 docs(g4): acceptance record for uniservice user source integration
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 16:51:58 +08:00
浅念 8c255eb747 feat(api): USER_SYNC_SOURCE switch wires mock/http user source (G4)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 16:28:55 +08:00
浅念 d732caa739 feat(api): HttpUserSource adapter for uniservice open/v1/users (G4)
全量拉取+phone 全局去重(一人多档跨页)、水位游标不当页码回归守护、
分块续翻缓存;对齐 UserSourcePort 类型。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 16:27:43 +08:00
浅念 52cd31679a refactor(api): per-source sourceSystem on user source port, retire pending-activation dead code
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 16:24:37 +08:00
浅念 b7754d52d1 test(api): user-sync e2e aligned to V1.1 initial credentials
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 16:22:38 +08:00
浅念 42878f115b docs(g4): uniservice open/v1/users API contract + implementation plan
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 16:21:26 +08:00
浅念 f193e4f085 fix(viewer): remove extra closing brace in AlbumHeader CSS
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:59:14 +08:00
浅念 b353a3de06 fix(viewer): replace text arrow share icon with SVG share glyph
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:55:37 +08:00
浅念 900ff2a74d feat(viewer): refine visual details to match design reference
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:49:15 +08:00
浅念 9dbdb0084e docs(ui04): E04 acceptance record entry
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:28:26 +08:00
浅念 3912279889 feat(viewer,ui04): E04 interactions — pause reason set, click lock/drag cancel, manual scrub, keyboard semantics, destroy
- pauseReasons Set (hover/focus/pointer/offscreen/hidden/manual + userPaused via Space, no auto-resume); 500ms transient resume with re-evaluation
- pointerdown target lock; >8px drag suppresses click and scrubs via nudgeOffset (window-clamped); removed photos clear pending target
- keyboard: Space pause toggle, Escape collapse, ArrowUp/Down scrub; input fields untouched
- aria-live status announcements (zh/en); viewport touch-action none
- e2e: hover freeze/resume, popup deep link hit, drag cancel, keyboard, slot disable destroy

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:28:13 +08:00
浅念 998565e439 feat(viewer,ui04): E03 continuous scroll engine — pure state machine, rAF orchestration, boundary continuity
- stream.ts: advanceStream (per-frame, dt cap 50ms), loop generation keys, window math (DOM<=16, queue<=30, 480px buffer), anchorRebuild (photo-position preserving), removePhoto, single-photo static
- useVerticalPhotoStream: rAF integration, direct transform writes (no per-frame Vue reactivity), low-frequency item sync, ResizeObserver re-anchor, stepForTest hook
- EmbedStream wired to engine; cycle copies aria-hidden; img error -> controlled drop
- tests: 14 unit cases (236 viewer total), e2e: 32px/2s speed, boundary continuity <2.5px, DOM<=16 over 20s, 32s recording with loop boundaries

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:19:21 +08:00
浅念 1d1979f540 feat(viewer,ui04): E02 static fidelity — real photo fixtures, measured shell/photo/collapse specs, edge fade
- fixtures: 8 picsum-seeded real photos (mixed ratios); seedPhoto thumbBytes/browseBytes injection
- e2e E02 block: wrapper shell (195x280/radius/border/#10161E), photo strip (193w, ratio-height, 3px gap), collapse (44/44 hit, 24 visual, sole button), desktop+mobile screenshots
- EmbedStream: top/bottom 12px dark fade (0.12, §2.3 optional item)
- fix(admin): pre-existing eslint globals gap for ElNotification (template drift, blocks lint gate)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 13:01:34 +08:00
浅念 66d1eb3e9f feat(embed,ui04): E01 v2 contract skeleton — displayMode/scrollSpeed/reactionsEnabled, v2 loader entry and fixed 195x280 shell
- contracts: EmbedSlotSettings optional v2 fields (carousel default) + SlotSettingsPayload; gen + redocly green
- api: DTO validation + normalization full-set (cn manage + ov public projection share normalizeStoredSettings)
- embed-loader: params v2 parse/merge/url family, loader-v2.js fixed shell (border/radius/#10161E/safe-area, resize ignored, stack gap 12), dual-artifact build+sync; v1 source frozen
- viewer: EmbedPage v=2 branch, EmbedStream (viewport/track/real anchors/collapse/empty), stream.ts pure fns, i18n zh/en
- admin: types + utils (create default vertical-stream, clampScrollSpeed, v1/v2 snippet selection)
- tests: loader 36 (+9 v2), viewer 222, admin 82, api unit 51, v1 embed e2e 20, v2 E01 gate 2 (195x280 desktop+mobile cross-origin, no footer)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 12:50:28 +08:00
浅念 f8dbc3ab9b docs(ui04): E00 baseline — design refs, plan, v1 measurements and record skeleton
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 12:08:40 +08:00
浅念 f435d7bfc3 docs: UI-03 acceptance record
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 03:16:21 +08:00
浅念 8ee69598bf feat(mobile): UI-03 photos and share pages (17-20)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 02:45:34 +08:00
浅念 ab51616c70 feat(mobile): UI-03 capture and upload pages (13-16)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 02:06:23 +08:00
浅念 8bd09eefb9 feat(mobile): UI-03 forms and collaboration pages (09-12)
- Page 09 create: grouped form (Event details / Description & languages),
  required default-language selector, zh-CN/en tabs with per-locale
  title/description/venue/address, explicit timezone field, bottom save
  button kept keyboard-reachable, create mode has no Access tab
- Page 10 edit: Details/Access tabs sharing one draft; Access has four
  switches with explanations; original downloads constrained by downloads
  (disabled + forced off in PATCH); unsaved-changes PopScope confirm;
  save commits all changes in one minimal PATCH
- Page 11 members: Owner group + Collaborators list with initial avatars
  and per-row remove; full-width Invite colleague opens account-search
  bottom sheet (debounced prefix search, race guard, already-added state);
  remove confirm names the member
- Page 12 categories: extracted to standalone page with per-row edit/
  delete menu and New category sheet (language tabs + name + sort order);
  delete confirm mentions photo impact; collaborator browse-only; old
  inline section removed from album detail
- l10n: new form/members/categories keys both locales; regenerated
- tests: form 14, members 6, categories 7, detail nav 1; full suite green

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 01:23:02 +08:00
浅念 5715c608d8 feat(mobile): UI-03 album workspace pages (05-08)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 00:57:59 +08:00
浅念 95e8417553 feat(mobile): UI-03 theme calibration and account pages (01-04)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 00:28:39 +08:00
浅念 9d521ff9da docs(ui03): baseline screenshots and acceptance skeleton
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-22 00:10:50 +08:00
浅念 18c4c3cfbc docs(plan): UI-03 app redesign implementation plan
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 23:45:34 +08:00
浅念 2a489aa16a docs: UI-02 acceptance record and visual verification
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 23:10:58 +08:00
浅念 160e7e5f1a feat(viewer): UI-02 heart particles, interaction notices, share and download
Task 5 (V05 §5.4/§6): decorative heart particles on the lightbox stage
(local like clicks + others' WS bursts for the current photo), compact
cross-photo interaction notices above the action bar (click to locate),
navigator.share-first share orchestration with clipboard fallback for
album and photo deep links (lang param), and download failures attributed
to the photo that triggered them. Self-echo dedup stays in the realtime
router (own batches never produce particles/notices); particles cap at
12 with visibility/unmount cleanup and are suppressed under reduced
motion; notices cap at 3 with ~4s auto-dismiss and throttled SR summary.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 22:20:19 +08:00
浅念 89f45896b7 feat(viewer): UI-02 dark immersive photo viewer with thumbnail strip
V04 (方案 §5):PhotoLightbox 模板重构为深色沉浸布局——顶栏(关闭/位置
计数/⋯ 减少动画菜单)+ 舞台(contain 大图 + 边缘 ‹› + 粒子/互动占位层)+
缩略图条 + 底部操作栏;业务逻辑(序列导航/缩放手势/签名刷新/下载/点赞)
原样保留。

- 新增 viewer/position.ts:§5.2 位置计数真实回退(solo→照片预览;无
  total 未到末页→已加载 N 张;全部加载→i/n;不伪造总数)
- 新增 ThumbnailStrip:当前 ±3 窗口(≤7 项)、主色 2px 描边、thumb 变体、
  滚入可见(遵守减少动画)、点击选择不新增历史
- 新增 PhotoActionBar:Like(coral 心形+计数+连续点赞提示)/Share/
  Download 均分大触控;下载关闭整项移除;原图二级菜单(▾ + 长按)
- 模态可用性:body 滚动锁、焦点进入/困住/归还触发元素、Esc 先收菜单、
  菜单内左右键不抢占、dvh + 安全区、chrome 区手势/滚轮隔离
- 分享 V04 最小实现(复制当前深链,support/clipboard 从 AlbumHeader
  提取共用);navigator.share 编排属 Task 5
- zh-CN/en 新词条;vitest 新增 23 例(位置回退/缩略图/操作栏/焦点/滚锁)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 21:58:09 +08:00
浅念 3d89fcdb99 feat(viewer): UI-02 responsive waterfall with like badges
Task 3 (V03 瀑布流重排, 方案 §4.3):
- responsiveColumns 断点:<600px 双列 gap4 / 600-959px 三列 gap6 / ≥960px 四列
  gap8;PhotoFeed 经既有 ResizeObserver 容器测量整体重排
- 照片卡片去卡片化:图片边到边 + 4px 圆角,无白色厚包裹/无常驻文件名;
  右下角点赞角标(半透明暗底渐变、白心 16px、12px tabular-nums 计数),
  @click.stop 独立交互不冒泡开大图;计数经 Intl 分组
- 新照片提示改白色 pill(viewer.newPhotos,接口仅 hasNew 不伪造数量);
  refreshFromHint 不再强制回顶(用户浏览位置保持)
- 首屏骨架按 skeletonSources 竖/横/方比例走真实瀑布流放置(非均匀网格);
  宽高缺失/NaN/Infinity 回退 4:3 安全比例(无 NaN/无限高度)
- 保留懒加载 IO、游标分页、photoId 稳定键、翻页失败底部重试与已到底文案

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 21:34:56 +08:00
浅念 9c3915b387 feat(viewer): UI-02 visual foundation, top bar and album info
V01+V02 (Task 2 of the UI-02 viewer redesign plan):

- viewer-tokens.css: UI-02 §3.1 design tokens scoped to .viewer-shell
  (never :root), so embed routes consume none of them
- App.vue: normal routes get a sticky white top bar (PhotoLive brand +
  compact locale switcher + lightweight "..." menu holding the
  reduce-motion toggle); global 16px content padding removed so banner
  and photos run edge-to-edge; embed shell branch untouched
- LocaleSwitcher: compact "EN/中文 + caret" trigger with a proper menu
  (current language checked), 44px touch target, Escape/outside close
- AlbumHeader (new): banner (2.4:1 mobile, 320px desktop cap,
  object-fit contain, collapses on missing/failed), 2-line expandable
  title + share button (clipboard copy with selectable-text fallback),
  3-line expandable pre-line description, meta row (Intl-formatted
  view count with em-dash fallback for unknown, album-timezone dates
  with full range on title, venue), Latest/Popular 44px tabs and
  category pills from the API with horizontal scroll + overflow fade
- ActivityPage: delegates the info area to AlbumHeader; sequence
  reset/sort-lock/category-by-id semantics unchanged; desktop content
  capped at 1120px
- i18n: viewer.* strings (brand/share/views/readMore/latest/popular/
  allCategories/noPhotos/newPhotos/reduceMotion/settings) in zh-CN+en
- tests: viewer-shell (token source + normal/embed isolation) and
  album-header (8 cases) specs; activity/i18n specs updated for the
  menu switcher and the em-dash unknown view count; e2e selectors
  refreshed

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 21:22:36 +08:00
浅念 2cbd167cc0 docs(ui02): baseline screenshots and acceptance skeleton
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 21:09:03 +08:00
浅念 3327551f6b docs(plan): UI-02 viewer redesign implementation plan
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 21:01:59 +08:00
浅念 f31388c0c1 docs: UI-01 acceptance record and visual verification
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 20:15:36 +08:00
浅念 ac23a4c40e feat(admin): UI-01 embed slot config form and live preview
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 19:26:48 +08:00
浅念 ddf26a177f feat(embed,viewer): UI-01 complete carousel, loader config and accessibility
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 18:55:15 +08:00
浅念 1f67b7c818 feat(mobile): UI-01 upload center, capture and auxiliary pages
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 17:20:43 +08:00
浅念 f6929ae18f feat(mobile): UI-01 album cards, photo grid and full viewer
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 15:55:44 +08:00
浅念 c94b9e5e58 feat(mobile): UI-01 theme system, shared components and navigation
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 14:55:29 +08:00
浅念 8f4ad11bd5 feat(contracts,api): UI-01 cover, preview, scope=own and embed config extensions
契约扩展(全部可选/可空,旧客户端零感知)+ cn/ov 实现 + e2e 权限矩阵:
- AlbumSummary += cover(kind=cover state=effective 最新行的短期签名 URL,
  列表/详情按页批量组装非 N+1;未配置为 null)
- AdminPhoto += preview{thumb,browse}(变体齐备且未删除才签发;隐藏仅
  admin/owner;协作者仅自己上传,scope=own 服务端过滤 uploaderId,
  成员资格逐请求裁决)
- listAlbumPhotos += scope=all|own(缺省 all 行为不变:仅 owner/admin,
  协作者 403;own 任何有效成员)
- EmbedSlotSettings += imageFit/offsetX/offsetBottom/zIndex(cn PATCH 校验
  → slot-state 投影 → ov 公开回读;settings 为 Json 列免迁移,读侧
  normalizeStoredSettings 兜旧形状默认值)
- Flutter 模型同步(SignedUrl/PhotoPreview/AlbumPhotoScope,可空容错)

e2e:ui01-contracts 9 例(封面选取/字节取回/N+1 计数断言、preview 权限
矩阵、scope 过滤与 403/404/400)+ embed ⑨ 配置链路;全量 e2e 257 通过。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 14:09:35 +08:00
浅念 3b5f8d2d77 docs(ui01): baseline screenshots and acceptance record skeleton
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 13:08:57 +08:00
浅念 6754cd4d44 docs(plan): UI-01 implementation plan from spec analysis
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 12:56:35 +08:00
浅念 92e64b7f10 fix(api): seed-admin works in production containers (no dotenv/workspace)
Production image installs prod deps only — dotenv is a devDep, and the
pnpm-workspace.yaml root lookup throws in containers. Both now degrade
gracefully: env comes from container env vars. Hot-patched into the running
test deployment during 2026-09-21 deploy; committed for the next image build.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 11:32:07 +08:00
浅念 52d8a57751 docs(deploy): single-server dual-stack test deployment plan
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 10:27:02 +08:00
浅念 5cdf828ff5 docs: G1 gate closure recorded in master plan and P5 draft
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 10:17:16 +08:00
浅念 eb8983a06c feat(storage,g1): real-OSS support and G1 smoke — gate CLOSED
G1 (skipped at P1 for lack of credentials) executed 2026-09-21 against the
user-provided bucket live-album @ oss-cn-beijing:

Raw-SDK smoke (scripts/g1-oss-smoke.mjs, creds via runtime env only):
- HeadBucket / presign PUT direct upload / head byte+type verify /
  presign GET round-trip / copy staging→originals / idempotent replay /
  DeleteObject cleanup — all pass.
- S3-compat lifecycle query unsupported → console manual check remains the
  only open G1 sub-item (need: confirm no lifecycle rule hits photo-live/).

Adapter-level (production path, createStorageFromEnv → real OSS):
- presignPut+PUT 200, head verify, presignGet round-trip equal,
  copyIfAbsent idempotent (created:true→false, same etag),
  forbid-overwrite guard throws UPLOAD_VERIFY_FAILED — all pass.

Findings locked in:
- Addressing: OSS S3-compat requires virtual-host style with BASE endpoint
  (path-style → 403 signature mismatch). StoragePort adapter gains optional
  MinioStorageConfig.forcePathStyle + S3_FORCE_PATH_STYLE env (default true
  keeps local MinIO behavior); required-field validation fixed to string
  fields only (boolean false ≠ missing).
- .env.production.example-cn S3 section updated to the confirmed shape
  (beijing endpoint/region, virtual-host, bucket live-album).

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 10:16:33 +08:00
浅念 c26d6b9a73 fix(deploy): review fixes — smoke photoId field, web healthcheck wget, outbox table name, cdn key shape
Reviewer findings on p5-prep batch:
1. BLOCKING: prod-smoke.sh visibility grep used "id" but API items
   serialize photoId (cn public.service / ov public-ov.service) — every
   healthy deployment would false-FAIL release gate ④. 4 sites fixed.
2. web/web-ov healthchecks used curl on nginx:alpine (absent) → perpetual
   false-unhealthy; switched to busybox wget.
3. RUNBOOK rollback rule cited nonexistent sync_outbox → outbox_events.
4. cdn-checklist invalidation sample key shape aligned to actual
   variantsObjectKey layout (.../albums/{albumId}/variants/{photoId}/{version}/{variant}.jpg).

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-21 02:03:44 +08:00