浅念
8be21b856b
feat(mobile): login, password change and logout screens
...
P3 Task 3 移动端(对接 Task 2 api client + 本任务新增的后端契约):
- 登录页实装:账号/密码表单(空值客户端校验)→ api.login(会话自动
持久化)→ pushReplacement /home;错误码本地化(AUTH_INVALID_
CREDENTIALS / AUTH_RATE_LIMITED(含稍后再试文案)/ 网络 / 校验);
提交加载态防重复提交。
- 修改密码页(设置页入口):当前/新/确认三字段,客户端校验(≥8 位、
两次一致)→ api.changePassword → toast + pop;成功后本地会话不变
(服务端保留当前会话);旧密码错误(401 AUTH_INVALID_CREDENTIALS)
显示「当前密码错误」且不触发 401 驱逐。
- 退出登录:设置页按钮 → api.logout 尽力而为 → 清会话 → 清栈回
/login;App 壳 initState 注册 onUnauthorized(业务 401 → 清栈 /login),
根 navigatorKey 接线;password-change 的 401 豁免会话驱逐(拦截器
豁免集合与令牌附加分离)。
- l10n:新增 16 组 zh/en 文案;错误码 → 文案解析扩展
(core/error_l10n.dart,errorCode→AppLocalizations)。
- 测试:ApiClient.changePassword 单测 ×2(Bearer+请求体;旧密码 401
不驱逐);widget 测试 ×12(登录 5:空值/成功跳转/凭据错误/限速文案/
加载禁用;改密 4:过短/不一致/旧密码错误文案+会话保留/成功 toast+pop
且令牌不变;设置 2:改密入口跳转/登出清会话回登录;App 壳 1:401
清栈回 /login)。flutter analyze 0 issue;flutter test 81/81。
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-19 01:19:57 +08:00
浅念
f975321b67
feat(mobile): api client, session storage and contract-aligned models
...
P3 计划 Task 2(apps/mobile):
- core/config.dart:API_BASE/VIEWER_BASE 经 --dart-define 覆盖,缺省
10.0.2.2 模拟器宿主回环;viewer 相册链接构造 {VIEWER_BASE}/a/{token}。
- core/error_codes.dart:errors.ts 17 码 1:1 镜像(含注释),另设 4 个
客户端本地伪码(NETWORK_ERROR/NETWORK_TIMEOUT/CANCELLED/HTTP_ERROR)。
- core/api_client.dart:dio 封装——Bearer 注入(登录端点豁免)、401
驱逐(清会话 + onUnauthorized 回调去重,App 壳注册跳 /login)、
DioException/错误体 {code,message,requestId} 归一 AppException、
通用游标分页助手;auth/albums/members/categories/admin/uploads/photos
全端点方法;riverpod provider 出口。
- core/session_store.dart:SessionStore 抽象 + flutter_secure_storage
实现(token/expiresAt/account 三键,encode/decode 纯函数可测)。
- features/{auth,albums,uploads,photos}/models.dart:手写 fromJson/
toJson,逐字段对齐 openapi.yaml(类注释标注契约 schema/operationId);
locale 按字符串透传(zh-CN 标识符不兼容),业务枚举 Dart 化并在
未知值 fail-fast。
- 测试 66 项:17 码表驱动 + 网络/超时/取消 + 兜底映射、游标边界
(含 CursorPageMeta 不变式违约容错)、模型往返(fixture 转写自
openapi.yaml schema 与 api e2e 断言,来源在测试头注释)、拦截器
行为(手写 FakeAdapter:Bearer 注入/401 驱逐/登录豁免/并发去重/
尽力而为 logout/refresh 滑动续期)。flutter analyze 零告警。
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-19 00:40:02 +08:00
浅念
8bc50e07ef
feat(mobile): flutter scaffold with env script and baseline nav
...
- scripts/flutter-env.sh: toolchain PATH/JAVA_HOME/ANDROID_HOME + pub 镜像 env
- apps/mobile: flutter create (com.photolive.photo_live, android+ios)
- Android minSdk 24 / targetSdk 36;INTERNET 权限(main manifest,debug+release)
- iOS Info.plist:本地网络 ATS 例外 + 相册/相机用途说明(zh+en)
- 依赖接入:riverpod / drift(+sqlite3_flutter_libs) / dio / secure_storage /
image_picker / camera / qr_flutter / path_provider / path / intl
- l10n:l10n.yaml + app_zh/app_en arb(20 键),gen-l10n(zh 模板,非空 getter)
- 基线:Material 3 主题、/login→/home 命名路由、底部导航(相册/队列/设置桩)、
locale provider 脚手架(Task 10 完成切换)
- flutter analyze 零问题;widget 测试通过;debug apk 构建成功
(MuMu 冒烟因宿主 commit 内存耗尽未完成,Task 2 重试)
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-19 00:22:04 +08:00
浅念
cdead49838
feat(viewer): likes, bubbles, visit reporting and hot sorting
...
Task 10 viewer 互动化:
- 点赞:useLikes 批次状态机(500ms 防抖 / 5 次满额即冲 / 失败同 batchId
退避重试 3 次后回滚丢弃),乐观计数 + 服务端 total 权威校准
(countVersion 单调),大图与格子双入口;
- WS 实时:RealtimeClient 纯状态机(半频心跳、指数退避重连、三败降级、
重连成功 resync 第 1 页重取),消息路由器做 likes.burst 自身过滤
(originBatchIds 求交)、隐藏页暂停与减少动画下仅校准不出气泡;
photo.hidden/deleted 即时移出序列并回退邻居大图;降级后 8s 轮询接管;
- 浏览上报:visitorId 跨标签 BroadcastChannel first-writer-wins 协调,
可见时上报、requestId 持久幂等、网络失败指数重试;
- 排序:最新/热门 chips(热门走 ov 冷快照),大图打开期间禁用切换;
顶栏「减少动画」偏好开关;
- 契约包新增 ./realtime 子路径出口(浏览器面不可引桶出口——其连带
internal-sync 的 node:crypto 会被 Vite 外置化致整页崩溃);
- e2e 注入钩子 __viewerWsUrl/__viewerWsRetryBaseMs/__viewerRealtimePollMs/
__viewerBubbleMs 与 .activity[data-connection] 连接态锚。
vitest:viewer 105(新增 36:likes 批次 8、visitor 协调 5、上报门控 4、
路由 8、WS 状态机 7、排序 4);Playwright:viewer 21(新增 likes.spec 7、
journey 补互动腿断言)。
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 19:52:27 +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
浅念
40f8f37ca4
test(e2e): p1b cross-frontend playwright journey
...
- viewer playwright.config: third webServer boots admin dev (5176,
reuseExisting) so one config serves both frontends
- journey.spec.ts: admin UI (login, zh+en album, real-jpeg banner via
file chooser, category, staffB invite by account search, logout) ->
staffB API uploads x3 (init/presign-PUT/complete) -> worker
PublishService.processPhoto x3 -> public list verify -> viewer UI
(banner bytes, zh->en switch, waterfall 3, chip filter 1, lightbox
zoom/close, deep link) -> admin hide -> viewer 2 + hidden deep-link
404 notice -> empty album state
- cleanup: journey album domain rows + staffB account via Prisma
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 12:54:18 +08:00
浅念
50c59ca9d4
feat(admin): album management pages with members and categories
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 12:33:46 +08:00
浅念
a6cc190751
feat(admin): art-design-pro integration with local session auth
...
P1b Task 9: apps/admin based on art-design-pro v3.0.2 (tag, commit
d224dd4; source recorded in apps/admin/SOURCE.md), trimmed to
layout/login/i18n/request/table-form core. Login wired to real
POST /v1/auth/password (single-token session), Bearer header on all
requests, 401 interceptor logout+redirect, request-driven sliding
renewal (refresh at ~80% TTL, single-flight), best-effort
POST /v1/auth/logout on user-menu logout. One protected stub page
(相册管理). Dev port 5176 strictPort + /v1 proxy to 8080. Admin keeps
its own eslint9 flat config; root eslint ignores apps/admin/**.
vitest unit tests for renewal pacing + Playwright e2e (guard redirect,
localized wrong-password error, login lands on stub, token persists
across reload, logout clears session).
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 11:47:32 +08:00
浅念
90fe64f637
feat(viewer): photo viewer with zoom, navigation and deep link
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 11:04:05 +08:00
浅念
d0b79dd0c9
feat(viewer): waterfall feed with lazy load, filter and new-photo hint
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 10:23:27 +08:00
浅念
adc45b1563
feat(viewer): album page with locale fallback and timezone display
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 09:52:22 +08:00
浅念
04b5641901
chore(viewer): move dev ports to 5175/5176 (user decision; avoids cms project conflict on 5173)
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 09:18:27 +08:00
浅念
f9cb72ed06
feat(viewer): vite vue3 scaffold with routing and i18n
...
- apps/viewer (@photo/viewer): Vite 5 + Vue 3.4 + TS 最小骨架(无 Pinia/UI 库)
- router: /a/:token 活动页 + /a/:token/p/:photoId 单图深链(复用活动页组件)
- i18n: vue-i18n 9,zh-CN/en 词条,localStorage(viewer.locale) 持久 +
navigator.language 检测兜底 zh-CN;顶栏语言切换组件;文案全量走 i18n
- api client: 类型化 fetch 封装(契约生成类型直连),错误信封 → ApiError,
错误码 → i18n key 映射表(src/api/errors.ts)
- scripts: dev/build/preview/test(vitest 10 例)/test:e2e(Playwright 冒烟,
webServer 自拉 dev)/lint/vue-tsc 全部接入 turbo
- root: +@playwright/test、+eslint-plugin-vue(flat config 收敛到 apps/**/*.vue)、
pnpm.onlyBuiltDependencies 放行 esbuild
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-09-18 09:12:45 +08:00