Files
sub2api/docs/superpowers/plans/fidelity-delta-report.md
mini 623a7518b2 fix(docs): remove iShare mention (puro 独立运营定位)
- docs.sections.getKey.note 键从 zh/en 删除
- DocsView 对应 <p class="note"> 段删掉
- 全仓再次 grep 确认无其他 ishare/iShare 引用
2026-04-23 13:08:43 +08:00

446 lines
42 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PURO AI Fidelity Delta Report
> Compare: `docs/design-drafts/v2/{Landing,Login,Register}.html` vs `frontend/src/views/{landing,auth}/*.vue`
> Generated: 2026-04-19
---
## 1. LandingView
**Zip:** `docs/design-drafts/v2/Landing.html`
**Vue:** `frontend/src/views/landing/LandingView.vue`
---
### Copy / Text Deltas
| # | Zip (HTML) | Vue (SFC) | Severity | Notes |
|---|---|---|---|---|
| L-T1 | Hero eyebrow: `<span class="badge">NEW</span> 统一接入多个 AI 平台 · 零改动切换` | Hero eyebrow: `ChatGPT Plus · Claude Pro · Codex · Gemini` (plain pill, no badge) | **important** | Zip has a highlighted NEW badge + tagline; Vue shows only a product-list pill with no "NEW" call-out and no `统一接入…` text |
| L-T2 | Hero sub: `聚合成统一 API零改动接入 <span class="pill">OpenAI</span> / <span class="pill">Anthropic</span> SDK` — pill is a code-styled inline token | Vue: `聚合成统一 API零改动接入 OpenAI / Anthropic SDK` — plain text, no pill styling | **cosmetic** | Inline `<span class="pill">` with monospace border lost |
| L-T3 | Hero CTA buttons: `立即开始 →` (primary) + `查看文档` (ghost) | Hero CTA buttons: `登录 →` (primary) + `联系咨询` (ghost) | **important** | Primary button label changed from "立即开始" to "登录"; secondary changed from "查看文档" to "联系咨询". Zip routes unauthenticated users to Register first; Vue routes to Login |
| L-T4 | Hero micro-text: `无需信用卡 · 用你已有的订阅 · 5 分钟跑通` (three dot-separated items, each a `<span>`) | Hero micro-text: `已验证可用 Codex CLI · Claude Code · curl · 服务器出口新加坡` (single plain string) | **important** | Entirely different social-proof claims; zip emphasises zero-friction onboarding, Vue emphasises tech compatibility |
| L-T5 | Model-wall section kicker: `// providers` | Vue model-wall section kicker: `支持的 AI 平台` (Chinese, no `//` prefix) | **cosmetic** | Zip uses monospace `// providers` pattern; Vue switches to Chinese heading |
| L-T6 | Model-wall subtitle: `通过 OAuth 直接复用你的订阅,无需申请官方 API key` | Vue sub: `无需申请官方 API key也无需切换账号` | **cosmetic** | Minor copy rewrite; same meaning |
| L-T7 | Features section title: `付一次订阅,<br>用起一整个模型池` | Vue section title: `一套 key三件武器` | **important** | Substantially different headline; zip's "pay once" framing vs Vue's "one key, three weapons" |
| L-T8 | Features section sub: `把散落在各个平台的订阅,整合成开发者真正能用的基础设施` | Vue: *(sub entirely absent)* | **important** | Vue omits the features section subtitle entirely |
| L-T9 | Feature card 2 copy: `某个 ChatGPT Plus 触发限流,自动 failover 到下一个。重启、刷新 token 全自动。` | Vue: `某个上游触发限流 / 冷却时流量切到下一个健康账号token 刷新全自动。` | **cosmetic** | Light rewrite, same meaning |
| L-T10 | Feature bullets (all 3 cards): 3-bullet lists under a dashed-border divider | Vue: *bullets entirely absent* from all feature cards | **important** | All 9 feature bullet items (`OpenAI Responses API 兼容`, `限流/5xx 自动 failover`, etc.) are missing |
| L-T11 | Code demo section kicker: `// integration` | Vue: `快速接入` | **cosmetic** | |
| L-T12 | Dashboard section sub (long): `不像第三方 API 池子那种"扣了多少不告诉你"。你能看到每次调用:扣了哪个账号、跑了哪个模型、用了多少 tokens、花了多少钱、上游响应几秒。` | Vue: `不像第三方 API 池子那种"扣了多少不告诉你"——扣哪个账号、跑哪个模型、用了多少 tokens、上游响应几秒一目了然。` | **cosmetic** | Condensed; "花了多少钱" detail removed from Vue version |
| L-T13 | CTA banner: `把订阅变成 API — 5 分钟` + `绑定第一个账号,生成 sk- key把 base_url 指过来。就这些。` | *CTA banner entirely absent from Vue* | **important** | The mid-page conversion CTA section is completely missing from Vue |
| L-T14 | Pricing section (full 3-tier grid + `pricing-more-link`) | *Pricing section entirely absent from Vue* | **important** | Full pricing section with 3 tiers ($9.9 / $29.9 / $99), all tier copy, and "查看完整定价" link is missing |
| L-T15 | FAQ section (6 expandable `<details>` + "查看全部 10 个问题" link) | *FAQ section entirely absent from Vue* | **important** | All FAQ content missing |
| L-T16 | Footer brand tagline: `把多个 AI 订阅聚合成统一 API。让「已经付过钱」的订阅真正为你工作。` | Vue: `Self-hosted on puro.im` | **important** | Zip has Chinese product tagline; Vue shows English self-hosted note |
| L-T17 | Footer meta: `© 2026 puro.im · Built with ♥ in Shanghai` | Vue: `© 2026 puro.im · MIT License\nfork of Wei-Shaw/sub2api` | **cosmetic** | Different but both acceptable |
| L-T18 | Footer "产品" column: 文档 / 定价 / FAQ / 功能 | Vue "产品" column: 文档 / 更新日志 | **important** | Vue removes 定价/FAQ/功能 links |
| L-T19 | Footer "账户" column: 登录 / 注册 / Dashboard / 绑定订阅 | Vue footer has "联系" column (admin@puro.im / git.puro.im) instead of "账户" column | **important** | Entire "账户" column replaced with "联系" column |
| L-T20 | Footer system-status line: `all systems operational` (with green dot) | *Absent from Vue footer* | **cosmetic** | |
| L-T21 | Stat card labels (dashboard): `Requests · 24h`, `Tokens · 24h`, `Avg latency`, `Est. savings` | Vue: `今日请求`, `输入 Tokens`, `输出 Tokens`, `今日费用` | **important** | Different stat names and dimensions (4th stat is "savings" in zip vs "cost" in Vue; zip has 1 tokens stat vs Vue has 2 separate I/O token stats) |
| L-T22 | Log table columns: Time / Provider / Model / Tokens / Cost / Latency / Status | Vue: 时间 / 模型 / 上游 / 状态 / 用量 (5 cols, Chinese, Cost and Latency absent) | **important** | Zip has 7-column table with Cost + Latency; Vue drops those two columns |
---
### Structure Deltas
| # | What zip has | Vue status | Severity |
|---|---|---|---|
| L-S1 | Nav links include `#pricing` and `#faq` anchor links | Vue nav only has `#features` + `/docs` (no pricing/faq) | **important** |
| L-S2 | Hero: `<span class="hero-micro">` with 3 `<span>` children and `.dot` separators | Vue: single plain string in `.hero-micro`, no separators | **cosmetic** |
| L-S3 | Model cards: icon logo (`<div class="model-logo">` + inline SVG) + name + tag stacked vertically with green status chip | Vue: colored dot + name + meta in a row (horizontal), no status chip, no SVG logos | **important** |
| L-S4 | Code demo: single-column with TWO separate `code-frame` panels, each with traffic-light dots + tabs + `● edited 2s ago` / `zsh · puro ≈ 210ms` labels | Vue: two-column `code-demo` grid with simplified `code-block` panels (no tab row, no traffic dots) | **important** |
| L-S5 | Dashboard: browser-chrome header (`dash-head` with url bar `ai.puro.im/dashboard` + lock icon + `me@puro` label) | Vue: minimal `dash-header` with title + three dots, no URL bar | **important** |
| L-S6 | Dashboard: left sidebar (`dash-side`) with WORKSPACE and SETTINGS nav groups | Vue: sidebar entirely absent | **important** |
| L-S7 | Dashboard chart area: `chart-grid` (2fr + 1fr) with line chart SVG + donut chart SVG side-by-side | Vue: single `chart-card` with a simplified `<polyline>` chart only, no donut | **important** |
| L-S8 | Donut chart: full SVG with 4 arc segments (Claude 48% / GPT 32% / Gemini 14% / Codex 6%) + legend | Vue: absent | **important** |
| L-S9 | CTA banner section (mid-page, after dashboard) | Vue: absent | **important** |
| L-S10 | Pricing section (3-tier grid) | Vue: absent | **important** |
| L-S11 | FAQ section (`<details>` accordion, 6 items) | Vue: absent | **important** |
| L-S12 | Footer: 4-column grid (2fr brand + 3×1fr cols) with `footer-brand` description paragraph | Vue: 4-column grid present but content differs (see L-T16/T18/T19) | **cosmetic** (structure match, content differs) |
---
### Visuals / SVG
| # | Delta | Severity |
|---|---|---|
| L-V1 | Nav brand: inline SVG hexagon (`<path d="M12 2L21 7V17L12 22L3 17V7L12 2Z">` + inner fill path) | Vue: `⬢` Unicode emoji | **important** — SVG renders crisp at all sizes; emoji rendering varies by OS/font |
| L-V2 | Footer brand: same inline SVG hexagon | Vue: `⬢` emoji | **important** |
| L-V3 | Model-card logos: unique inline SVG per provider (Claude chevron, GPT circle, Codex bracket, Gemini star, "..." dots) | Vue: colored 10px `<div class="model-dot">` only | **important** |
| L-V4 | Dashboard line-chart: SVG with gradient fill area, cyan/purple/amber stroke lines, x-axis time labels (`00:00``now`) | Vue: simplified `<polyline>` without fill area or x-axis labels | **important** |
| L-V5 | Hero eyebrow: `.badge` span with cyan tinted background for "NEW" | Vue: no badge element | **important** |
| L-V6 | Pricing tier-flag chips (STARTER / ◆ 推荐 / ⚡ 限时) with color variants (`muted` / default / `amber`) | Vue: absent (no pricing section) | n/a (section missing) |
---
### Missing CSS (zip has, Vue scoped missing)
| # | Missing rule / component | Impact |
|---|---|---|
| L-C1 | `.model-logo` (icon container with border + bg), `.status-chip` (green dot + glow pulse), `.model-card.disabled` opacity | Model wall looks flat vs. designed appearance |
| L-C2 | `.hero-eyebrow .badge` (cyan tinted pill) | Missing "NEW" badge styling |
| L-C3 | `.hero-micro .dot` (4px separator dots) | Separator dots between hero micro items |
| L-C4 | `.code-tabs`, `.tab`, `.tab.active`, `.tab-dot`, `.traffic` | Full code-frame tab-bar styling missing |
| L-C5 | `.dash-head .url` (address-bar mockup with lock icon pseudo) | Dashboard browser-chrome bar |
| L-C6 | `.dash-side`, `.side-group`, `.side-label`, `.side-item`, `.side-item.active` | Sidebar nav entirely unstyled |
| L-C7 | `.chart-grid` 2:1 layout, `.chart-title .legend`, `.sw` (legend swatch) | Chart section layout and legend |
| L-C8 | `.cta-banner` and all sub-rules | Mid-page CTA banner |
| L-C9 | `.pricing-grid-landing`, `.tier-l`, `.tier-l-flag`, `.tier-l-price`, `.tier-l-credit`, `.tier-l-discount`, `.tier-l-feats`, `.pricing-more-link` | Entire pricing card system |
| L-C10 | `.faq-l` + `summary`, `::after`, `[open]` variants, `.faq-answer` | FAQ accordion |
| L-C11 | `.section-kicker` with `// ` monospace prefix convention (zip uses `letter-spacing: 0.15em`) | Vue uses 0.12em and different style |
---
### Missing Scripts / Interactivity
| # | What zip has | Vue status | Severity |
|---|---|---|
| L-I1 | Code-frame tab switching: clicking `.tab` elements switches displayed code block | Vue code demo has no tab interaction (static 2 panels) | **interactive** |
---
---
## 2. LoginView
**Zip:** `docs/design-drafts/v2/Login.html`
**Vue:** `frontend/src/views/auth/LoginView.vue`
---
### Copy / Text Deltas
| # | Zip (HTML) | Vue (SFC) | Severity | Notes |
|---|---|---|---|---|
| LN-T1 | Narrative headline: `<span class="amber">N</span> 个订阅 → <span class="cyan">1</span> 个 key` (N is amber-colored variable) | Vue: `<span class="num-5">5</span> 个订阅 → <span class="num-1">1</span> 个 key` | **important** | Zip uses abstract "N" (variable quantity); Vue hardcodes "5". This was the specific discrepancy the user noticed |
| LN-T2 | Narrative kicker: `// 你的订阅,已经付过钱了` | Vue: absent (no kicker element in narrative) | **important** | |
| LN-T3 | n-sub text: `省去切换账号的繁琐,` / `省去为多个高昂订阅重复买单。` / `PURO(纯粹)—— 让 AI 调用回归本质。` | Vue: `省去切换账号的繁琐,` / `省去为多个高昂订阅重复买单。` / `PURO纯粹—— 让 AI 调用回归本质。` (via `auth-narrative-tagline`) | **cosmetic** | Full-width vs half-width punctuation (`` vs `,`, `` vs `()`); same meaning otherwise |
| LN-T4 | Form title: `登录` (h1) + sub: `用你的 PURO AI 账户继续` | Vue: `{{ t('auth.puroLoginTitle') }}` + `{{ t('auth.puroLoginSub') }}` — actual rendered text depends on i18n key values | **important** | Need to verify i18n values match; design source has specific Chinese copy |
| LN-T5 | "Remember me" checkbox: `记住我` | Vue: absent (no remember-me UI) | **cosmetic** | |
| LN-T6 | "Forgot password" link: `忘记密码?` (always visible, inline with remember-me) | Vue: only shown `v-if="passwordResetEnabled && !backendModeEnabled"` | **cosmetic** | Conditioned; zip always shows it |
| LN-T7 | Submit button text: `登录 →` | Vue: i18n key `t('auth.signIn')` / `t('auth.signingIn')` | **cosmetic** | Likely matches; verify arrow `→` is included |
| LN-T8 | LinuxDO button: `使用 LinuxDO 登录` with custom orange gradient `.linuxdo-ico` "L" badge | Vue: delegated to `<LinuxDoOAuthSection>` component | **cosmetic** | Functionally equivalent; visual parity depends on component implementation |
| LN-T9 | Footer link: `没有账户?<a>注册</a>` | Vue: i18n `t('auth.dontHaveAccount')` + `t('auth.signUp')` | **cosmetic** | Verify i18n values |
| LN-T10 | Legal line: `登录即表示你同意 <a>服务条款</a> 与 <a>隐私政策</a>` | Vue: **absent** | **important** | No terms/privacy consent text in Vue login form |
---
### Structure Deltas
| # | What zip has | Vue status | Severity |
|---|---|---|
| LN-S1 | `route-demo` block: live routing demo panel showing `POST /v1/chat/completions`, `model: claude-sonnet-4-5`, `route → claude-pool-03`, `status 200 · 213ms · 42 tok` | Vue: **entirely absent** | **important** |
| LN-S2 | `n-bottom` bar: provider list (`Claude · ChatGPT · Codex · Gemini`) + `live · ai.puro.im · operational` green-dot status | Vue: replaced by simpler `auth-narrative-foot` = `Claude · ChatGPT · Codex · Gemini` only; no live status | **important** |
| LN-S3 | `back-home` link (`← 返回首页`) absolute-positioned top-right of form panel | Vue: absent | **cosmetic** |
| LN-S4 | Password field: eye toggle with two SVG states (open / closed-with-slash), both embedded inline | Vue: `<Icon name="eye">` / `<Icon name="eyeOff">` (component-based) | **cosmetic** — functionally equivalent |
| LN-S5 | `remember-me` checkbox with custom styled box + check mark | Vue: absent | **cosmetic** |
| LN-S6 | Login form `autocomplete="off" novalidate` attribute | Vue: `autocomplete` per-field, no `novalidate` (uses Vue validation) | **cosmetic** |
---
### Visuals / SVG
| # | Delta | Severity |
|---|---|---|
| LN-V1 | Brand in narrative: inline SVG hexagon (same double-path as Landing) | Vue: `⬢` emoji | **important** |
| LN-V2 | `route-demo` styling: pill-inline badges with cyan/amber/green border-tinted backgrounds, green dot-pulse status | Vue: absent (whole block missing) | n/a (structure missing) |
| LN-V3 | `n-bottom .live .dot` — 5px green dot with `box-shadow` glow | Vue: absent | **important** |
| LN-V4 | Narrative background: `narrative::before` pseudo with dual radial-gradient overlay (cyan + purple) | Vue: handled by `AuthLayout` — parity depends on that component | unknown — needs AuthLayout check |
---
### Missing CSS (zip has, Vue scoped missing)
| # | Missing rule | Impact |
|---|---|---|
| LN-C1 | `.route-demo` and all its `.row`, `.k`, `.v`, `.pill-inline` variants | Route demo panel |
| LN-C2 | `.n-bottom` and `.n-bottom .live`, `.n-bottom .sep` | Bottom status bar |
| LN-C3 | `.n-kicker` | Kicker line above headline |
| LN-C4 | `.check` custom checkbox (`.box`, `:checked ~ .box::after`) | Remember-me checkbox |
| LN-C5 | `.legal` legal notice line (monospace, dashed link underlines) | Terms/privacy link |
| LN-C6 | `.back-home` | Return-to-home link |
| LN-C7 | `@media (max-width: 900px)` hides `.route-demo` and `.n-bottom` | Responsive rule |
---
### Missing Scripts / Interactivity
| # | Zip has | Vue status | Severity |
|---|---|---|
| LN-I1 | Password eye-toggle: vanilla JS swaps `pw.type` + toggles two SVG icons by `display` | Vue: reactive `showPassword` ref + Icon component. Functionally equivalent | **none** — Vue solution is better |
| LN-I2 | Login submit: loading spinner class, success state (`✓ 登录成功` label text change + green background), redirect to Dashboard.html | Vue: `isLoading` spinner, redirect via `router.push('/dashboard')`; no "✓ 登录成功" button text mutation | **cosmetic** — success toast used instead |
| LN-I3 | Basic non-empty check only (`if (!form.email.value || !form.password.value)`) | Vue: full regex email validation + min-length password validation + Turnstile + 2FA flow | **none** — Vue is more complete |
---
---
## 3. RegisterView
**Zip:** `docs/design-drafts/v2/Register.html`
**Vue:** `frontend/src/views/auth/RegisterView.vue`
---
### Copy / Text Deltas
| # | Zip (HTML) | Vue (SFC) | Severity | Notes |
|---|---|---|---|---|
| R-T1 | Narrative kicker: `// 5 分钟开始用` | Vue: absent (no kicker) | **important** | |
| R-T2 | Narrative headline: `<span class="amber">N</span> 个订阅 → <span class="cyan">1</span> 个 key` | Vue: `<span class="num-5">5</span> 个订阅 → <span class="num-1">1</span> 个 key` | **important** | Same as Login: "N" vs hardcoded "5" |
| R-T3 | Form title: `创建账户` (h1) + sub: `注册即送 <b style="color:var(--cyan)">$5</b> 测试积分` | Vue: `{{ t('auth.puroRegisterTitle') }}` + `{{ t('auth.puroRegisterSub') }}` | **important** | The "$5 bonus credit" hook in the sub-title is a key conversion element; Vue moves it to i18n |
| R-T4 | Password placeholder: `至少 8 位,含字母与数字` | Vue: `{{ t('auth.createPasswordPlaceholder') }}` | **cosmetic** | Verify i18n value matches |
| R-T5 | `bonus-note` block: green-bordered callout `+$5 完成注册即送 $5 测试积分 —— 够你跑几万次 Claude 请求。` | Vue: **absent** | **important** | High-conversion element entirely missing |
| R-T6 | Steps panel title: `// 下一步` with 3 numbered onboarding steps (创建账户 → 绑定订阅 → 生成 key) | Vue: **absent** | **important** | The onboarding journey explainer is missing |
| R-T7 | `n-bottom` provider list + `live · ai.puro.im · operational` | Vue: `auth-narrative-foot` = `Claude · ChatGPT · Codex · Gemini` only | **important** | Live status indicator missing |
| R-T8 | `back-home` link: `← 返回首页` | Vue: absent | **cosmetic** | |
| R-T9 | Footer: `已有账户?<a>登录</a>` | Vue: i18n `t('auth.alreadyHaveAccount')` + `t('auth.signIn')` | **cosmetic** | Verify i18n values |
---
### Structure Deltas
| # | What zip has | Vue status | Severity |
|---|---|---|
| R-S1 | Onboarding `.steps` panel (3-step card in the narrative: 1. Create account, 2. Bind subscription, 3. Generate key) | Vue: **entirely absent** | **important** |
| R-S2 | Email field: inline validation green checkmark (`valid-ico` SVG) appears when email format is valid | Vue: shows `input-error-text` below field on error; no inline success icon on valid state during typing | **cosmetic** |
| R-S3 | Password field: 4-bar strength meter (`pw-strength` div) + text label (`// strength · 弱/中/强/极强`) | Vue: no strength meter; only a static `input-hint` paragraph | **important** |
| R-S4 | Confirm-password field with: `valid-ico` checkmark + `match-hint` (`// matched` / `// passwords do not match`) | Vue: no confirm-password field at all | **important** |
| R-S5 | Terms checkbox (`我已阅读并同意 服务条款 与 隐私政策`) — submit button disabled until checked | Vue: no terms checkbox | **important** |
| R-S6 | `bonus-note` callout block | Vue: absent | **important** |
| R-S7 | Password confirm field activates submit only when: email valid + score ≥ 2 + passwords match + terms checked | Vue: password min-length 6, no confirm field, no terms gate | **important** |
| R-S8 | Vue-only: invitation code field (conditional on `invitationCodeEnabled`) | Zip: absent | n/a (Vue enhancement) |
| R-S9 | Vue-only: promo code field (conditional on `promoCodeEnabled`) | Zip: absent | n/a (Vue enhancement) |
| R-S10 | Vue-only: Turnstile CAPTCHA widget | Zip: absent | n/a (Vue enhancement) |
---
### Visuals / SVG
| # | Delta | Severity |
|---|---|---|
| R-V1 | Brand in narrative: inline SVG hexagon | Vue: `⬢` emoji | **important** |
| R-V2 | Steps panel: numbered circles (`step-num`) with cyan border and active fill | Vue: absent | **important** |
| R-V3 | `bonus-note` callout: green border `rgba(52,211,153,0.2)` + `+$5` chip in green background | Vue: absent | **important** |
| R-V4 | Password strength bars: 4 `<span class="bar">` elements that fill red/amber/cyan/green based on `data-score` | Vue: absent | **important** |
| R-V5 | Match-hint monospace text (`// matched` in green / `// passwords do not match` in red) | Vue: absent | **important** |
| R-V6 | `valid-ico` green SVG checkmark inside input-wrap when field is valid | Vue: absent | **cosmetic** |
---
### Missing CSS (zip has, Vue scoped missing)
| # | Missing rule | Impact |
|---|---|---|
| R-C1 | `.steps`, `.steps-title`, `.step`, `.step-num`, `.step.active .step-num`, `.step-text .k` | Onboarding steps panel |
| R-C2 | `.pw-strength[data-score]` + `.bar` + 4 score-tinted variants | Password strength meter |
| R-C3 | `.pw-hint[data-score]` + `.val` color variants | Strength label |
| R-C4 | `.match-hint`, `.match-hint.mismatch`, `.match-hint.ok` | Confirm-password match feedback |
| R-C5 | `.valid-ico` + `.input-wrap input.ok ~ .valid-ico` | Inline valid checkmark |
| R-C6 | `.bonus-note` + `.bonus-note .emoji` | Registration bonus callout |
| R-C7 | `.n-bottom` + live-dot styles (same as Login) | Bottom status bar |
---
### Missing Scripts / Interactivity
| # | Zip has | Vue status | Severity |
|---|---|---|
| R-I1 | Password strength scorer (`scorePw()`) — counts: ≥8 chars, mixed case, digit, special/long; maps score 0-4 to `['—','弱','中','强','极强']` | Vue: no strength meter, only min-length check | **interactive** |
| R-I2 | Real-time confirm-password match checker with `// matched` / `// passwords do not match` feedback | Vue: no confirm-password field | **interactive** |
| R-I3 | Email inline validation (adds `.ok` class → shows green checkmark) | Vue: error shown on submit, not live | **interactive** |
| R-I4 | Submit button gated on: email `.ok` + `score >= 2` + passwords match + terms checkbox checked | Vue: submit gated only on loading + optional Turnstile | **interactive** |
| R-I5 | Success animation: button text changes to `✓ 注册成功,正在跳转...` + green background, then redirects | Vue: toast notification + router.push — no button animation | **cosmetic** |
---
---
## 4. DocsView
**Zip:** `docs/design-drafts/v2/Docs.html`
**Vue:** `frontend/src/views/docs/DocsView.vue`
---
### Copy / Text Deltas
| # | Zip (HTML) | Vue (SFC) | Severity | Notes |
|---|---|---|---|---|
| D-T1 | Page title / h1: `快速开始` + lede: `PURO AI 提供一个统一的 OpenAI 兼容端点 —— 你已有的 SDK 代码只需要改 base_url 和 api_key 两行…整个过程通常不超过 5 分钟。` | Vue h1: `快速接入 PURO AI` + subtitle: `三步走:拿 key → 配 base_url → 发请求` | **important** | Zip's lede is a full paragraph explaining the product value and 5-minute setup claim; Vue's subtitle is a terse 3-step summary. Different framing. |
| D-T2 | Step-card labels: `STEP 01 / 绑定订阅`, `STEP 02 / 创建 API Key`, `STEP 03 / 切换 base_url` with description paragraphs | Vue: no step-card grid at all | **important** | The `quick-grid` 3-card visual summary is entirely absent from Vue |
| D-T3 | Section "① 绑定你的订阅": full paragraph about Dashboard → OAuth flow + KMS callout `凭证通过 AES-256 加密存储在隔离的 KMS 中…` | Vue: Section "1. 获取 API key": `当前 PURO AI 不开放自助注册付费。联系管理员获取admin@puro.im` + note `未来通过 iShare 入口开放订阅购买。` | **important** | Completely different content: zip describes the self-serve OAuth flow; Vue describes an invite-only alpha state. Vue reflects current operational reality; zip is the target product state. |
| D-T4 | Section "② 创建 API Key": instructions for `Dashboard → API Keys → 创建 Key`, advice to create per-client keys for safe revocation | Vue: no dedicated "create API key" section | **important** | Zip's key-management guidance (per-client keys, revoke without affecting others) is absent from Vue |
| D-T5 | Section "③ 发送第一个请求": prose introducing OpenAI + Anthropic format support, code-panel with Python/Node/cURL/Anthropic SDK tabs | Vue: "2. Codex CLI 接入", "3. Claude Code 接入", "4. curl 直连测试" — three separate sections each with a plain `<pre>` block | **important** | Zip organises code samples under one tabbed panel; Vue splits them into three separate sections with different tool focus (Codex CLI is a Vue-only section) |
| D-T6 | Codex CLI section: **absent from zip** | Vue: Section "2. Codex CLI 接入" with `~/.codex/config.toml` and `~/.codex/auth.json` config samples | n/a (Vue enhancement) | Vue-only section targeting Codex CLI users; not in zip |
| D-T7 | Models table: `claude-sonnet-4-5`, `claude-opus-4`, `claude-haiku-4-5`, `gpt-5`, `gpt-5-codex`, `gemini-2.5-pro`, `gemini-2.5-flash` with PROVIDER / 池 / 上下文 / 状态 columns | Vue model-list: `gpt-5.4`, `gpt-5.4-codex`, `claude-opus-4-7`, `claude-sonnet-4-6`, `gemini-2.5-pro`, `gemini-2.5-flash` (plain `<ul>`) | **important** | Model names differ (e.g. `claude-sonnet-4-5` vs `claude-sonnet-4-6`; `gpt-5` vs `gpt-5.4`); zip has `claude-haiku-4-5` which Vue omits; zip has rich table structure vs Vue's plain list |
| D-T8 | Section "支持的 base_url": three URLs (`/v1`, `/anthropic`, `/google`) with explanations + amber callout about unified key across all formats | Vue: no dedicated base_url section; curl examples hard-code `/responses` and `/v1/messages` endpoints | **important** | The `/anthropic` and `/google` base_url variants and the "one key for all formats" callout are absent from Vue |
| D-T9 | Section "下一步": integration links for Claude Code, Cursor, Cline/Roo Code, Continue | Vue: no "next steps" section | **important** | Onward-journey links that guide users to integration docs are absent |
| D-T10 | Breadcrumb trail: `Docs / Getting Started / 快速开始` (monospace, with cyan `.current` span) | Vue: absent | **cosmetic** | |
| D-T11 | Nav "active" link: `文档` has `.active` class in zip nav | Vue nav: no `.active` state on current-page link | **cosmetic** | |
| D-T12 | Nav links: 产品 / 定价 / 文档 / 设计系统 | Vue nav links: 首页 / `#codex` / `#claude-code` / `#curl` (in-page anchors) | **important** | Zip nav is a proper site-level navigation; Vue nav links to in-page anchors only and removes Pricing + Design System entries |
| D-T13 | Nav CTA: `Dashboard` (ghost) + `开始使用` (primary) | Vue nav CTA: `登录 →` (primary only, no ghost button) | **important** | Zip has two CTA buttons (authenticated + unauthenticated states); Vue has one |
| D-T14 | Left sidebar brand-line: `// docs · v1` (monospace kicker) | Vue: no sidebar at all | **important** | The `// docs · v1` kicker text is a brand-pattern element; entire sidebar is missing |
| D-T15 | Right TOC label: `On this page` (monospace uppercase) with 6 anchor links | Vue: no right-column TOC | **important** | |
| D-T16 | Page-footer nav links: `← 上一页 / 产品概念` and `下一页 → / 绑定你的订阅` | Vue: no page-footer nav | **important** | Prev/next doc navigation absent |
| D-T17 | Section "6. 问题反馈" + callout with admin@puro.im | Vue has equivalent "6. 问题反馈" section (same email) | — | This matches; no delta |
| D-T18 | Callout (cyan) security note with SVG lock icon: `凭证通过 AES-256 加密存储在隔离的 KMS 中…` | Vue callout: plain `<a>` email link inside div, no icon | **important** | Zip callout has inline SVG icon + richer copy; Vue callout is a minimal email link only |
| D-T19 | Callout (amber, warning) key portability note: `一个 sk-puro-* 可以同时用于三种 base_url…` | Vue: no amber/warning callout variant | **important** | Amber callout variant used in zip for advisory messages is entirely absent from Vue |
---
### Structure Deltas
| # | What zip has | Vue status | Severity |
|---|---|---|---|
| D-S1 | 3-column grid layout: `docs-layout` (240px left nav + 1fr main + 220px right TOC) | Vue: single-column `.container` with centred `.docs-body`; no sidebar, no TOC column | **important** |
| D-S2 | Sticky left sidebar (`docs-nav`) with `brand-line`, search `<input>`, 4 nav-section groups (Getting Started / API Reference / Integrations / Advanced) | Vue: absent | **important** |
| D-S3 | Sticky right TOC (`docs-toc`) with `On this page` label + 6 anchor links (some `.sub` indented) | Vue: absent | **important** |
| D-S4 | Breadcrumb bar (`docs-crumbs`) above h1 | Vue: absent | **cosmetic** |
| D-S5 | Quick-start step-card grid (`quick-grid`) — 3 cards with monospace STEP 01/02/03 labels | Vue: absent | **important** |
| D-S6 | Code panel (`code-panel`) with `panel-tabs` bar (Python / Node.js / cURL / Anthropic SDK tabs) + `copy-code` button | Vue: plain `<pre class="mono">` blocks with no chrome, no tab switching, no copy button | **important** |
| D-S7 | Models table (`models-table`) — `<table>` with thead/tbody, provider badge spans (`.provider.claude/gpt/gemini` + `.dot`), status badges (`.badge.green/.amber`) | Vue: `<ul class="model-list">` plain list | **important** |
| D-S8 | Two distinct callout variants: default cyan and `.amber` warning, each with inline SVG icon (`<svg>` lock / triangle) | Vue: single callout style with no icon and no amber variant | **important** |
| D-S9 | Page-footer prev/next nav (`page-foot` with two `foot-link` cards) | Vue: absent | **important** |
| D-S10 | Nav `docs-top` with `backdrop-filter: blur(12px)` sticky bar + brand SVG hex | Vue: plain `.nav` (no `docs-top` class, no sticky backdrop, `⬢` emoji brand) | **important** |
| D-S11 | Left nav search input (`nav-search` with SVG magnifier pseudo-element) | Vue: absent | **cosmetic** |
| D-S12 | `h2` headings with `::before` 3px cyan vertical bar accent | Vue `h2`: `border-bottom: 1px solid var(--border)` only — no left-bar accent | **important** |
| D-S13 | `<section id="models">` — Vue-only "5. 支持的模型" section maps to zip's models table | Equivalent content present but rendered as list vs table (see D-T7) | — |
| D-S14 | Vue-only: `docs-hero` centered section above `docs-body` | Zip: no separate hero section; content starts directly with breadcrumbs + h1 inside `docs-body` | n/a (Vue adds hero) |
---
### Visuals / SVG
| # | Delta | Severity |
|---|---|---|
| D-V1 | Nav brand: inline SVG hexagon (same double-path as Landing/Login/Register: outer stroke + inner filled path) | Vue: `⬢` Unicode emoji | **important** |
| D-V2 | Left nav SVG search icon (inline `url("data:image/svg+xml...")` magnifier in `::before` pseudo) | Vue: no sidebar/search | n/a (structure missing) |
| D-V3 | `h2::before` pseudo-element: 3px × 22px cyan vertical accent bar | Vue `h2`: plain bottom border only | **important** |
| D-V4 | Code syntax token spans: `.com` (grey italic comments), `.kw` (pink keywords), `.str` (green strings), `.fn` (amber functions), `.prop` (blue properties), `.num` (orange numbers) | Vue pre blocks: `.str` (cyan), `.kw` (amber), `.cm` (grey) — only 3 token types, different colour mapping | **cosmetic** |
| D-V5 | Models table: `.provider` span with 6px `.dot` circle (colour per provider) + "Claude / ChatGPT / Gemini" text | Vue model list: no provider badge, provider shown as inline text only | **important** |
| D-V6 | Models table: `.badge.green` ("OK") and `.badge.amber` ("BETA") status chips | Vue: no status badges | **important** |
| D-V7 | Callout icons: inline SVG lock (14×14) for cyan callout; inline SVG triangle-warning for amber callout | Vue: no icon in callouts | **important** |
| D-V8 | Quick-grid cards: `::before` / hover `translateY(-2px)` lift animation | Vue: no step cards | n/a (structure missing) |
| D-V9 | `docs-nav-item.active`: cyan text + `rgba(34,211,238,0.06)` tinted background | Vue: no sidebar nav | n/a (structure missing) |
| D-V10 | `docs-toc a.active`: cyan text + left `2px solid var(--cyan)` border + `rgba(34,211,238,0.03)` bg | Vue: no TOC | n/a (structure missing) |
---
### Missing CSS (zip has, Vue scoped missing)
| # | Missing rule / component | Impact |
|---|---|---|
| D-C1 | `.docs-layout` 3-column grid, `.docs-nav`, `.docs-nav .brand-line`, `.docs-nav-section`, `.docs-nav-label`, `.docs-nav-item`, `.docs-nav-item.active` | Entire left sidebar nav system |
| D-C2 | `.docs-nav .nav-search` + `input` + `::before` SVG pseudo | Sidebar search bar |
| D-C3 | `.docs-toc`, `.docs-toc-label`, `.docs-toc a`, `.docs-toc a.active`, `.docs-toc a.sub` | Right-column TOC |
| D-C4 | `.docs-crumbs`, `.docs-crumbs .sep`, `.docs-crumbs .current` | Breadcrumb bar |
| D-C5 | `.docs-top` (sticky backdrop-blur nav variant) | Docs-specific nav bar |
| D-C6 | `.docs-body h2::before` (3px cyan left-bar accent pseudo-element) | h2 section accent bar; Vue uses bottom-border instead |
| D-C7 | `.code-panel`, `.code-panel .panel-tabs`, `.tabs-inner button`, `.tabs-inner button.active`, `.copy-code`, `.copy-code:hover` | Tabbed code panel chrome |
| D-C8 | `.code-panel pre .com`, `.kw`, `.str`, `.fn`, `.prop`, `.num` (6 token colour rules) | Full syntax highlighting palette (Vue has only 3 token types) |
| D-C9 | `.quick-grid`, `.quick-card`, `.quick-card:hover`, `.quick-card .num`, `.quick-card h4`, `.quick-card p` | Step-card quick-start grid |
| D-C10 | `.models-table`, `.models-table th`, `.models-table td`, `.models-table tr:hover`, `.models-table .mono` | Styled models table |
| D-C11 | `.callout .icon` (flex + cyan colour), `.callout.amber`, `.callout.amber .icon` | Callout icon + amber variant |
| D-C12 | `.docs-body h2` flex + `gap: 12px` + `align-items: center` | h2 layout for left-bar + text alignment |
| D-C13 | `.page-foot`, `.foot-link`, `.foot-link:hover`, `.foot-link .dir`, `.foot-link .title`, `.foot-link.next` | Prev/next page footer nav |
| D-C14 | `.tabs`, `.tab`, `.tab:hover`, `.tab.active` (standalone tab-bar component) | Tab bar used in docs layout |
---
### Missing Scripts / Interactivity
| # | What zip has | Vue status | Severity |
|---|---|---|
| D-I1 | Code-panel tab switching: clicking a `button` inside `.tabs-inner` shows/hides the corresponding `<pre>` block and toggles `.active` on the tab | Vue: all code blocks are always visible in separate `<section>` elements; no tab switching | **interactive** |
| D-I2 | Copy-to-clipboard: clicking `.copy-code` copies the current tab's `<pre>` text content, momentarily changes label to `✓ 복사됨` (or similar confirmation) | Vue: no copy button on any code block | **interactive** |
| D-I3 | TOC active-link tracking: scrolling the page updates which `.docs-toc a` has `.active` class (IntersectionObserver or scroll listener implied) | Vue: no TOC | n/a (structure missing) |
| D-I4 | Sidebar nav active-item tracking: clicked nav item gets `.active` class with cyan highlight | Vue: no sidebar | n/a (structure missing) |
---
### Recommended Fix List
| Priority | ID | Fix | Notes |
|---|---|---|---|
| 1 | D-S1 / D-S2 / D-S3 | Implement 3-column `docs-layout` with sticky left sidebar and right TOC | Structural foundation; all other doc-nav deltas depend on this. Estimate: 34h |
| 2 | D-S6 / D-I1 / D-I2 | Replace plain `<pre>` blocks with `.code-panel` component: tab bar (Python/Node/cURL/Anthropic SDK), copy-to-clipboard button, traffic-light dots | Highest developer-credibility element on the page. Port from zip JS or use Vue `ref`+`v-show`. Estimate: 2h |
| 3 | D-S7 / D-V5 / D-V6 | Replace `<ul class="model-list">` with `<table class="models-table">` including provider badge spans and OK/BETA status chips | Table format communicates provider, pool, context and status at a glance. Estimate: 1h |
| 4 | D-V1 / D-V3 | Replace `⬢` emoji brand with inline SVG hexagon (same as Landing fix); add `h2::before` cyan accent bar via CSS | Both are cosmetic but high-frequency — visible on every section heading. Estimate: 0.5h |
| 5 | D-T3 / D-T8 | Rewrite Section 1 to reflect OAuth subscription-binding flow (once feature exists); add `支持的 base_url` section with three endpoint variants and amber "one key for all formats" callout | Content alignment with zip product vision. May be deferred until backend supports self-serve OAuth. Estimate: 1h when ready |
| 6 | D-T9 / D-S9 | Add "下一步" integration-links section + `page-foot` prev/next navigation | Keeps users moving through the docs funnel. Estimate: 0.5h |
| 7 | D-S5 / D-C9 | Add `quick-grid` three-step card summary below the lede | Visual orientation aid above the long-form content. Estimate: 0.5h |
| 8 | D-V7 / D-C11 | Add SVG icon support to callout component (lock icon for info, triangle for amber/warning), add `.callout.amber` variant | Required to port the base_url portability warning. Estimate: 0.5h |
---
## Summary
### Total Deltas Found
| Category | Important | Cosmetic | Interactive |
|---|---|---|---|
| LandingView | 15 | 7 | 1 |
| LoginView | 5 | 9 | 0 (Vue is better) |
| RegisterView | 9 | 6 | 4 |
| DocsView | 16 | 3 | 2 |
| **Total** | **45** | **25** | **7** |
**Grand total: 77 deltas** (45 important + 25 cosmetic + 7 interactive)
---
### Top 10 Most Impactful User-Visible Deltas
1. **L-S9 / L-S10 / L-S11 — Landing: CTA banner + Pricing section + FAQ entirely missing**
`LandingView.vue` — These three sections are the primary conversion funnel below the fold. The design shows a compelling mid-page CTA (`把订阅变成 API — 5 分钟`), a full 3-tier pricing grid, and 6 FAQ items. All are absent. Without them, the landing page ends abruptly after the dashboard mockup.
2. **LN-T1 / R-T2 — Login + Register narrative: "N" hardcoded as "5"**
`LoginView.vue` lines 8-9, `RegisterView.vue` lines 8-9 — Zip uses abstract variable `N` (amber) to convey "however many subscriptions you have". Vue hardcodes `5`, which is factually wrong for users with 14 or more than 5 subscriptions.
3. **L-S6 / L-S7 — Dashboard mockup: no sidebar, no donut chart**
`LandingView.vue` — The zip's dashboard mockup has a sidebar nav (7 menu items) and a 2-panel chart area (line chart + model-distribution donut). Vue shows only a line chart and no sidebar. This is visible in the hero social-proof section used to sell the product.
4. **R-S3 / R-S4 / R-S5 — Register: no password strength meter, no confirm-password, no terms checkbox**
`RegisterView.vue` — Three mutually reinforcing UX elements from the zip are absent. The strength meter educates users; the confirm field prevents typos; the terms gate is a legal/trust signal. Combined, their absence degrades register-page quality significantly.
5. **R-T5 / R-S6 — Register: `+$5 bonus-note` callout missing**
`RegisterView.vue` — The green-bordered "完成注册即送 $5 测试积分 —— 够你跑几万次 Claude 请求" callout is a direct conversion driver. It's visible below the submit button in the zip; entirely absent in Vue.
6. **R-S1 — Register: onboarding steps panel missing**
`RegisterView.vue` — The narrative left-panel in zip shows a 3-step numbered checklist (create account → bind subscription → generate key). This explains what happens *after* registration and reduces drop-off. Vue shows a generic headline only.
7. **L-V1 / LN-V1 / R-V1 — SVG hexagon logo replaced by ⬢ emoji everywhere**
`LandingView.vue`, `LoginView.vue`, `RegisterView.vue` — The double-path SVG hex (`stroke` outline + inner `fill`) renders as a crisp cyan icon. The `⬢` Unicode character renders inconsistently across macOS/Windows/mobile and lacks the inner fill detail. Affects brand recognition.
8. **L-S3 / L-V3 — Model wall: SVG logos replaced by color dots**
`LandingView.vue` — Each model card in the zip has a distinct inline SVG icon (Claude chevron, GPT circle-crosshair, Codex bracket, Gemini star, dots). Vue renders only 10px color dots. On a section designed to communicate provider breadth, icon identity matters.
9. **LN-S1 — Login: route-demo panel entirely absent**
`LoginView.vue` — The live-routing demonstration block (`POST /v1/chat/completions → claude-pool-03 → 200 OK · 213ms`) is the most concrete product proof-point on the login page. It communicates technical credibility to developer users seeing the login page for the first time. Entirely missing from Vue.
10. **L-T7 / L-T8 / L-T10 — Landing features: different headline, no sub, no bullets**
`LandingView.vue` — Section headline changed from `付一次订阅,用起一整个模型池` to `一套 key三件武器`. The subtitle and all 9 feature bullet items (API compatibility claims, failover details, export options) are absent. Together these make the features section significantly less informative.
---
### Estimated Work
| Scope | Est. hours |
|---|---|
| Fix "N vs 5" in Login + Register narrative (L-T1 / R-T2) | 0.25h |
| Restore SVG hexagon logo across all 3 views | 0.5h |
| Restore Landing: CTA banner + Pricing section + FAQ | 46h |
| Restore Landing: model-card SVG logos + status chips | 1.5h |
| Restore Landing: code-frame tabs + traffic lights | 1h |
| Restore Landing: dashboard sidebar + donut chart | 2h |
| Restore Login: route-demo panel + n-bottom status bar | 1.5h |
| Restore Login: remember-me checkbox + legal notice | 0.5h |
| Restore Register: strength meter + confirm field + terms checkbox | 2h |
| Restore Register: steps panel + bonus-note callout | 1h |
| CSS parity (Landing/Login/Register) | 23h |
| Docs: 3-column layout + sticky sidebar + right TOC | 34h |
| Docs: tabbed code-panel + copy-to-clipboard | 2h |
| Docs: models table with provider/status badges | 1h |
| Docs: SVG hex + h2 accent bar + callout icon/amber variant | 1h |
| Docs: base_url section + page-footer nav + quick-grid | 1h |
| **Total (all important + interactive deltas)** | **~2530h** |
| **Top 5 only (Landing CTA/pricing/FAQ + Docs layout + code-panel)** | **~1214h** |