docs: add auth identity implementation plan
This commit is contained in:
@@ -0,0 +1,476 @@
|
|||||||
|
# Auth Identity Payment Foundation Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Rebuild the auth identity, profile binding, payment routing, and OpenAI advanced scheduler foundation on top of a clean `origin/main` branch while preserving historical compatibility for existing email users and historical LinuxDo users.
|
||||||
|
**Architecture:** A unified identity foundation centered on durable provider subjects (`email`, `linuxdo`, `oidc`, `wechat`) and transactional pending-auth sessions; backend-owned payment source routing behind stable frontend methods (`alipay`, `wxpay`); compatibility-first migration/backfill before feature enablement.
|
||||||
|
**Tech Stack:** Go, Gin, Ent, PostgreSQL, Redis, Vue 3, Pinia, TypeScript, Vitest, pnpm.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Non-Negotiable Product Rules
|
||||||
|
|
||||||
|
- [ ] Preserve login continuity for existing email users and historical LinuxDo users.
|
||||||
|
- [ ] During migration, backfill historical LinuxDo synthetic-email users into explicit LinuxDo identities before first post-upgrade login.
|
||||||
|
- [ ] Keep existing email login and add third-party login/bind for `linuxdo`, `oidc`, and `wechat`.
|
||||||
|
- [ ] On first third-party login:
|
||||||
|
- identity exists: direct login.
|
||||||
|
- identity does not exist: start pending-auth flow.
|
||||||
|
- local email binding is required only when system config says so.
|
||||||
|
- upstream provider email verification never counts as local email verification.
|
||||||
|
- [ ] When user-entered and locally verified email already exists:
|
||||||
|
- offer bind-existing-account after local re-authentication.
|
||||||
|
- offer change-email-and-create-new-account.
|
||||||
|
- when email binding is mandatory, do not allow bypass without changing to another email.
|
||||||
|
- [ ] On first third-party login or first third-party bind, provider nickname/avatar must be presented as independent replace options for the current nickname and avatar. They are not auto-applied.
|
||||||
|
- [ ] Source-specific initial grants must support per-source defaults for balance, concurrency, and subscriptions.
|
||||||
|
- [ ] Default grant timing: on successful new-account creation.
|
||||||
|
- [ ] Optional grant timing: on first successful bind for the configured source.
|
||||||
|
- [ ] Migration/backfill must never trigger first-bind or first-signup grants retroactively.
|
||||||
|
- [ ] Avatar profile supports:
|
||||||
|
- direct URL storage.
|
||||||
|
- image data URL upload compressed to `<=100KB` before storing in DB.
|
||||||
|
- explicit delete.
|
||||||
|
- [ ] Admin user management must expose and sort by `last_login_at` and `last_active_at`.
|
||||||
|
- [ ] WeChat login rules:
|
||||||
|
- WeChat environment uses MP login.
|
||||||
|
- non-WeChat browser uses Open/QR login.
|
||||||
|
- canonical identity uses `unionid`.
|
||||||
|
- when `unionid` is unavailable, fail the login/bind flow under the approved option-1 policy.
|
||||||
|
- [ ] Payment UI rules:
|
||||||
|
- user-facing methods stay `支付宝` and `微信支付`.
|
||||||
|
- backend decides whether each method routes to official provider instance or EasyPay.
|
||||||
|
- at runtime, each visible method may only have one active source.
|
||||||
|
- [ ] Alipay rules:
|
||||||
|
- PC: in-page QR.
|
||||||
|
- mobile browser: jump to Alipay payment.
|
||||||
|
- [ ] WeChat Pay rules:
|
||||||
|
- PC: in-page QR.
|
||||||
|
- WeChat H5: MP/JSAPI first, fallback to H5 pay.
|
||||||
|
- non-WeChat H5: H5 pay, or prompt to open in WeChat when unavailable.
|
||||||
|
- [ ] Payment success pages are informational only; actual fulfillment depends on webhook or server-side reconciliation.
|
||||||
|
- [ ] OpenAI advanced scheduler is available but default-disabled.
|
||||||
|
|
||||||
|
## Hard Technical Constraints From Audit
|
||||||
|
|
||||||
|
- [ ] Browser-based third-party auth must use Authorization Code + PKCE `S256`.
|
||||||
|
- [ ] OIDC identity primary key must be `(issuer, subject)`, not email.
|
||||||
|
- [ ] Email equality must never auto-link accounts.
|
||||||
|
- [ ] Bind-existing-account must require explicit local re-authentication and TOTP verification when enabled.
|
||||||
|
- [ ] OAuth redirect URI must be fixed server config, exact-match, and never derived from user input.
|
||||||
|
- [ ] User-supplied redirect may only choose a normalized same-origin internal route after completion.
|
||||||
|
- [ ] WeChat canonical identity must be `unionid`; `openid` remains channel/app-scoped support data only.
|
||||||
|
- [ ] Every payment order must snapshot the selected provider instance and reuse that exact instance for callback verification, reconciliation, refund, and audit.
|
||||||
|
- [ ] Frontend must not receive first-party bearer tokens through callback URL fragments in the rebuilt flow.
|
||||||
|
- [ ] Public payment result polling must not expose order data by raw `out_trade_no` alone; use authenticated lookup or signed opaque result token.
|
||||||
|
|
||||||
|
## Baseline Notes
|
||||||
|
|
||||||
|
- [ ] Current clean branch head when this plan was written: `721d7ab3`.
|
||||||
|
- [ ] Baseline backend verification on clean `origin/main`: `cd backend && go test ./...` passes.
|
||||||
|
- [ ] Baseline frontend verification on clean `origin/main`: `cd frontend && pnpm test:run` currently fails in unrelated existing suites. New work must add targeted tests and avoid claiming full frontend green until those baseline failures are addressed separately.
|
||||||
|
- [ ] Existing migration directory currently ends at `107_*`; this rebuild reserves `108` through `111`.
|
||||||
|
|
||||||
|
## Target File Map
|
||||||
|
|
||||||
|
### New backend migrations
|
||||||
|
|
||||||
|
- [ ] `backend/migrations/108_auth_identity_foundation_core.sql`
|
||||||
|
- [ ] `backend/migrations/109_auth_identity_compat_backfill.sql`
|
||||||
|
- [ ] `backend/migrations/110_pending_auth_and_provider_default_grants.sql`
|
||||||
|
- [ ] `backend/migrations/111_payment_routing_and_scheduler_flags.sql`
|
||||||
|
|
||||||
|
### New or rebuilt Ent schema
|
||||||
|
|
||||||
|
- [ ] `backend/ent/schema/auth_identity.go`
|
||||||
|
- [ ] `backend/ent/schema/auth_identity_channel.go`
|
||||||
|
- [ ] `backend/ent/schema/pending_auth_session.go`
|
||||||
|
- [ ] `backend/ent/schema/identity_adoption_decision.go`
|
||||||
|
|
||||||
|
### New or rebuilt backend repositories/services/handlers
|
||||||
|
|
||||||
|
- [ ] `backend/internal/repository/user_profile_identity_repo.go`
|
||||||
|
- [ ] `backend/internal/repository/user_profile_identity_repo_contract_test.go`
|
||||||
|
- [ ] `backend/internal/repository/auth_identity_migration_report.go`
|
||||||
|
- [ ] `backend/internal/service/auth_identity_flow.go`
|
||||||
|
- [ ] `backend/internal/service/auth_identity_flow_test.go`
|
||||||
|
- [ ] `backend/internal/service/auth_pending_identity_service.go`
|
||||||
|
- [ ] `backend/internal/service/auth_pending_identity_service_test.go`
|
||||||
|
- [ ] `backend/internal/service/payment_config_service.go`
|
||||||
|
- [ ] `backend/internal/service/payment_order.go`
|
||||||
|
- [ ] `backend/internal/service/payment_order_lifecycle.go`
|
||||||
|
- [ ] `backend/internal/service/payment_fulfillment.go`
|
||||||
|
- [ ] `backend/internal/service/openai_account_scheduler.go`
|
||||||
|
- [ ] `backend/internal/handler/auth_pending_identity_flow.go`
|
||||||
|
- [ ] `backend/internal/handler/auth_linuxdo_oauth.go`
|
||||||
|
- [ ] `backend/internal/handler/auth_oidc_oauth.go`
|
||||||
|
- [ ] `backend/internal/handler/auth_wechat_oauth.go`
|
||||||
|
- [ ] `backend/internal/handler/auth_handler.go`
|
||||||
|
- [ ] `backend/internal/handler/user_handler.go`
|
||||||
|
- [ ] `backend/internal/handler/payment_handler.go`
|
||||||
|
- [ ] `backend/internal/handler/payment_webhook_handler.go`
|
||||||
|
- [ ] `backend/internal/handler/admin/user_handler.go`
|
||||||
|
- [ ] `backend/internal/handler/admin/setting_handler.go`
|
||||||
|
|
||||||
|
### New or rebuilt frontend API/store/views/components
|
||||||
|
|
||||||
|
- [ ] `frontend/src/api/auth.ts`
|
||||||
|
- [ ] `frontend/src/api/user.ts`
|
||||||
|
- [ ] `frontend/src/api/payment.ts`
|
||||||
|
- [ ] `frontend/src/api/admin/settings.ts`
|
||||||
|
- [ ] `frontend/src/api/admin/users.ts`
|
||||||
|
- [ ] `frontend/src/stores/auth.ts`
|
||||||
|
- [ ] `frontend/src/stores/payment.ts`
|
||||||
|
- [ ] `frontend/src/components/auth/ThirdPartyAuthCallbackFlow.vue`
|
||||||
|
- [ ] `frontend/src/components/auth/LinuxDoOAuthSection.vue`
|
||||||
|
- [ ] `frontend/src/components/auth/OidcOAuthSection.vue`
|
||||||
|
- [ ] `frontend/src/components/auth/WechatOAuthSection.vue`
|
||||||
|
- [ ] `frontend/src/components/user/profile/ProfileAccountBindingsCard.vue`
|
||||||
|
- [ ] `frontend/src/components/user/profile/ProfileInfoCard.vue`
|
||||||
|
- [ ] `frontend/src/views/auth/LinuxDoCallbackView.vue`
|
||||||
|
- [ ] `frontend/src/views/auth/OidcCallbackView.vue`
|
||||||
|
- [ ] `frontend/src/views/auth/WechatCallbackView.vue`
|
||||||
|
- [ ] `frontend/src/views/user/ProfileView.vue`
|
||||||
|
- [ ] `frontend/src/views/user/PaymentView.vue`
|
||||||
|
- [ ] `frontend/src/views/user/PaymentQRCodeView.vue`
|
||||||
|
- [ ] `frontend/src/views/user/PaymentResultView.vue`
|
||||||
|
|
||||||
|
## Phase 1: Migration And Compatibility Foundation
|
||||||
|
|
||||||
|
### Task 1. Create core identity schema migration
|
||||||
|
|
||||||
|
- [ ] Implement `backend/migrations/108_auth_identity_foundation_core.sql` with:
|
||||||
|
- `auth_identities`
|
||||||
|
- `auth_identity_channels`
|
||||||
|
- `pending_auth_sessions`
|
||||||
|
- `identity_adoption_decisions`
|
||||||
|
- `users.last_login_at`
|
||||||
|
- `users.last_active_at`
|
||||||
|
- grant-tracking columns/tables required to prevent double-award
|
||||||
|
- [ ] Add uniqueness/index rules:
|
||||||
|
- one canonical identity per `(provider, provider_subject)`
|
||||||
|
- one channel record per `(provider, provider_channel, provider_app_id, provider_channel_subject)`
|
||||||
|
- one adoption decision per pending session
|
||||||
|
- [ ] Preserve null-safe compatibility defaults so historical rows remain readable before backfill finishes.
|
||||||
|
- [ ] Add explicit rollback blocks only where safe; never repeat the destructive pattern observed in old `112_update_pending_auth_sessions.sql`.
|
||||||
|
|
||||||
|
### Task 2. Materialize historical identities before runtime
|
||||||
|
|
||||||
|
- [ ] Implement `backend/migrations/109_auth_identity_compat_backfill.sql` to backfill:
|
||||||
|
- existing email users into `auth_identities(provider=email, provider_subject=normalized_email)`
|
||||||
|
- historical LinuxDo users into `auth_identities(provider=linuxdo, provider_subject=linuxdo_subject)`
|
||||||
|
- historical synthetic-email LinuxDo users into explicit LinuxDo identity rows by parsing legacy email mode and legacy provider metadata
|
||||||
|
- profile/channel rows from historical `user_external_identities`-style data when present in upgraded databases
|
||||||
|
- [ ] Write migration report output in `backend/internal/repository/auth_identity_migration_report.go` so production can inspect unmatched rows instead of silently skipping them.
|
||||||
|
- [ ] Set `signup_source` and provider provenance when recoverable from historical data. Do not flatten everything to `email`.
|
||||||
|
|
||||||
|
### Task 3. Provider default grant and scheduler config migration
|
||||||
|
|
||||||
|
- [ ] Implement `backend/migrations/110_pending_auth_and_provider_default_grants.sql` for:
|
||||||
|
- provider-specific initial balance/concurrency/subscription defaults
|
||||||
|
- grant timing flags: `on_signup`, optional `on_first_bind`
|
||||||
|
- email-required-on-third-party-signup flags
|
||||||
|
- profile avatar storage columns/settings
|
||||||
|
- [ ] Implement `backend/migrations/111_payment_routing_and_scheduler_flags.sql` for:
|
||||||
|
- stable payment method to provider-instance routing
|
||||||
|
- admin exclusivity flags for `alipay` and `wxpay`
|
||||||
|
- advanced scheduler enable flag defaulting to disabled
|
||||||
|
|
||||||
|
### Task 4. Generate Ent and compile migration-safe model layer
|
||||||
|
|
||||||
|
- [ ] Add the schema definitions in:
|
||||||
|
- `backend/ent/schema/auth_identity.go`
|
||||||
|
- `backend/ent/schema/auth_identity_channel.go`
|
||||||
|
- `backend/ent/schema/pending_auth_session.go`
|
||||||
|
- `backend/ent/schema/identity_adoption_decision.go`
|
||||||
|
- [ ] Run:
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
go generate ./ent
|
||||||
|
```
|
||||||
|
- [ ] Compile after generation:
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
go test ./... -run '^$'
|
||||||
|
```
|
||||||
|
- [ ] Commit checkpoint:
|
||||||
|
```bash
|
||||||
|
git add backend/migrations backend/ent/schema backend/ent
|
||||||
|
git commit -m "feat: add auth identity foundation schema"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 2: Backend Identity Flow Rebuild
|
||||||
|
|
||||||
|
### Task 5. Build a single repository contract for identity lookups and grants
|
||||||
|
|
||||||
|
- [ ] Implement `backend/internal/repository/user_profile_identity_repo.go` with transactional helpers for:
|
||||||
|
- get user by canonical identity
|
||||||
|
- get user by channel identity
|
||||||
|
- create canonical + channel identity together
|
||||||
|
- bind identity to existing user after verified re-auth
|
||||||
|
- record one-time provider grant award
|
||||||
|
- record adoption preference decisions
|
||||||
|
- update `last_login_at` and `last_active_at`
|
||||||
|
- [ ] Add repository contract coverage in `backend/internal/repository/user_profile_identity_repo_contract_test.go`.
|
||||||
|
- [ ] Enforce dual-write for email registration/login so `users.email` and `auth_identities(provider=email, ...)` stay consistent from this phase onward.
|
||||||
|
|
||||||
|
### Task 6. Rebuild transactional pending-auth service
|
||||||
|
|
||||||
|
- [ ] Implement `backend/internal/service/auth_pending_identity_service.go` and tests to own these flows:
|
||||||
|
- create pending session from third-party callback
|
||||||
|
- verify local email code
|
||||||
|
- create new account from pending session with correct `signup_source`
|
||||||
|
- bind pending identity to existing account after password/TOTP re-auth
|
||||||
|
- apply configured provider defaults on the correct trigger only once
|
||||||
|
- store provider nickname/avatar candidates and user opt-in replacement decisions independently
|
||||||
|
- [ ] Keep pending session payload normalized:
|
||||||
|
- provider identity fields live in typed columns/JSON structure
|
||||||
|
- avoid the old branch’s mixed `metadata` and `upstream_identity_payload` ambiguity
|
||||||
|
- [ ] Do not call plain email registration helpers from this flow. The old feature branch bug where pending third-party signup fell back to `RegisterWithVerification` must not reappear.
|
||||||
|
|
||||||
|
### Task 7. Rebuild provider callback adapters
|
||||||
|
|
||||||
|
- [ ] Refactor these handlers to thin adapters over the shared pending-auth service:
|
||||||
|
- `backend/internal/handler/auth_linuxdo_oauth.go`
|
||||||
|
- `backend/internal/handler/auth_oidc_oauth.go`
|
||||||
|
- `backend/internal/handler/auth_wechat_oauth.go`
|
||||||
|
- [ ] For OIDC:
|
||||||
|
- require PKCE `S256`, `state`, and `nonce`
|
||||||
|
- validate `iss`, `aud`, optional `azp`, `exp`, `nonce`
|
||||||
|
- persist canonical identity as `(issuer, sub)`
|
||||||
|
- [ ] For WeChat:
|
||||||
|
- MP flow in WeChat UA
|
||||||
|
- Open/QR flow outside WeChat UA
|
||||||
|
- persist channel identity by `(channel, appid, openid)`
|
||||||
|
- persist canonical identity by `unionid`
|
||||||
|
- hard-fail when `unionid` is absent under the approved product policy
|
||||||
|
- [ ] Replace callback URL fragment token delivery with backend session completion or one-time exchange code consumed by `frontend/src/stores/auth.ts`.
|
||||||
|
|
||||||
|
### Task 8. Rebuild auth endpoints and profile binding endpoints
|
||||||
|
|
||||||
|
- [ ] Implement `backend/internal/handler/auth_pending_identity_flow.go` for:
|
||||||
|
- fetch pending session summary
|
||||||
|
- submit verified email
|
||||||
|
- choose create-new-account or bind-existing-account
|
||||||
|
- submit nickname/avatar replacement choices
|
||||||
|
- [ ] Update `backend/internal/handler/auth_handler.go` and `backend/internal/handler/user_handler.go` to expose:
|
||||||
|
- current bindings summary
|
||||||
|
- start-bind endpoints for LinuxDo/OIDC/WeChat
|
||||||
|
- disconnect endpoints with safety checks
|
||||||
|
- avatar upload/delete endpoints
|
||||||
|
- [ ] Avatar handling requirements:
|
||||||
|
- allow external URL
|
||||||
|
- allow data URL upload
|
||||||
|
- compress image payload to `<=100KB`
|
||||||
|
- store compressed value in DB
|
||||||
|
- deleting custom avatar must not implicitly resurrect stale provider avatar unless the user explicitly chooses provider avatar again
|
||||||
|
|
||||||
|
### Task 9. Add admin visibility and sorting
|
||||||
|
|
||||||
|
- [ ] Update `backend/internal/handler/admin/user_handler.go` and supporting query/service code so admin list supports:
|
||||||
|
- `last_login_at`
|
||||||
|
- `last_active_at`
|
||||||
|
- sorting by both
|
||||||
|
- binding/provider summary columns
|
||||||
|
- [ ] Update `backend/internal/handler/admin/setting_handler.go` and setting service code for:
|
||||||
|
- provider initial grant config
|
||||||
|
- mandatory-email-on-third-party-signup config
|
||||||
|
- payment source exclusivity config
|
||||||
|
- advanced scheduler toggle
|
||||||
|
|
||||||
|
### Task 10. Backend verification checkpoint
|
||||||
|
|
||||||
|
- [ ] Run targeted backend tests:
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
go test ./internal/repository -run 'TestUserProfileIdentity|TestAuthIdentityMigration'
|
||||||
|
go test ./internal/service -run 'TestAuthIdentityFlow|TestPendingAuthIdentity|TestOpenAIAccountScheduler'
|
||||||
|
go test ./internal/handler -run 'TestLinuxDo|TestOidc|TestWechat|TestPaymentWebhook'
|
||||||
|
go test ./...
|
||||||
|
```
|
||||||
|
- [ ] Commit checkpoint:
|
||||||
|
```bash
|
||||||
|
git add backend
|
||||||
|
git commit -m "feat: rebuild auth identity backend flows"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 3: Frontend Third-Party Flow And Profile UX
|
||||||
|
|
||||||
|
### Task 11. Rebuild callback flow UI around pending session decisions
|
||||||
|
|
||||||
|
- [ ] Rebuild `frontend/src/components/auth/ThirdPartyAuthCallbackFlow.vue` so it:
|
||||||
|
- loads pending-session summary from backend
|
||||||
|
- shows provider nickname/avatar candidates
|
||||||
|
- lets user independently choose nickname replacement and avatar replacement
|
||||||
|
- handles create-new-account vs bind-existing-account
|
||||||
|
- enforces verified local email before completion when required
|
||||||
|
- handles “email already exists” by branching to bind-existing-account or change-email-and-create-new-account
|
||||||
|
- [ ] Update:
|
||||||
|
- `frontend/src/views/auth/LinuxDoCallbackView.vue`
|
||||||
|
- `frontend/src/views/auth/OidcCallbackView.vue`
|
||||||
|
- `frontend/src/views/auth/WechatCallbackView.vue`
|
||||||
|
- `frontend/src/api/auth.ts`
|
||||||
|
- `frontend/src/stores/auth.ts`
|
||||||
|
- [ ] Replace any token-fragment bootstrap with backend session completion or one-time exchange code flow.
|
||||||
|
|
||||||
|
### Task 12. Rebuild profile account binding and avatar UX
|
||||||
|
|
||||||
|
- [ ] Rebuild `frontend/src/components/user/profile/ProfileAccountBindingsCard.vue` to:
|
||||||
|
- show linked LinuxDo/OIDC/WeChat providers
|
||||||
|
- start bind/unbind flows
|
||||||
|
- show provider avatars and nicknames as reference only
|
||||||
|
- prevent unsafe disconnect when it would strand the account
|
||||||
|
- [ ] Rebuild `frontend/src/components/user/profile/ProfileInfoCard.vue` and `frontend/src/views/user/ProfileView.vue` to:
|
||||||
|
- support avatar URL entry
|
||||||
|
- support data URL upload/compression preview
|
||||||
|
- support avatar delete
|
||||||
|
- clearly separate current profile nickname/avatar from provider-sourced suggested nickname/avatar
|
||||||
|
|
||||||
|
### Task 13. Add frontend tests for rebuilt auth/profile flows
|
||||||
|
|
||||||
|
- [ ] Add or update:
|
||||||
|
- `frontend/src/components/auth/__tests__/ThirdPartyAuthCallbackFlow.spec.ts`
|
||||||
|
- `frontend/src/components/auth/__tests__/LinuxDoCallbackView.spec.ts`
|
||||||
|
- `frontend/src/components/auth/__tests__/WechatCallbackView.spec.ts`
|
||||||
|
- `frontend/src/components/user/profile/__tests__/ProfileAccountBindingsCard.spec.ts`
|
||||||
|
- `frontend/src/components/user/profile/__tests__/ProfileInfoCard.spec.ts`
|
||||||
|
- [ ] Cover:
|
||||||
|
- email-required branch
|
||||||
|
- email-conflict branch
|
||||||
|
- bind-existing-account with re-auth prompt
|
||||||
|
- nickname replacement only
|
||||||
|
- avatar replacement only
|
||||||
|
- neither replacement
|
||||||
|
- avatar delete after prior provider adoption
|
||||||
|
|
||||||
|
## Phase 4: Payment Routing Rebuild
|
||||||
|
|
||||||
|
### Task 14. Normalize payment routing backend
|
||||||
|
|
||||||
|
- [ ] Rebuild `backend/internal/service/payment_config_service.go` to expose a stable method-routing contract:
|
||||||
|
- frontend visible methods remain `alipay` and `wxpay`
|
||||||
|
- admin chooses which provider instance serves each method
|
||||||
|
- runtime validation guarantees only one active source per visible method
|
||||||
|
- [ ] Rebuild `backend/internal/service/payment_order.go` and `backend/internal/service/payment_order_lifecycle.go` so order creation snapshots:
|
||||||
|
- visible method
|
||||||
|
- selected provider instance id
|
||||||
|
- provider type
|
||||||
|
- provider capability mode
|
||||||
|
- [ ] Rebuild `backend/internal/handler/payment_handler.go` for UX rules:
|
||||||
|
- Alipay PC: QR page
|
||||||
|
- Alipay mobile: direct jump
|
||||||
|
- WeChat PC: QR page
|
||||||
|
- WeChat H5 in WeChat: MP/JSAPI first, fallback to H5
|
||||||
|
- WeChat H5 outside WeChat: H5 or “open in WeChat” prompt when unavailable
|
||||||
|
- [ ] Never derive canonical return URL from `Referer`; use configured or signed internal callback targets only.
|
||||||
|
|
||||||
|
### Task 15. Make fulfillment and reconciliation provider-instance-safe
|
||||||
|
|
||||||
|
- [ ] Rebuild `backend/internal/handler/payment_webhook_handler.go` and `backend/internal/service/payment_fulfillment.go` so:
|
||||||
|
- verification uses the order’s original provider instance
|
||||||
|
- webhook processing is idempotent by provider event id and internal order id
|
||||||
|
- missed webhook recovery uses server-side provider query, not frontend success return
|
||||||
|
- [ ] Harden `frontend/src/views/user/PaymentResultView.vue` and `frontend/src/api/payment.ts` so result polling uses an authenticated order lookup or signed opaque token, not a raw public `out_trade_no` query.
|
||||||
|
|
||||||
|
### Task 16. Rebuild payment frontend views
|
||||||
|
|
||||||
|
- [ ] Rebuild `frontend/src/views/user/PaymentView.vue`, `frontend/src/views/user/PaymentQRCodeView.vue`, and `frontend/src/stores/payment.ts` so:
|
||||||
|
- only two buttons are shown to user: `支付宝` and `微信支付`
|
||||||
|
- frontend does not leak official-vs-EasyPay distinction
|
||||||
|
- route-specific copy handles QR, jump, MP, H5 fallback correctly
|
||||||
|
- [ ] Add or update:
|
||||||
|
- `frontend/src/views/user/__tests__/PaymentView.spec.ts`
|
||||||
|
- `frontend/src/views/user/__tests__/PaymentResultView.spec.ts`
|
||||||
|
- backend webhook/payment routing tests
|
||||||
|
|
||||||
|
### Task 17. Payment verification checkpoint
|
||||||
|
|
||||||
|
- [ ] Run:
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
go test ./internal/service -run 'TestPayment'
|
||||||
|
go test ./internal/handler -run 'TestPayment'
|
||||||
|
cd ../frontend
|
||||||
|
pnpm test:run src/views/user/__tests__/PaymentView.spec.ts src/views/user/__tests__/PaymentResultView.spec.ts
|
||||||
|
```
|
||||||
|
- [ ] Commit checkpoint:
|
||||||
|
```bash
|
||||||
|
git add backend frontend
|
||||||
|
git commit -m "feat: rebuild payment routing foundation"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 5: Scheduler, Rollout, And Final Compatibility Pass
|
||||||
|
|
||||||
|
### Task 18. Gate advanced scheduler behind explicit config
|
||||||
|
|
||||||
|
- [ ] Update `backend/internal/service/openai_account_scheduler.go` and related admin setting surfaces so:
|
||||||
|
- advanced scheduler remains compiled and testable
|
||||||
|
- default runtime state is disabled
|
||||||
|
- enablement is explicit through admin settings
|
||||||
|
- legacy scheduling behavior remains default on upgrade
|
||||||
|
- [ ] Add targeted coverage in `backend/internal/service/openai_account_scheduler_test.go`.
|
||||||
|
|
||||||
|
### Task 19. Complete compatibility and rollout safety checks
|
||||||
|
|
||||||
|
- [ ] Add migration/repository tests covering:
|
||||||
|
- historical email-only user login after upgrade
|
||||||
|
- historical LinuxDo user login after upgrade
|
||||||
|
- historical synthetic-email LinuxDo user login after upgrade
|
||||||
|
- no retroactive grant replay during migration
|
||||||
|
- first-bind grant fires once only when enabled
|
||||||
|
- email identity dual-write stays consistent
|
||||||
|
- bind-existing-account requires password and TOTP where configured
|
||||||
|
- [ ] Add deploy sequencing note to release docs or internal runbook:
|
||||||
|
1. deploy schema and backfill release.
|
||||||
|
2. inspect migration report for unmatched rows.
|
||||||
|
3. deploy backend identity/payment compatibility code.
|
||||||
|
4. deploy frontend callback/profile/payment UI.
|
||||||
|
5. enable strict email-required signup or provider bind grants only after metrics are healthy.
|
||||||
|
|
||||||
|
### Task 20. Final verification and handoff
|
||||||
|
|
||||||
|
- [ ] Run final backend verification:
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
go test ./...
|
||||||
|
```
|
||||||
|
- [ ] Run targeted frontend verification:
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
pnpm test:run \
|
||||||
|
src/components/auth/__tests__/ThirdPartyAuthCallbackFlow.spec.ts \
|
||||||
|
src/components/auth/__tests__/LinuxDoCallbackView.spec.ts \
|
||||||
|
src/components/auth/__tests__/WechatCallbackView.spec.ts \
|
||||||
|
src/components/user/profile/__tests__/ProfileAccountBindingsCard.spec.ts \
|
||||||
|
src/components/user/profile/__tests__/ProfileInfoCard.spec.ts \
|
||||||
|
src/views/user/__tests__/PaymentView.spec.ts \
|
||||||
|
src/views/user/__tests__/PaymentResultView.spec.ts
|
||||||
|
```
|
||||||
|
- [ ] Run focused manual smoke checks:
|
||||||
|
- email login with existing account
|
||||||
|
- LinuxDo existing-account login after migration
|
||||||
|
- third-party first login create-new-account path
|
||||||
|
- third-party first login bind-existing-account path
|
||||||
|
- first third-party bind with optional nickname/avatar replacement
|
||||||
|
- PC Alipay QR
|
||||||
|
- mobile Alipay jump
|
||||||
|
- PC WeChat QR
|
||||||
|
- WeChat H5 MP/JSAPI path
|
||||||
|
- non-WeChat H5 fallback path
|
||||||
|
- [ ] Commit final checkpoint:
|
||||||
|
```bash
|
||||||
|
git add docs backend frontend
|
||||||
|
git commit -m "feat: rebuild auth identity and payment foundation"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Review Checklist
|
||||||
|
|
||||||
|
- [ ] No flow still relies on provider email equality for account linking.
|
||||||
|
- [ ] No flow still creates third-party users through plain email registration helpers.
|
||||||
|
- [ ] No callback still returns first-party bearer tokens in URL fragments.
|
||||||
|
- [ ] No payment result view trusts provider return page as authoritative fulfillment.
|
||||||
|
- [ ] No webhook verification path selects provider credentials from “currently active config” instead of the order snapshot.
|
||||||
|
- [ ] Existing email users and historical LinuxDo users are covered by migration tests.
|
||||||
|
- [ ] Avatar adoption and deletion semantics are explicit and reversible.
|
||||||
|
- [ ] Grant timing is source-aware and one-time only.
|
||||||
|
|
||||||
Reference in New Issue
Block a user