Files
wordpress-theme-aksrt/.specs/plans/frontend-modal-identity-badges.md
T
2026-08-04 20:40:59 +08:00

8.3 KiB

Plan: Frontend Modal Identity and Badges

Architectural Decisions

  • Dependency: This plan starts only after frontend-modal-runtime Phase 2 supplies AksrtModalRuntime, loader/cache/state contracts, telemetry marks, and the rollout reader.
  • Authentication snapshot: AuthApply and ApplicationRepository expose one current-user snapshot containing verification state, latest application, form payload, allowed next action, and poll metadata. The REST handler and owner permission callback reuse that loaded application instead of querying by UUID twice.
  • External provider boundary: Aliyun/Tencent validation and refresh stay behind ApplicationService. Provider HTTP work starts after the shell is visible, is cancellable/visibility-aware where possible, and cannot prevent the modal from opening.
  • Badge canonical path: The JSON REST path is the only new badge read/write path. User-center and public author entry points share the same privacy-aware DTO; old HTML AJAX modal registrations and post-wear remote reopening are removed after cutover.
  • Privacy: Cache keys include user/object/context and public-display mode. Authentication evidence remains owner/capability protected and no-store; public badge data follows list_for_user() privacy rules. No private DTO is persisted in browser storage.
  • Domain cache: Badge owned/wear maps and authentication snapshots use short in-memory/request-context memoization. Any submit, review, wear, or status transition invalidates the affected tag before rendering the next view.
  • Admin boundary: Existing native authentication review and badge management remain the operational surface. This plan does not move them into the Admin SPA.

Phase 1 — Authentication status appears quickly and refreshes safely

User stories: US8, US9, US13.

What to build

Replace the three independent SSR facade reads in inc/helpers/user-center-renderers/profile-auth.php with one typed snapshot from src/User/AuthApply.php/src/User/ApplicationRepository.php. Shape the current identity REST response around the same snapshot and reuse the application loaded by owns_application() in src/Identity/RestController.php inside get/refresh/manual handlers. Update assets/js/routes/user-center-auth.js to open the unified shell immediately, render snapshot state, defer provider refresh until the modal is open or the user explicitly refreshes, pause while hidden, apply backoff, and cancel stale refreshes. Preserve the existing create, manual evidence, provider callback, nonce, owner, capability, and sensitive no-store boundaries.

Done when

  • profile-auth.php, AuthApply, and ApplicationRepository produce one active/latest/verified snapshot per request; browser harness scenario auth-snapshot-query-count with SAVEQUERIES shows no repeated identical application SELECT for the active panel.
  • RestController owner permission and get/refresh/manual handlers reuse one loaded application per request; php -l src/User/AuthApply.php src/User/ApplicationRepository.php src/Identity/RestController.php src/Identity/ApplicationService.php passes.
  • Browser scenario auth-modal-deferred-refresh verifies shell-first rendering, no polling while the modal is closed, pause on hidden visibility, minimum interval/backoff, cancellation on close, and a useful error when the provider exceeds its timeout.
  • Browser/API scenarios cover create, provider-pending, processing, verified, rejected/manual retry, evidence upload, duplicate submit, unauthorized owner, and sensitive evidence isolation; existing native review changes are reflected on the next snapshot.

Phase 2 — Badge modal uses one cached JSON path

User stories: US10, US11, US12, US13.

What to build

Refactor src/User/Badges.php so list_for_user(), get_owned_map(), and get_wear() share one context and do not rebuild owned/wear dictionaries repeatedly. Remove duplicate Badges::init() calls from functions.php. Update assets/js/user-badges.js to use the runtime loader, short cache, skeleton/error/retry states, and tag invalidation after wear. Replace the user-center and public author HTML/AJAX modal entry points in inc/helpers/user-center-renderers/profile-header.php, templates/parts/user/author-hero.php, and assets/js/core/remote-modal.js with the canonical privacy-aware JSON path. The old wp_ajax(_nopriv)_aksrt_*badge*modal handlers and post-wear remote reopen must disappear after this cutover.

Done when

  • SAVEQUERIES scenario badge-read-query-count shows one shared owned/wear/dictionary read context per badge response, and a repeated open for the same user/context uses the runtime cache without cross-user reuse.
  • assets/js/user-badges.js displays skeleton/empty/error/retry states, re-renders the current list after wear, and no longer calls AksrtRemoteModal.openRemote after a successful wear; node --check assets/js/user-badges.js assets/js/core/remote-modal.js passes.
  • git grep -n "aksrt_user_badge_info_modal\|aksrt_single_badge_info_modal\|get_info_link" shows no active target entry after the canonical path is enabled, and functions.php contains one badge singleton initialization.
  • Browser/API scenarios cover no badges, earned/unearned/in-progress/detail, wear success/failure, public author privacy, self/manager visibility, unauthenticated access, REST nonce, and no leakage through cache keys.

Phase 3 — Authentication and badges are independently releasable

User stories: US1, US2, US3, US11, US12, US13, US14.

What to build

Connect identity and badge loaders to the per-domain rollout values from frontend-modal-runtime. Make successful authentication transitions, manual review results, badge wear, and badge management invalidate the appropriate runtime tags and update header/profile signals without a full reload. Exercise the two domains as separate gray releases, then remove the old domain-specific modal branches once each switch is permanently enabled.

Done when

  • The authentication and badge rollout values independently select the new loader path; toggling one does not change the other and does not create a second data store or dual-read branch.
  • php tools/audit-admin-contracts.php exits 0 and node --check assets/js/routes/user-center-auth.js assets/js/user-badges.js passes after the final route/schema changes.
  • Desktop/mobile scenarios verify shell/ready/error budgets, state refresh behind the modal, focus/keyboard behavior, no horizontal overflow, and no stale private data after logout or account switch.
  • The gray-release checklist records shell/ready/error/status-mismatch metrics and demonstrates pausing the next rollout stage when identity or badge errors exceed the agreed threshold.

Out of Scope

  • 修改会员价格、会员权益、支付网关规则、订单账务、退款核算、认证资格/审核政策或徽章授予条件;这些规则只允许被新的流程正确调用和展示。
  • 新增支付渠道、替换支付供应商、在浏览器保存支付凭证,或改变支付回调/异步结算机制。
  • 新增公开认证资料库、向其他用户暴露认证文档、跨用户查看订单或徽章数据。
  • 把订单、售后、认证审核或徽章运营工作台迁移进配置型 SPA;日常运营仍属于原生 WordPress 后台。
  • 全站页面导航、用户中心信息架构、品牌设计系统或所有非弹窗页面的全面重做;本期只统一弹窗运行时和四类流程所需的轻量体验。
  • 强制页面加载时预取所有弹窗数据、长期持久化敏感弹窗数据、建立订单/认证/徽章的第二套事实存储或长期保留旧新双路实现。
  • 以新增兼容别名、旧 option 双读、静默降级或数据迁移层解决旧实现问题;流程切换后以新的规范化链路为唯一实现。
  • 建立独立的数据仓库、复杂转化漏斗或第三方用户行为追踪系统;本期观测只服务于弹窗性能、错误和业务状态闭环。

Open Questions

  • 认证云供应商是否支持在请求取消/页面隐藏时安全停止远端刷新;若不支持,客户端只能停止轮询并让服务端回调/下次打开完成状态确认。
  • 徽章公开作者入口最终是否必须支持未登录访问;默认保留现有公开可见 DTO,但统一路径仍必须执行业务层 privacy 过滤。