Extract all Chinese from DocsView.vue into docs.* namespace and add
auth.narrative.* sub-namespace for LoginView/RegisterView narrative slots.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces all rendered Chinese strings in LandingView with $t() calls and
<i18n-t> interpolation components; adds landing namespace (62 leaf keys) to
both zh.ts and en.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Port A-group deltas from design zip (excluding bonus/pricing which
are explicitly out of scope):
- Narrative: N (not 5) 个订阅; add '// 5 分钟开始用' n-kicker;
SVG hexagon logo (was emoji); n-bottom live status bar
- Add 3-step onboarding panel (创建账户 → 绑定订阅 → 生成 key)
in narrative, active-step highlighted
- Add password strength meter (4 bars + text label 弱/中/强/极强)
- Add confirm-password field with live // matched/mismatch hint
- Add Terms & Privacy consent checkbox (submit gated)
- New i18n keys: confirmPasswordLabel/Placeholder, passwordsDoNotMatch
All existing Vue logic preserved (OAuth/Turnstile/verify code/
invitation+promo codes).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three regressions from Task 7-9 caused /login /register to render broken:
- bg-glow not rendering: puro.css scopes .bg-glow to .puro-page,
AuthLayout isn't inside one. Fix: duplicate bg-glow rules into
AuthLayout scoped CSS keyed on .auth-shell-split.
- .auth-main had no background: right side showed naked body bg.
Fix: .auth-shell-split now sets var(--bg-0) for whole shell.
- Heading/label colors used text-gray-900 light-mode classes,
invisible on dark bg. Fix: switch to explicit text-slate-50/400,
and :deep() override for form inputs via AuthLayout split scope.
Legacy (non-split) mode unaffected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Login and Register heading strings moved from hardcoded Chinese to
auth.puroLoginTitle / puroLoginSub / puroRegisterTitle / puroRegisterSub.
Landing (LandingView) and Docs (DocsView) intentionally keep hardcoded
Chinese this cycle (see spec §6 note 5 — English version deferred).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Route /docs (no auth). Six sections: get key, codex CLI, claude code,
curl, supported models, feedback. Uses puro.css design system.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same split layout as LoginView: left narrative, right form.
Heading: '创建账户' + '5 分钟开始用 PURO AI'.
All form logic preserved (OAuth, Turnstile, email verify code, password fields).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Left: ⬢ PURO AI brand + '5→1' headline + three-line value props
- Right: existing form (OAuth, Turnstile, 2FA all preserved unchanged)
- Heading changed from t('auth.welcomeBack') to '登录' — i18n key consolidation in Task 11
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New slot 'narrative' enables split-screen layout (50/50 desktop, collapses
to single column on mobile <900px).
Backward compatibility:
- Pages that don't pass a narrative slot still render the original
centered-card layout with siteName + logo + copyright
- ForgotPassword, ResetPassword, EmailVerify unaffected
To be used in Tasks 8 and 9 (LoginView, RegisterView).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add noreferrer to all external rel attributes (4 anchors)
- Change 更新日志 link from /releases (may 404) to /commits/branch/main
- Remove dead CSS overridden by puro.css: .nav z-index:10, .nav-links gap:20px
- Document puro.css global dependency at top of scoped style block
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 4-column footer (brand/产品/资源/联系), responsive 2-col on mobile
- Nav sticky with blur background, border-bottom
- nav-links hidden on mobile (<640px)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dashboard mockup is pure static (SVG chart + stats grid + log table).
No backend dependency. Reuses puro.css .log-table / .provider / .status-*
(scoped to .puro-page). Only adds component-local styles for .code-demo,
.dash-mock, .stat-row, .chart-card and friends.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Temporary route /landing-preview added for dev iteration. Will flip /
to this view once all 6 sections are in place (Task 6).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
One missed prefix from the automated transform. Aligns with the
scoping contract established in 41664efe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add puro.css (tokens + primitives) as global stylesheet
- Load Inter + JetBrains Mono via Google Fonts
- Extend tailwind.config with puro.* color namespace (no conflict with legacy primary/accent palettes)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace dead EventSource variable with AbortController to enable
cancelling fetch streams. Remove close-button disable during connecting
status so users can dismiss the dialog at any time.
- Show base amount (充值金额) as first line
- Show fee amount with percentage when fee_rate > 0
- Show pay_amount (实付金额) in bold primary color
- Show credited amount (到账金额) when different from pay_amount
- Compute baseAmount and feeAmount from backend order data
Backend:
- Use cfg.RechargeFeeRate in order creation instead of hardcoded 0
- Remove dead getFeeRate stub method
- All amounts computed server-side: order_amount, pay_amount, fee_rate
Frontend - PaymentView:
- Read recharge_fee_rate from checkout-info API (not per-method)
- Show fee breakdown only when fee_rate > 0
- Show credited amount only when multiplier ≠ 1
Frontend - Order display (user + admin):
- Fix fee_rate * 100 bug (fee_rate is already a percentage)
- OrderTable: show pay_amount as primary, fee/credited as sub-lines
- AdminOrderDetail: full breakdown (base/fee/paid/credited)
- AdminRefundDialog: label "到账金额" for clarity
- PaymentResultView: show pay_amount with fee info
Types + i18n:
- Add recharge_fee_rate to CheckoutInfoResponse
- Add fee_rate to CreateOrderResult
- Add translations: creditedAmount, fee, baseAmount, includedInPayAmount
Extract repeated badge template (SVG icon + current/max display) into
a reusable CapacityBadge component. Reduces AccountCapacityCell from
~300 lines to ~180 lines with identical behavior.
Bug fixes:
- Detached context for GetAccountConcurrencyBatch (prevent all-zero on request cancel)
- Filter soft-deleted users in GetByGroupID
- Stripe CSP policy (allow Stripe.js in script-src and frame-src)
- WebSearch API key validation on save
- RECHARGING status in payment result success check
- Windows test fixes (logger Sync deadlock, config path escaping)
Feature enhancements:
- Webhook multi-instance dispatch (extractOutTradeNo + GetWebhookProvider)
- EasyPay mobile H5 payment (device param + PayURL2)
- SSE error propagation in WebSearch emulation
- AccountStatsCost DTO field for admin usage logs
- Plans sort by sort_order instead of created_at
- UsageMapHook for streaming response usage data
- apicompat Instructions field passthrough
- EffectiveLoadFactor for ops concurrency/metrics
- Usage billing RETURNING balance for notify system
- BulkUpdate mixed channel warning with details
- println to slog migration in auth cache
- Wire ProviderSet cleanup
- CI cache-dependency-path optimization
Frontend:
- Refund eligibility check per provider (canRequestRefund)
- Plan sort_order editing
- Dead code cleanup (simulate_claude_max, client_affinity)
- GroupsView platform switch guard
- channels features_config API type
- UsageView account_stats_cost export
allow_user_refund:
- Add allow_user_refund field to PaymentProviderInstance ent schema
- Migration 103: ALTER TABLE payment_provider_instances ADD COLUMN
- Cascade logic: disabling refund_enabled auto-disables allow_user_refund
- User refund validation: check provider instance allows user refund
- Admin refund validation: check provider instance allows admin refund
- Subscription refund: deduct days on refund, rollback on failure
- New endpoint: GET /payment/orders/refund-eligible-providers
- Frontend: ToggleSwitch in ProviderCard/Dialog, cascade in SettingsView
Wildcard matching:
- Change findPricingForModel from "longest prefix wins" to "config order
priority (first match wins)", aligning with channel service behavior
- QuotaLimit changed to *int64 (null=unlimited, >0=limited)
- Add reset-usage endpoint (POST /admin/settings/web-search-emulation/reset-usage)
- Show quota usage in header always (collapsed and expanded)
- Add reset quota button in expanded provider view
- Quota input: empty=unlimited with ∞ placeholder, must be >0 if set
- Add email verification hint on balance notify card
The buttons were hidden because v-if only checked provider.api_key,
which is always empty for saved providers (backend sanitizes it).
Now also checks api_key_configured. Copy button is disabled when
no actual key is available (only configured placeholder shown).