Commit Graph

307 Commits

Author SHA1 Message Date
浅念 b79edf447b feat(app): bounded-parallel prepare (default 3) replaces serial queue
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 13:43:07 +08:00
浅念 dc5ae4a24a feat(app): raise default upload parallelism 2 -> 4
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 13:34:48 +08:00
浅念 cc47278f50 docs: upload speedup plan v2 — 9 tasks after full re-review
- Task 7 camera WYSIWYG aspect + pinch zoom (two-pointer test, throttled setZoom)
- Task 8 server-dedup app integration (force passthrough, PHOTO_DUPLICATE
  classification, l10n) — closes the 409 dead-end from 90dcc58
- Task 6 crop: crop_your_image 2.0.0 callback API + Isolate.run pixel pipeline
- Stale claims fixed (album_detail dedup already wired in 638dd9b), pre-flight
  parallel-session check added

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 13:34:03 +08:00
浅念 441a24a54c docs: upload speed optimization plan draft
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 11:33:04 +08:00
浅念 90dcc58c33 feat(uploads): P0-1 batch 4 — server-side duplicate photo detection (409 + force + index)
契约 UploadInitRequest 加 force(bool,仅 owner/admin 跳过查重)。
服务端 init 事务前置查重:同 albumId + uploaderId + bytes 的非 deleted
照片已存在 → 409 PHOTO_DUPLICATE。photos 表加 idx_photos_dedup 索引
(迁移 20260928120000)。
App UploadInitRequest 加 force 字段 + toJson 序列化。
本地查重(层 1)+ 服务端查重(层 2)双层防线到位。

API typecheck ✅ · app analyze ✅ · 397/397 ✅ · contract lint ✅

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 11:29:29 +08:00
浅念 33f347cdea feat(app): P0 batch 3 — offline detection with engine pause/resume + UI banner
P0-4 离线感知:
  - connectivity_plus → NetworkAvailability(online/offline/unknown)
  - engine_scope 三重绑定:有账号+有网 → start;任一失去 → stop(在途不中断)
  - 网络恢复 → start + onNetworkRestored(waitingNetwork 即时重试)
  - HomePage 顶部离线黄条(wifi_off + i18n 双语)

P0-5 更正:EXIF 方向已由服务端 sharp .rotate() 自动转正——v2 分析误报

397/397 全绿、analyze 0

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 11:23:51 +08:00
浅念 638dd9b45d feat(app): P0 batch 2+2.5 — local upload dedup with batch dialog, album switch check, file size guard
P0-1 层 1 本地查重:
  - checkDuplicates:同账号+同相册+state=completed+filename+bytes 匹配
  - EnqueueResult 返回 enqueued+duplicates+skipped
  - capture_page + album_detail_page:批量单次弹窗(非逐张)三选一
    [跳过重复上传非重复] [全部上传] [取消]

P0-8 相册上传开关预检:album_detail_page 入队前检查 uploadEnabled,
  关闭时提示「该相册已关闭上传」+ 不入队

P1-8 文件大小预检:preparer 限单文件 ≤100MB(磁盘满由 on Object 兜底)

P0-7 更正:上传并发限制已有(kMaxParallelUploads=2),v2 分析误报

397/397 全绿、analyze 0

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 11:06:40 +08:00
浅念 9edcb3f2b1 feat(app): P0 batch 1 — photo viewer zoom, camera lifecycle, image memory management
P0-2 查看器缩放:InteractiveViewer(5x max,放大后平移,1x 时穿透到
  PageView 滑动切页)
P0-3 相机后台释放:WidgetsBindingObserver——paused 时 dispose(省电+
  隐私指示灯),resumed 时重开(沿用前后摄/闪光灯偏好)
P0-6 图片内存管理:PhotoThumbnail 加 maxCacheWidth 参数——网格/列表
  缩略图限制解码宽度(600/400px),查看器大图不限

397/397 全绿、analyze 0

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 10:35:14 +08:00
浅念 98e073d8c8 docs: App potential issues v2 — full analysis with server-side dedup (confirmed, ready to execute)
v2 补齐 v1 自查发现的 8 个漏洞:三重指纹(filename+bytes+CRC32)、批量弹窗
(单次确认非逐张)、photos 表 dedup 索引、force 权限约束(owner/admin)、
上传并发限制(3)、相册开关预检、上传进度百分比、磁盘空间预检。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 10:24:46 +08:00
浅念 984fe8981c docs(viewer): prod verification — share sheet copy-only (native share button removed)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 09:15:30 +08:00
浅念 a5d71686ff feat(viewer): remove native share button from share sheet (user request) — copy link only
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-28 09:08:39 +08:00
浅念 dc8d3ff967 feat(app): launcher icon — brand logo 1024px + adaptive (blue #1A73E8 background)
flutter_launcher_icons 自动生成全尺寸 mipmap(48-192px + 自适应前景/背景)。
正式签名生产环境 APK 已打好。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 17:07:14 +08:00
浅念 2ce529dd5b docs(viewer): prod verification — share sheet without link text
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 16:55:07 +08:00
浅念 d279cefd71 feat(viewer): hide link text under QR in share sheet (user request) — QR + copy button remain
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 16:51:36 +08:00
浅念 643f837bca feat(viewer): hide view count in album header (user request) — counting/reporting unaffected
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 16:24:05 +08:00
浅念 cf490c7892 feat(app): all album date displays date-only — formatAlbumDateTime drops HH:mm
相册列表卡/详情信息/分享页 meta/照片查看器日期一律纯日期(y/M/d)。
全量测试断言同步;397/397 全绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 16:20:47 +08:00
浅念 07761b1b26 fix(app): camera preview distortion — swap sensor W/H for portrait
previewSize 报横向(W>H),竖屏直用会把画面拉扁。交换宽高转纵向比例再
FittedBox cover 铺满(裁切不变形)。397/397 全绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 16:07:44 +08:00
浅念 c199d0630c feat(embed): photo click opens album page in a new tab (user decision 2026-09-24)
Reverts the in-host detail modal interaction: click now window.open's the album page (/a/:token?lang=, no /p/ deep link) with noopener — same target for middle-click/right-click via the real <a> href. The loader's open-photo modal code remains but is no longer triggered.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 15:25:41 +08:00
浅念 bd4db7b458 style(viewer): 相册 banner 限高 320px + cover 裁切(PC 端观感修正)
height:100% + contain 在桌面宽屏下整图 letterbox 压扁留白——改为限高裁切。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 15:00:12 +08:00
浅念 32eb4ceb8e docs: 观众链接统一境外源定稿(后台分享/嵌入/App二维码均 ov 域名)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 14:46:54 +08:00
浅念 76380477a0 docs: 验收记录补嵌入组件 EMBED_ORIGIN 修正(cn 后台嵌入代码改指 ov 域名)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 14:01:12 +08:00
浅念 e5302e3929 docs: 正式环境双地域部署计划与验收记录
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 13:41:47 +08:00
浅念 30a3520669 fix(deploy): formalize nginx entrypoint ipv6 script removal in web.Dockerfile
G4 §4.8 事件 B:服务器新拉的 nginx:alpine 最新 digest 的
10-listen-on-ipv6-by-default.sh 在服务器上挂起(nginx 不启动、
healthcheck 拒连)。此前补丁只在服务器侧临时 Dockerfile,本次正式
进仓库;钉基础镜像版本后可移除(G4 待办)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 11:53:11 +08:00
浅念 d331d55880 chore: remove temporary freeze-debug spec
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 19:03:21 +08:00
浅念 17d510ccd5 fix(embed): scroll freeze final layer — Chrome fires a queued pointerenter after pointercancel when dragging outside, permanently trapping hover pause
Sequence: drag past iframe edge -> pointercancel (clears press state) -> Chrome still delivers one pre-queued pointerenter (re-sets hover) -> no further boundary events ever reach the iframe -> hover pause stuck forever. Fix: ignore pointerenter within 500ms after a pointercancel (and while pressed); re-set hover on genuine in-frame release so post-click hover behavior is preserved.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 18:59:47 +08:00
浅念 5efb89a252 fix(deploy): remove orphaned proxy directives from template cleanup
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 18:41:31 +08:00
浅念 57394387cc fix(deploy): proxy_pass double http:// prefix — API was down
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 18:39:12 +08:00
浅念 222c44c1f7 fix(deploy): disable gzip on /v1/ API paths — Flutter release AOT gzip decompression failure
服务端 200+数据正常、debug/JIT 正常;release/AOT 的 Dart HttpClient 对
Content-Encoding: gzip 解压异常 → JSON 解析失败 → 显示 INTERNAL_ERROR。
nginx /v1/ 路径 gzip off(静态资源 gzip 不受影响);proguard keep 规则
一并保留(dio/flutter_secure_storage/全项目模型)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 18:36:11 +08:00
浅念 fa06193a12 fix(embed): scroll freeze complete fix — remove pointer capture (broke photo clicks), keep watchdog
Capture redirected pointerup/click to the viewport element so photo <a> click handlers never fired (detail modal stopped opening). Watchdog alone is the deterministic freeze fallback: clears pointer/manual/hover/focus after 2s on lost release. A09 switched to count-based heart assertion (position check unstable under ambient bubbles + serial suite).

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 18:25:59 +08:00
浅念 65581b7920 fix(android): usesCleartextTraffic=true — release APK blocked HTTP APIs (Android 9+ default)
release 构建默认禁明文 HTTP(debug 由 Flutter 自动放行)——服务暂时不可用
即此因。当前测试服务器 API/观众页均为 http://,需显式允许;上 https 后移除。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 18:10:46 +08:00
浅念 f7f24b0a0b build(android): release signing config — key.properties based, debug fallback
正式签名(CN=PhotoLive):keystore/key.properties 不入库(gitignore 已覆盖);
无配置的构建机回退 debug 签名。首个正式签名 APK 已产出并 apksigner 验证。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 17:15:51 +08:00
浅念 1cad7823e2 fix(embed): watchdog also clears hover + releases capture (third freeze layer — capture suspends pointerleave, lost release never frees it)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 17:13:49 +08:00
浅念 74593d9953 fix(embed): scroll freeze root cause — drag-set 'manual' pause reason never cleared
setReason('manual', true) fired on >8px drag had no clear path anywhere (wheel/keyboard have 500ms timers; pointer path didn't) — one drag left the reason permanently, stopping auto-scroll until refresh. Now cleared on pointerup, watchdog, and window blur.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 17:09:17 +08:00
浅念 b414b3666e fix(embed): pointer pause watchdog — capture does not cross iframe boundary, outside-release now auto-resumes in 2s
The earlier capture+window-listener fix is insufficient: releasing outside the 195x280 window dispatches pointerup in the host document, which no in-iframe listener can observe. Deterministic fallback: 2s watchdog on pointerdown force-clears the pause reason (in-frame releases still cancel it immediately).

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 17:04:46 +08:00
浅念 2332d24591 docs(g4): clipboard HTTP-context fix record
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 17:04:45 +08:00
浅念 aaea76b0e3 fix(admin): copy buttons dead on HTTP origin — execCommand fallback
navigator.clipboard 仅安全上下文(HTTPS/localhost)可用,测试服务器经
http://IP:32005 访问时为 undefined,四处复制按钮(公开令牌/分享链接/
嵌入代码/重置密码)点击即抛 TypeError 且无提示。统一 utils/clipboard
copyText:API 优先、失败降级隐藏 textarea + execCommand。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 17:01:54 +08:00
浅念 cd8a3696e2 fix(embed): scroll freeze — pointer pause leaked when release happened outside window
Root cause: pointerup/pointercancel bound only on the viewport element; press on a photo then release outside the 195x280 window (or gesture interruption) never cleared the 'pointer' pause reason -> auto-scroll stopped permanently until page refresh.
- pointerdown now setPointerCapture (release guaranteed to return)
- window-level pointerup/pointercancel + blur fallbacks clear the reason
- rAF frame wrapped in try/catch so a single bad frame can no longer break the animation chain

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:57:04 +08:00
浅念 ae17776be6 feat(app): session restore on startup — no forced re-login after app restart
用户反馈:关闭 App 重开每次都要登录。根因:会话已持久化(安全存储,
服务端 TTL 30 天),但启动固定落在登录页——无人消费已存会话。

- _StartupGate(home):watch sessionAccount——在场直进 HomePage,离场
  LoginPage;状态驱动(401/登出清会话后 gate 自动重建,不依赖导航时序)
- onUnauthorized 保留 push 兜底(home 路由被显式导航替换后的 401 场景)
- 测试适配(boot 401 两项重写通过;397/397 全绿)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:48:27 +08:00
浅念 b6daa6fa0e docs(embed): live title+modal verification — '2026届-广交会' overlay, coordinate click opens in-host detail modal with deep link, closes via button
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:47:27 +08:00
浅念 a5dcfffd37 docs(embed): refreshed evidence artifacts (modal screenshot, screenshots/recordings regenerated)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:37:17 +08:00
浅念 da6f1b282e feat(embed): in-host photo detail modal + title overlay — e2e adapted (no popup, close button, some() heart attribution with ambient bubbles)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:36:51 +08:00
浅念 985829fee8 fix(app): poster title truly left-aligned — Column crossAxisAlignment start (QR re-centered)
Text 的 textAlign 被 Column 默认 center 吞掉(文本行收缩包裹时对齐不生效);
文字区 Column 改 CrossAxisAlignment.start,二维码+扫码说明显式 Center 回居中。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:30:14 +08:00
浅念 a16fa738f6 fix(app): poster — date-only text, left-aligned title/time/venue (QR stays centered)
用户反馈:海报日期仍带时间(表单已日期粒度,海报 formatAlbumDateTime 同步改
posterDate 只显 y/M/d);宣传图下标题/时间/地址居左;二维码保持居中。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:26:32 +08:00
浅念 8834b1bbb9 feat(embed): album title overlay + in-host photo detail modal (replaces new-tab open)
- viewer: EmbedStream shows album title overlay top-left (ellipsis, avoids collapse zone); photo click posts open-photo {url} to host instead of window.open (direct-open still new tab)
- loader v2: open-photo message (origin+source whitelisted, URL must match widget origin) opens host overlay modal with embedded viewer deep-link iframe, close button/Esc/scrim dismiss, single instance, cleaned on destroy
- tests: click case asserts modal iframe deep link + no popup + close button dismiss; viewer 244 + loader 36 green

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:20:10 +08:00
浅念 5a207b395e feat(app,viewer): WeChat card share + 'Share to...' label + site og tags
- 按钮文字「分享到微信/其他应用」→「分享到...」(用户需求)
- 微信卡片分享(fluwx 6):WECHAT_APPID 经 --dart-define 注入;已配置且
  装微信 → WXWebpage 卡片(标题=相册名、描述=日期·地点、缩略图=封面压缩
  240px PNG ≤32KB、点击进观众链接);未配置/未装 → 回退系统分享面板
- viewer index.html 加站点级 og 标签(微信/QQ 抓取链接预览用;每相册动态
  og 需服务端注入,登记后续增强)
- 397/397 全绿、analyze 0

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 16:05:53 +08:00
浅念 77b1519209 docs(viewer): like-hidden live verification — feed badges/sort tabs gone, lightbox bar is share+download only
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 14:31:21 +08:00
浅念 2babd364ba feat(viewer): hide like feature — action bar like slot, photo like badges, hot sort tab, others' like bubbles (user request 2026-09-23)
- PhotoFeed: cell like badge not rendered
- AlbumHeader: sort tabs row removed (hot depends on likes; latest-only has no toggle value)
- PhotoActionBar: like slot v-if=false (share/download remain, auto re-center)
- ActivityPage: LikeBubbles hidden
- specs updated to hidden assertions; 244 green

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 14:29:22 +08:00
浅念 e44b35db28 feat(albums): date-only pickers for start/end (create & edit, admin + app)
- 管理后台:DatePicker type=datetime → date;提交归一(开始=当天 00:00、
  结束=当天 23:59 整天活动语义;契约仍 datetime 仅交互粒度)
- App:去掉时间选择步骤(选日期即定;同上归一);表单显示只显 yyyy/M/d
- e2e 日期填入改 '2026-10-01'(date 格式);widget 断言日期粒度
- admin 87/87 + build、app 397/397 全绿

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 14:13:58 +08:00
浅念 f984535c2a fix(deploy): absolute_redirect off — root redirect keeps host:port through reverse proxy
nginx 默认 absolute_redirect on:return 302 被绝对化为 scheme://Host/(经
OpenResty 反代 Host 无端口 → 32005/ 跳到无端口的 /admin/ 打不开)。
off 后发相对 Location,浏览器按当前 host:port 补全。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 13:55:46 +08:00
浅念 7ef27797ff fix(deploy): root path redirect to admin (cn) — persisted in template+compose
用户约定:32005 根路径打开即管理后台。之前是直接改在服务器容器配置上的,
历次镜像重建被冲掉——本次固化进仓库:nginx 模板 location = / → 302
${ROOT_REDIRECT};Dockerfile 默认 /admin/;compose 按栈注入(cn=/admin/,
ov=/index.html 观众端安全自指,不影响 /a/<token> 与嵌入路径)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 13:52:29 +08:00