64 Commits

Author SHA1 Message Date
phamnazage-jpg
13b88ba2e7 debug(gateway): add log to verify key admin_status at gateway
Some checks are pending
CI / Build & Test (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Security Scan (push) Waiting to run
CI / Docker Build (push) Waiting to run
CI / Release (push) Blocked by required conditions
2026-06-07 14:49:52 +08:00
phamnazage-jpg
37694f993f fix(gateway): pass sqlite DSN to NewAPIHandlerWithAuth so gateway can open DB for key auth
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-07 14:42:46 +08:00
phamnazage-jpg
6d6f950382 fix(gateway): add SubscriptionUserID to proxy chat request for managed key resolution
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-07 14:16:44 +08:00
phamnazage-jpg
c86c8a17ca feat(v3): add CRM gateway /v1/chat/completions with key auth + governance check
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- POST /v1/chat/completions public route on CRM (not host pass-through)
- Bearer token → sha256 fingerprint → ListByFingerprint → governance check
- paused → 403 forbidden, retired/deleted → 403
- ProxyRouteChatCompletions to upstream
- NewAPIHandler/NewAPIHandlerWithAuth: optional dsn param for gateway SQLite access
- ListByFingerprint in user_keys_repo
2026-06-07 12:19:24 +08:00
phamnazage-jpg
6eec70d6a3 feat(v3): close key governance with subject-scoped selector and pause/resume on real host
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
* ensureSubjectHasAccess now uses real SubjectID, not fixed 'portal-user'
* CreateUserKey/ResetUserKey metadata (masked_preview, key_fingerprint) based on actual returned key
* PauseManagedSubscriptionAccess/ResumeManagedSubscriptionAccess update host user allowed_groups
* Remote43 hot-updated with singleton CRM (secondary instance killed to avoid SQLITE_BUSY)
* Fresh JWT issued for remote43 host adapter
* Real E2E: create=201, chat-before=200, pause=200, resume=200, chat-resumed=200
* Known gap: paused chat still 200 (host auth cache delay, not CRM code)
2026-06-06 22:25:46 +08:00
phamnazage-jpg
47a67eb663 feat(vnext2): close portal key management ui on real host
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-06 10:12:13 +08:00
phamnazage-jpg
5b59ad7490 feat(vnext2): close user key self-service on real host
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-05 19:58:02 +08:00
phamnazage-jpg
596a2a110c feat(vnext2): add user key self-service skeleton
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- PORTAL_KEY_EXPERIENCE.md: review from pending to approved
- KEY_SELF_SERVICE_API.md: review from pending to approved
- 0015_user_keys.sql: migration for key_records table
- user_keys_repo.go + test: SQLite repo (Create/ListByOwner/GetByID/UpdateStatus)
- key_self_service.go: HTTP handlers (POST/GET /api/keys, pause/resume/delete)
- key_self_service_svc.go: action wiring (buildUserKeyHandler)
- registered in ActionSet + NewAPIHandlerWithAuth

Note: full user auth requires host+CRM co-deployment.
Current skeleton accepts Bearer token for testing.
2026-06-05 11:45:17 +08:00
phamnazage-jpg
53edcd86ac docs: update EXECUTION_BOARD + VNEXT_COMPLETION_CHECKLIST for vNext.1 closure
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- EXECUTION_BOARD: record vNext.1 release gate completion, remote43 binary swap, fresh 3-layer acceptance status
- VNEXT_COMPLETION_CHECKLIST: upgrade to 'conditionally complete (vNext.1)', update all checklists
- add vnext_fresh_acceptance.py: standalone fresh 3-layer acceptance probe script
2026-06-05 11:39:46 +08:00
phamnazage-jpg
492f33a129 feat(vnext): complete vNext.1 release gate — default chain admission, idempotent init, user key skeleton
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- DEFAULT_CHAIN_ADMISSION.md: reviewed and approved, real artifact refs added
- DEFAULT_DATA_IDEMPOTENT_RELEASE_GATE.md: reviewed and approved
- scripts/setup_default_data.sh: idempotent init with --dry-run/--apply/artifact
- scripts/test/test_default_data.sh: 4 test cases all pass
- scripts/acceptance/verify_user_key_self_service.sh: Phase 0 skeleton
- .gitignore: add generated artifact directories
2026-06-05 11:07:50 +08:00
phamnazage-jpg
77b7f7f660 feat: harden runtime import and frontend verification workflows
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-04 20:02:36 +08:00
phamnazage-jpg
7ce72cbc35 docs: sync truth docs, frontend audits, and runbooks 2026-06-04 20:00:03 +08:00
phamnazage-jpg
4b743848bc refactor(portal): merge register + login into single auth entry
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- Two separate cards (register + login) -> single unified card
- handleRegister + handleLogin -> single handleAuth that tries login first,
  falls back to register if login fails (new user detection)
- Single email/password input, single button, single status display
- Enter key submits on both fields
- File size 57873 -> 51329 chars (-11%)

Test: test_tksea_portal_assets.sh PASS, verify_frontend_smoke.sh PASS,
      verify_quality_gates.sh PASS (gofmt+vet+cov+integration)
2026-06-04 13:52:18 +08:00
phamnazage-jpg
2b5607285f docs(test): add 2026-06-04 testing pitfalls to checklist + fix key confusion in acceptance script
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
Key changes:

1. scripts/acceptance/import_remote43_provider.sh:690/695
   - Fixed  ->  for gateway direct probe
   - Added REDLINE comments explaining why sub_key is correct

2. docs/REAL_HOST_ACCEPTANCE_CHECKLIST.md: §9
   - 4 new pitfalls from 2026-06-04 real testing:
     - Gateway probe key confusion ( vs )
     - Hermes session key redaction (must get raw key from PG)
     - Account upstream key update method (PUT with type+key, not credentials)
     - Hermes redaction destroys shell variables in .sh files

3. docs/SOURCE_OF_TRUTH.md: evidence interpretation
   - Added rule #5: session env keys are redacted, must use PG raw values
2026-06-04 13:45:29 +08:00
Hermes
62b3c657a9 fix(portal): restore missing inputs in providers.html (revert buggy reorder)
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
The reorder_hints.py script incorrectly removed several <input> elements
when moving .hint spans before inputs. This commit restores the file to
the correct state from commit 56474264, preserving all inputs while
keeping the hints in their proper places.

Fixes: admin-username input missing, several other inputs corrupted
2026-06-03 21:02:50 +08:00
Hermes Agent
23fd8db77d refactor(portal): move .hint info-banner ABOVE its <input> + upgrade to teal-accented banner style
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
Two-part UX upgrade:

1. CSS — upgrade .hint from a generic "card with slate background" to a
   proper info-banner:
   - background: var(--color-primary-soft) (translucent teal 12%) instead
     of var(--bg-elev-2) (slate card) — visually distinct from any
     <input> card, so it can never be confused with one
   - border-left: 2px solid var(--color-primary) — clear "this is a hint"
     teal accent
   - padding: 8px 12px 8px 14px (smaller, lighter)
   - font-size: 12.5px (slightly larger for readability)
   - margin: 4px 0 8px 0 (sits between field label and input)
   - .hint code { monospace, teal-300, teal-tinted background } for inline
     <code> tokens
   - .hint strong { text-default color } for emphasis

   Also: label > input/select/textarea forced to display:block width:100%
   margin-top:6px (after the hint, hint + input collapse to margin-top:0)

2. HTML — reorder 11 labels across providers.html (7) and
   admin-batch-import.html (4) so the .hint span sits BEFORE the
   <input>/<select>/<textarea> it describes. Datalist stays adjacent to its
   owning input.

   Pattern before: <label>Field
  <input>
  <span class="hint">desc</span>
</label>
   Pattern after:  <label>Field
  <span class="hint">desc</span>
  <input>
</label>

Why: Linear/Vercel canonical form pattern is label + info banner above +
clean input below. The previous "input then hint" layout was just an
artifact of how the inline-script-dedup pass emitted the fields, not a
deliberate UX choice.

Verification (chrome remote-debugging, 7 pages, all .hint elements):
  Page                                            n_hints  covered
  https://sub.tksea.top/portal/                       2        0
  https://sub.tksea.top/portal/admin/                 0        0
  https://sub.tksea.top/portal/admin/providers.html   8        0
  https://sub.tksea.top/portal/admin/accounts.html    0        0
  https://sub.tksea.top/portal/admin/logical-groups   1        0
  https://sub.tksea.top/portal/admin/route-health     0        0
  https://sub.tksea.top/portal/admin-batch-import     4        0
  Total: 7/7 pages, 0 hint covered by any input

Local tests still PASS:
  - test_tksea_portal_assets.sh
  - verify_frontend_smoke.sh
2026-06-03 20:01:44 +08:00
Hermes Agent
3e158e780b fix(portal): prevent .hint description from being covered by <input>
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
5 .hint spans (ADMIN TOKEN / PACK PATH / PROVIDER ID / SMOKE TEST MODEL /
COMMIT MESSAGE) were being visually overlapped by their sibling <input>
boxes because:
  - .hint was inline, padding 10px 12px with background+border
  - <input> was inline-block
  - label was display:block, font-size 12px
  - the inline .hint box was being squeezed into the same flow line as the
    input, so its last 8-10px were covered

Verified via getBoundingClientRect + elementFromPoint probe before fix:
  hint.top < input.bottom (5 fields) = hint overlapped by input

Fix: force .hint to display:block with margin-top:6px so it always sits
below its input as a separate block; also force label > input/select/textarea
to display:block width:100% so the form field always stretches and never
inlines with the field label text.

Verified after fix: 0 hints overlapped on providers.html (the worst case
with 8 .hint spans).

CSS-only change; no HTML edits. Affects all 8 portal pages. Smoke +
frontend assets tests still PASS.
2026-06-03 16:31:01 +08:00
Hermes Agent
86412192fd docs(weekly): record 2026-05-28~06-03 cross-project learnings + 4 skills
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
7-day window 220 commits across 3 active repos (sub2api-cn-relay-manager 115,
user-system 72, llm-intelligence 33). 4 cross-project patterns extracted into
hermes-global skills:

1. numbered-task-board — M-/H-/B- + T-Data- prefix systems
2. six-stage-pipeline-verify — schema→lib→importer→fixture→real-dry→real-upsert
3. docs-only-commit — code/docs commits never mixed
4. test-coverage-iteration-workflow — per-module 30-100 test funcs

Each skill cites the source commits / files for verifiability.
This sub2api-cn-relay-manager view focuses on what the project contributed.

Docs-only commit (skill #3 in action). No code changes.
2026-06-03 15:56:03 +08:00
Hermes Agent
d6a0261a47 docs(understand-anything): record set-and-forget fallback chain upgrade for enrich
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
§9 of codegraph-integration note now documents the 2026-06-03 15:20 upgrade:
- enrich defaults to callWithFallback() chain (current model → fallback_providers)
- skips codex_responses transport providers automatically
- resolves __default._providerModel to endpoint-served name (not user alias)
- strips <think>...</think> blocks before JSON.parse
- explicit --provider still supported (skip chain, useful for fast mode)

Verified on 5 git repos (contract management / gongju / llm-intelligence /
user-system / supply-intelligence) — 13/13 OK, 0 fallback rotation needed,
all from minimax-m3/MiniMax-M3 (current agent model).

Docs-only commit; sibling subagent's parallel code changes are NOT included.
2026-06-03 15:30:48 +08:00
phamnazage-jpg
77f40c2b69 docs(understand-anything): record 16/16 workspace batch graph refresh (67s, 0 fatal)
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-03 14:34:10 +08:00
phamnazage-jpg
c079b8ab66 docs(understand-anything): record 2026-06-03 offline graph refresh + script + skill
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-03 14:24:12 +08:00
phamnazage-jpg
d493e97402 docs(codegraph): record 16/16 workspace rollout + wrapper bugfix
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-03 13:53:07 +08:00
phamnazage-jpg
047ddca92c docs(portal): record codegraph workspace integration + OMP AGENTS.md refresh
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-03 13:29:28 +08:00
Hermes Agent
56474264d6 refactor(portal): dedup inline scripts in accounts + batch-import + providers
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
All three admin pages had two parallel inline <script> blocks (a modern S1
that used adminRuntime + a legacy S2 that was self-contained). Both had
a nested <script> text inside S1 that the browser tolerated only because
the second script re-ran any state-affecting calls. Merge into a single
inline script per page; fix the nested <script> comment.

- providers.html: 100371 -> 62761 chars (-37610, -37%)
- accounts.html:  54878 -> 33098 chars  (-21780, -40%)
- batch-import:   43861 -> 26570 chars  (-17291, -39%)

Also rename draftProviderIDInput -> providerIDInput in providers.html
(the old draft-provider-id input was removed during the earlier workflow
merge, leaving the script with a null addEventListener on draft id).

All scripts pass node --check. Both test_tksea_portal_assets.sh and
verify_frontend_smoke.sh PASS.
2026-06-03 13:14:31 +08:00
phamnazage-jpg
09f7c07de3 feat(portal): make provider/batch-import form fields self-explanatory + auto-fill
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
Problem: provider manifest form had all-empty fields with cryptic
placeholders, users had to know what model IDs to type.

Fix on /portal/admin/providers.html (Provider Manifest 草稿):
- DISPLAY NAME: datalist of common vendors (OpenAI / DeepSeek /
  硅基流动 / Moonshot / 智谱 / Anthropic / 零一万物 / MiniMax / Qwen / Baichuan / 混元)
- PLATFORM: datalist of common platforms (openai / openai-compatible /
  deepseek / anthropic / gemini / zhipu / moonshot / minimax / qwen / ...)
- SMOKE TEST MODEL: datalist of common smoke models + auto-fills with
  first model from MODELS field if user leaves it empty
- BASE URL PLACEHOLDER: datalist of common base URLs (12 presets)
- MODELS: chip-row of 11 common models (gpt-5.4, gpt-5.4-mini,
  deepseek-chat, MiniMax-M2.7-highspeed, kimi-k2.6, glm-4.6,
  claude-sonnet-4-5, gemini-2.5-pro, qwen3-coder-plus, gpt-4o, o4-mini)
  + clear button. Click chip → append to MODELS field (dedup).
- KEYS textarea: 6 rows + example placeholder (sk-example-1/2/3)

Fix on /portal/admin-batch-import.html (发起导入):
- HOST ID: datalist of common host_ids + hint about loading pack first
- ENTRIES textarea: 6 rows + multi-line hint explaining
  base_url|api_key|model1,model2 format, optional model, batch import

JS change: syncDraftHelperState() in providers.html now auto-fills
smoke_test_model with first model if user hasn't filled it yet.
Also fixed: 2 duplicate copies of syncDraftHelperState (from
earlier batch script restoration) — both now have the new logic.

Verification:
- bash scripts/test/test_tksea_portal_assets.sh → PASS
- bash scripts/test/verify_frontend_smoke.sh → PASS
- browser_console click test: gpt-5.4 + deepseek-chat + kimi-k2.6 chips
  → models='gpt-5.4,deepseek-chat,kimi-k2.6' + smoke='gpt-5.4' auto-fill ✓
- screenshot: /tmp/portal-screenshots/admin-providers-v5.png
2026-06-03 11:24:54 +08:00
phamnazage-jpg
122d6282e1 fix(portal): unify all input/select/textarea/label/button/table styles via global fallback
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
Root cause: only admin/index.html had explicit .input / .select / .label classes.
100+ inputs across logical-groups / route-health / accounts / providers /
admin-batch-import + public portal had no class → browser default styling →
页面看起来「未统一」。

Fix:
- portal.css: add global rules that auto-apply design system styling to
  any input/select/textarea/label/button/table that doesn't opt out
  via .raw-input / .field-label. The existing .input / .select /
  .label / .btn classes still win (same styles, just explicit).
- portal.js: detectInitialTheme() now respects HTML's data-theme
  attribute first (page author intent), then localStorage, then OS
  preference. This makes admin pages' explicit data-theme="dark"
  actually stick instead of being overridden.
- admin/index.html: h3 标题 8 个 article 统一用 class="card-title"
  (前 4 个 inline 15px / 后 3 个 inline 16px 已统一)
- 6 admin pages: 修复 critical HTML 结构 bug — 之前 batch 处理的
  残留让 <link> 和 <style> 嵌套在 <style>:root{} 块内,浏览器
  解析时直接忽略,导致所有 stylesheet 不加载、整个页面无样式

Verification:
- bash scripts/test/test_tksea_portal_assets.sh → PASS
- bash scripts/test/verify_frontend_smoke.sh → PASS
- 8 张 screenshot v4 在 /tmp/portal-screenshots/ (各 600KB-1.2MB)
- 浏览器实测:3 stylesheets 加载,103 个 input 全部 38px/12px 圆角输入框
  35 个 label 全部 12px uppercase slate-400
  6 个 select 全部 38px + 自定义箭头
2026-06-03 11:05:10 +08:00
phamnazage-jpg
e804a830a0 docs(portal): record 2026-06-03 frontend visual upgrade + design system runbook
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- EXECUTION_BOARD.md: new 2026-06-03 entry with full evidence trail
  (asset tests, browser smoke, screenshot list, conclusion=已闭环)
- 2026-06-03-FRONTEND-DESIGN-SYSTEM-RUNBOOK.md (new, 10KB):
  * file structure + design token quick reference
  * standard page skeleton + component API (stat-card, statusbar,
    Portal.icons, Portal.toast, Portal.copyText, Portal.theme,
    Portal.renderModernAdminNav)
  * test-contract string rules (70+ strings must remain in HTML)
  * common pitfalls (duplicate <!doctype>, duplicate const AdminCommon,
    stat-card ID drift, accidental script removal)
  * submission workflow + screenshot evidence commands
2026-06-03 09:11:18 +08:00
phamnazage-jpg
cc8fc900ca refactor(portal): migrate 8 pages to portal.css+portal.js design system
Each page now uses the new page-hero + stat-card + statusbar pattern
with the Linear/Vercel-aligned token system, while preserving all
admin-common.js nav render contract and 70+ test-contract strings.

- public portal: index.html (1816 → 1280 lines)
- admin entry: admin/index.html
- admin pages: logical-groups / route-health / accounts / providers
- batch import: admin/batch-import.html (39-line redirect to
  admin-batch-import.html for legacy URL compatibility)
- admin-batch-import.html: real legacy URL handler page

Verified:
- bash scripts/test/test_tksea_portal_assets.sh → PASS
- bash scripts/test/verify_frontend_smoke.sh → PASS (all 7 admin
  pages + public portal render with smoke-admin / Smoke Logical
  Group / Smoke Provider Account / smoke-route-primary visible)
- 8 screenshot artifacts at /tmp/portal-screenshots/ (1440×2400
  chromium headless, 269KB–1.2MB each = real content)
2026-06-03 09:11:07 +08:00
phamnazage-jpg
3a9061e11d style(portal): add design system + shared layer (portal.css/portal.js/admin-common.css shim)
- portal.css: 777-line real design system (Linear/Vercel 信息建筑派)
  * tokens: spacing 4/8/12/16/24/32/48, type 12/13/14/15/17/20/24/32/44
  * colors: ink/paper/accent/success/warn/danger × 50/100/500/900
  * teal #14b8a6 1:1 aligned with host sub2api Vue/Tailwind
  * dark-first; light override for public portal
  * components: page-hero, stat-card, card, status, pill, btn-primary,
    toast-host, empty, skeleton, drawer, tabs
- portal.js: window.Sub2ApiPortal — toast, lucide 1.75px stroke SVG
  icon registry (shield/group/activity/route/health/account/provider/
  import/check/x/alert/info/copy/edit/trash/plus/refresh/...),
  copyToClipboard, theme auto/dark/light, drawer, renderModernAdminNav
- admin-common.css: 4KB legacy shim — maps old class names
  (.topnav/.primary/.secondary/.ghost/.danger/.metric/.statusbar/.stat/
  .eyebrow/.hero-points/.page-hero__eyebrow/.shell/.fade-in/.topline/
  .chip/.tag/.mono/.meta-card/.meta-label/.status-pill/.inline-code/
  .tone-*) onto new tokens without breaking admin-common.js nav contract

Evidence:
- bash scripts/test/test_tksea_portal_assets.sh → PASS (70+ string assertions)
- bash scripts/test/verify_frontend_smoke.sh → PASS (chromium headless 7 pages)
2026-06-03 09:10:45 +08:00
phamnazage-jpg
35447be934 feat(deploy): add CRM-only online deployment to remote43
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- scripts/deploy/deploy_crm_only.sh: 单进程部署 sub2api-cn-relay-manager
  CRM 控制面到 remote43,不依赖 sub2api host / PG / Redis 容器。
  复用 scripts/deploy/remote43_patched_stack_lib.sh 的 env 渲染
  (render_remote43_crm_env),render_crm_only_bootstrap 用 $\{VAR\} 占位符 +
  sed 注入避开 set -u + unquoted-heredoc 边缘问题。
  部署前先 kill 老进程 (再 scp 二进制) 避免 ELF overwrite 失败。

- docs/DEPLOYMENT.md: 加 '在线部署节点' 段,记录 stack / 端口 / 入口 / 验证。
- docs/EXECUTION_BOARD.md: 顶部加 'Latest Online Stack' 段。
- artifacts/online-deploy-20260602/: 本次真实部署的证据
  - 01-local-build.txt: 本地 server 二进制 md5 + git head
  - 02-remote-inspect.txt: 远端 process / port / db tables
  - 03-crm-api-checks.txt: /healthz /api/packs /api/hosts /metrics 真实响应
  - 04-portal-public.txt: sub.tksea.top 公共入口
  - 05-quality-gates.txt: gofmt / vet / test -race / integration
  - manifest.json: 结构化汇总

验证(2026-06-02 21:32-21:43):
- /healthz: HTTP 200 'ok'
- /api/packs (Bearer): HTTP 200 '{"packs":[]}'
- /api/hosts (Bearer): HTTP 200 '{"hosts":[]}'
- /api/packs (no auth): HTTP 401
- /metrics (Prometheus): HTTP 200,含 active_hosts/active_providers/
  db_connections_active + Go runtime
- sub.tksea.top/portal/: HTTP 200
- sub.tksea.top/portal-admin-api/healthz: HTTP 200 'ok'(反代到 CRM)
- go test -race ./internal/... ./tests/integration/...: PASS
- gofmt / go vet: 干净
2026-06-02 21:46:39 +08:00
phamnazage-jpg
4ec9dad44f test: 修 build-broken edge-case 测试
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- internal/store/sqlite/edge_cases_test.go: 把错误的 sqlite.New 调用换成
  实际存在的 sqlite.Open(ctx, dsn),清掉阻塞 `go test ./internal/...`
  的 build 失败
- internal/host/sub2api/edge_cases_test.go: gofmt
- internal/worker/runner_extra_test.go: TestRunnerLoggerCalled 加
  sync.Mutex 保护 logger 写入的共享状态;测试结束前 cancel 并留 20ms
  flush 窗口,避免 -race 检测到 goroutine 仍在写

验证: gofmt -l . 干净,go vet ./... 零警告,
go test -race -count=1 ./internal/... 全包通过,集成测试通过
2026-06-02 20:38:29 +08:00
phamnazage-jpg
f6600d663a feat(monitoring): add complete Prometheus + Grafana monitoring stack
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
Add production-ready monitoring infrastructure:
- 15 alerting rules (4 Critical + 11 Warning)
- Grafana dashboard with service health panels
- Full documentation with deployment guide

Covers: service availability, error rates, latency,
routing health, database connections, and log metrics
2026-06-02 19:54:38 +08:00
phamnazage-jpg
fb32deb2b1 docs: 更新验证报告,记录 metrics 端点修复
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-02 07:22:24 +08:00
phamnazage-jpg
5e3bd44e96 fix(metrics): 在主路由中注册 /metrics 端点
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- 添加 metrics 包导入
- 在主 handler 中注册 GET /metrics 路由
2026-06-02 07:22:01 +08:00
phamnazage-jpg
278991bc9d docs: 添加生产上线全面验证报告
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
2026-06-02 07:17:37 +08:00
phamnazage-jpg
8bbdffaf17 test: 补充真实功能验证测试
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- ErrorMetrics 并发安全测试
- AsyncLogWriter 错误指标真实记录测试
- HTTP Server 超时配置真实验证
- Prometheus 指标 HTTP 端点真实测试
- 日志文件输出真实写入测试
2026-06-02 07:07:53 +08:00
phamnazage-jpg
28f377f2bd feat(api): M-04 添加版本信息端点
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
- 添加 /version 端点返回版本信息
- 版本变量支持构建时 ldflags 注入
- 返回 version、commit、build_time、go_version
2026-06-02 07:00:15 +08:00
phamnazage-jpg
133da2d442 test: M-03 添加边界测试
- 添加大量数据边界测试(100条记录)
- 添加特殊字符 PackID 边界测试
- 添加空字段验证边界测试
2026-06-02 06:58:45 +08:00
phamnazage-jpg
b69cb9166e refactor: M-02 添加 errs 包提供错误处理基础设施 2026-06-02 06:57:13 +08:00
phamnazage-jpg
08f7db1bc2 test: M-01 替换测试代码中的 panic 为 t.Fatal
- packs_repo_test.go: panic → t.Fatal
- providers_repo_test.go: panic → t.Fatal
2026-06-02 06:56:30 +08:00
phamnazage-jpg
21065735dd fix(docker): H-05 优化 Dockerfile 环境变量配置
- 添加清晰的注释说明 SUB2API_CRM_ADMIN_TOKEN 为必需配置
- 分离必需和可选环境变量到不同区块
- 更新 Go 版本到 1.23 以匹配 go.mod
2026-06-02 06:55:36 +08:00
phamnazage-jpg
d688722dd2 feat(metrics): H-04 Prometheus 指标暴露
- 创建 internal/metrics 包集成 Prometheus 客户端
- 添加 HTTP 请求指标(总量、延迟直方图)
- 添加业务指标(active_hosts、active_providers)
- 添加路由指标(decisions、failovers)
- 添加数据库指标(connections、operations)
- 添加日志指标(flush_errors、dropped_events)
- 添加 HTTP Middleware 自动收集请求指标
- 添加 StartServer 方法启动独立 metrics 服务
2026-06-02 06:53:24 +08:00
phamnazage-jpg
8984451845 feat(log): H-03 日志 flush 错误监控
- 添加 ErrorMetrics 结构体记录 flush/write/drop 错误数
- 添加 ErrorHandler 回调接口用于自定义错误处理
- 在 AsyncLogWriterOptions 中支持配置错误处理器
- 在 flushBatch 中记录 flush 错误指标并回调错误处理器
- 在 enqueue fallback 路径中记录丢弃事件数
- 添加 Metrics() 方法暴露错误统计
2026-06-02 06:51:14 +08:00
phamnazage-jpg
97502b8a86 test: H-02 补充 migrations 测试
- 验证迁移文件正确嵌入 embed.FS
- 测试所有迁移文件可读且非空
- 验证迁移文件命名规范(NNNN_前缀)
- 测试迁移文件排序一致性
- 验证初始迁移文件包含预期 SQL 内容
2026-06-02 06:50:02 +08:00
phamnazage-jpg
3838d78b00 test: H-01 补充 testutil 测试
- 添加 SQLiteTestDSN 函数测试(外键启用/禁用、特殊字符)
- 添加路径唯一性验证测试
- 添加 OpenSQLiteStore 功能测试(含并发测试)
- 添加 CloseSQLiteStore 测试
- 添加无效 DSN 错误处理测试
2026-06-02 06:49:07 +08:00
phamnazage-jpg
6865b3a33b ci: B-04 添加 GitHub Actions CI/CD 工作流
- 添加完整的 CI 流水线:构建、测试、覆盖率检查
- 集成 golangci-lint 静态代码分析
- 集成 gosec 和 govulncheck 安全扫描
- 添加 Docker 镜像构建验证
- 添加 Release 自动打包(多架构支持)
- 设置覆盖率阈值 60%
2026-06-02 06:47:06 +08:00
phamnazage-jpg
cf7dd35e1d feat(log): B-03 日志轮转配置 - 添加 lumberjack 支持
- 添加 lumberjack.v2 依赖实现日志轮转
- 支持配置文件输出(stdout/stderr/file)
- 支持文件轮转(100MB/3备份/7天/压缩)
- 添加 Config 结构体灵活配置
- 添加完整测试用例

测试验证:
- TestInitWithConfig PASS
- TestInitWithConfigFileOutput PASS
- TestDefaultConfig PASS
- 全量日志测试通过
2026-06-01 22:06:56 +08:00
phamnazage-jpg
714c4acbe4 fix(log): 修复测试文件未使用导入 2026-06-01 22:03:14 +08:00
phamnazage-jpg
91fa5d6ab4 fix(review): 完成系统性 Review 修复方案 - Task B-01 HTTP Server 超时配置
本次提交包含:
- B-01: HTTP Server 添加超时配置 (ReadTimeout/WriteTimeout/IdleTimeout/MaxHeaderBytes)
- 添加结构化日志包 internal/log/ (B-02 部分完成)
- 添加 Review 报告文档
- 添加系统性修复方案文档
- 添加最佳实践审核报告文档
- 更新任务清单和执行板

测试验证:
- TestServerHasTimeoutConfiguration 通过

关联文档:
- docs/2026-06-01-SYSTEMATIC-REVIEW-REPORT.md
- docs/2026-06-01-SYSTEMATIC-REPAIR-PLAN.md
- docs/2026-06-01-BEST-PRACTICE-AUDIT-REPORT.md
2026-06-01 22:02:01 +08:00
phamnazage-jpg
5fbac6ef0b test(frontend): add provider admin acceptance coverage
Add a dedicated acceptance script for providers.html, cover it in the local real-host script regression suite, and document the current frontend review baseline, closure audit, providers action matrix, and remediation task board.

This keeps the frontend acceptance boundary explicit: providers.html now has a repeatable verification entry point for its page-level actions, while non-UI provider operations remain documented as backend-only capabilities.
2026-06-01 09:58:20 +08:00
phamnazage-jpg
c588a95c7d fix(access): verify subscription readiness with real user keys
When subscription access is requested with an explicit access_api_key, assign the subscription to the real target user, bind that user's API key to the subscription group, and probe readiness with the same key instead of falling back to a managed synthetic user.

Update the runtime/reconcile flows, adapter tests, and source-of-truth docs so subscription_ready now reflects user-visible host access rather than managed-key-only closure success.
2026-06-01 09:55:11 +08:00
phamnazage-jpg
702ae19a61 feat(pack): publish provider admin draft provider-admin-publish-1780230107 2026-05-31 20:21:50 +08:00
phamnazage-jpg
fd12838519 docs(testing): record repo upsert closure 2026-05-30 18:54:07 +08:00
phamnazage-jpg
64e14ac30d test(quality): cover repo upsert fallback branches 2026-05-30 18:54:07 +08:00
phamnazage-jpg
2f2653c76f docs(testing): record upsert and open branch follow-up 2026-05-30 18:48:20 +08:00
phamnazage-jpg
9e32a24f8c test(quality): cover upsert validation and redis open branches 2026-05-30 18:48:20 +08:00
phamnazage-jpg
d9216d5712 docs(testing): record narrow branch coverage follow-up 2026-05-30 18:28:03 +08:00
phamnazage-jpg
f895eb9035 test(quality): cover sqlite redis and overlay edge branches 2026-05-30 18:28:03 +08:00
phamnazage-jpg
51472e9951 docs(testing): record hotspot branch coverage uplift 2026-05-30 17:22:25 +08:00
phamnazage-jpg
6bbd55111c test(quality): cover routing sqlite overlay hotspots 2026-05-30 17:22:11 +08:00
phamnazage-jpg
b33fa10677 test(quality): promote overlay coverage to core gate 2026-05-30 17:13:38 +08:00
phamnazage-jpg
249ad5938f test(quality): promote sqlite coverage to core gate 2026-05-30 17:04:45 +08:00
phamnazage-jpg
b371c698cc test(quality): promote routing coverage to core gate 2026-05-30 16:54:05 +08:00
phamnazage-jpg
2a925e2954 test(quality): promote internal app coverage to core gate 2026-05-30 16:48:55 +08:00
403 changed files with 26718 additions and 3965 deletions

165
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,165 @@
name: CI
on:
push:
branches: [main, master]
tags: ['v*']
pull_request:
branches: [main, master]
env:
GO_VERSION: '1.22.2'
jobs:
build:
name: Build & Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Download dependencies
run: go mod download
- name: Build binaries
run: |
go build -v ./cmd/server
go build -v ./cmd/cli
- name: Run unit tests
run: go test -v -race -count=1 ./internal/...
- name: Generate coverage report
run: go test -race -coverprofile=coverage.out -covermode=atomic ./internal/...
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: ./coverage.out
fail_ci_if_error: false
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Check coverage threshold
run: |
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
echo "Total coverage: $COVERAGE%"
if (( $(echo "$COVERAGE < 60" | bc -l) )); then
echo "Coverage $COVERAGE% is below threshold 60%"
exit 1
fi
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: --timeout=5m
skip-cache: false
security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Run gosec security scanner
uses: securego/gosec@master
with:
args: '-no-fail -fmt sarif -out results.sarif ./...'
- name: Run govulncheck
uses: golang/govulncheck-action@v1
with:
go-version-input: ${{ env.GO_VERSION }}
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: results.sarif
docker:
name: Docker Build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
push: false
load: true
tags: sub2api-cn-relay-manager:test
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Test Docker image
run: |
docker run --rm sub2api-cn-relay-manager:test /app/server --version || true
docker run --rm sub2api-cn-relay-manager:test /app/cli --help || true
release:
name: Release
runs-on: ubuntu-latest
needs: [build, lint, security, docker]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Build release binaries
run: |
mkdir -p dist
# Linux AMD64
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/server-linux-amd64 ./cmd/server
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/cli-linux-amd64 ./cmd/cli
# Linux ARM64
GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/server-linux-arm64 ./cmd/server
GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/cli-linux-arm64 ./cmd/cli
ls -la dist/
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: dist/*
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

10
.gitignore vendored
View File

@@ -1,4 +1,14 @@
.agent/
.understand-anything/
artifacts/frontend-acceptance-matrix/
artifacts/provider-admin-matrix/
artifacts/real-host-acceptance/
artifacts/host-capability/
artifacts/default-data/
artifacts/phase2-routing-matrix/
artifacts/fresh-vnext1-acceptance/
artifacts/user-key-self-service/
internal/store/sqlite/?_pragma=foreign_keys(1)
# Local build outputs
/bin/

View File

@@ -9,11 +9,15 @@
## 质量门禁(每个模块完成前必须执行)
1. **设计对齐** — 重新读取 PRD.md、TDD_PLAN.md、EXECUTION_BOARD.md、docs/plans/ 下的规划设计文档,逐条确认实现已覆盖设计目标。发现漂移先修正,不维持虚假 COMPLETED。
2. **代码 review** — 加载 `go-reviewer` skill对新写/修改的全部 Go 文件做系统审查。
3. **测试覆盖**`go test -cover ./internal/...` 核心包provision、access、pack覆盖率 >= 70%。未达标则补用例。
4. **静态分析**`go vet ./...` 零警告。`gofmt -l .` 显示无未格式化文件。
5. **集成验证**`go test ./tests/integration/... -count=1` 必须通过
6. **板同步** — 更新 EXECUTION_BOARD.md反映真实完成状态
2. **前端门禁** — 任何触及 `deploy/tksea-portal/``deploy/*portal*``/portal-admin-api/` 文案或前端验收文档的改动,必须至少执行:
- `bash ./scripts/test/test_tksea_portal_assets.sh`
- `bash ./scripts/test/verify_frontend_smoke.sh`
- 若改动 `providers.html` 页面内显式动作,还必须执行 `bash ./scripts/acceptance/verify_provider_admin_actions.sh` 或给出不可执行原因
3. **代码 review** — 加载 `go-reviewer` skill对新写/修改的全部 Go 文件做系统审查
4. **测试覆盖**`go test -cover ./internal/...` 核心包provision、access、pack覆盖率 >= 70%。未达标则补用例。
5. **静态分析**`go vet ./...` 零警告。`gofmt -l .` 显示无未格式化文件。
6. **集成验证**`go test ./tests/integration/... -count=1` 必须通过。
7. **板同步** — 更新 EXECUTION_BOARD.md反映真实完成状态。
## Go 编码规范

View File

@@ -1,4 +1,4 @@
FROM golang:1.22.2 AS builder
FROM golang:1.23 AS builder
ARG http_proxy=
ARG https_proxy=
ARG HTTP_PROXY=
@@ -35,9 +35,16 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=builder /out/sub2api-cn-relay-manager /usr/local/bin/sub2api-cn-relay-manager
ENV SUB2API_CRM_LISTEN_ADDR=:8080
ENV SUB2API_CRM_SQLITE_DSN=file:/data/sub2api-cn-relay-manager.db?_foreign_keys=on&_busy_timeout=5000
# Required: Admin API token for administrative endpoints
# Must be provided at runtime, container will fail to start without it
ENV SUB2API_CRM_ADMIN_TOKEN=
# Optional: Listen address (defaults to :8080)
ENV SUB2API_CRM_LISTEN_ADDR=:8080
# Optional: SQLite DSN (defaults to /data/sub2api-cn-relay-manager.db)
ENV SUB2API_CRM_SQLITE_DSN=file:/data/sub2api-cn-relay-manager.db?_foreign_keys=on&_busy_timeout=5000
VOLUME ["/data"]
EXPOSE 8080
ENTRYPOINT ["/usr/local/bin/sub2api-cn-relay-manager"]

580
TASKS.md Normal file
View File

@@ -0,0 +1,580 @@
# sub2api-cn-relay-manager 修复任务清单
> 基于 Review 报告生成
> **目标**: 系统化跟踪 BLOCKER/HIGH/MEDIUM 问题解决
---
## 📋 任务总览
- **BLOCKER**: 4 项 | 预计 16h
- **HIGH**: 5 项 | 预计 20h
- **MEDIUM**: 4 项 | 预计 12h
- **总计**: 13 项 | 预计 48h
---
## 🚨 BLOCKER 任务(必须完成)
### [ ] B-01 HTTP Server 添加超时配置
```yaml
优先级: P0
状态: 待处理
负责人: 待分配
开始日期: 待确定
预计工时: 4h
阻塞:
```
**描述**: HTTP Server 未配置 ReadTimeout、WriteTimeout、IdleTimeout
**文件修改**:
- `internal/app/app.go`
- `internal/app/app_test.go`
**验收标准**:
- [ ] 添加 ReadTimeout: 30s
- [ ] 添加 WriteTimeout: 30s
- [ ] 添加 IdleTimeout: 120s
- [ ] 添加 MaxHeaderBytes: 1MB
- [ ] 集成测试通过
---
### [ ] B-02 日志结构化改造
```yaml
优先级: P0
状态: 待处理
负责人: 待分配
开始日期: 待确定
预计工时: 6h
阻塞:
```
**描述**: 使用标准库 log 输出非结构化日志
**文件修改**:
- `internal/log/log.go` (新建)
- `cmd/server/main.go`
- `cmd/cli/main.go`
- `internal/routing/logwriter.go`
**验收标准**:
- [ ] 创建 slog 封装包
- [ ] 支持 LOG_LEVEL 环境变量
- [ ] 所有日志输出 JSON 格式
- [ ] 替换所有 log.Printf/log.Fatalf
---
### [ ] B-03 日志轮转配置
```yaml
优先级: P0
状态: 待处理
负责人: 待分配
开始日期: 待确定
预计工时: 4h
阻塞:
```
**描述**: 容器环境下日志无限增长
**文件修改**:
- `internal/log/log.go`
- `go.mod`
**依赖**:
- `gopkg.in/natefinch/lumberjack.v2`
**验收标准**:
- [ ] 单日志文件 100MB 限制
- [ ] 保留 3 个历史日志
- [ ] 历史日志自动压缩
- [ ] 7 天自动清理
---
### [ ] B-04 CI/CD 工作流配置
```yaml
优先级: P0
状态: 待处理
负责人: 待分配
开始日期: 待确定
预计工时: 4h
阻塞:
```
**描述**: 缺少 GitHub Actions 自动化测试和发布
**文件新建**:
- `.github/workflows/ci.yml`
- `.github/workflows/release.yml`
**验收标准**:
- [ ] CI 触发测试、覆盖率检查
- [ ] CI 触发格式化检查
- [ ] Release 构建多平台二进制
- [ ] Release 推送 Docker 镜像
---
## 🔴 HIGH 任务(建议完成)
### [ ] H-01 补充 testutil 测试
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 3h
```
**文件新建**:
- `internal/testutil/sqlite_test.go`
**验收标准**:
- [ ] TestNewTestDB 覆盖率 100%
- [ ] TestNewTestDBWithMigrations 覆盖率 100%
---
### [ ] H-02 补充 migrations 测试
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 4h
```
**文件新建**:
- `internal/store/migrations/migrations_test.go`
**验收标准**:
- [ ] TestMigrationScripts 验证关键表
- [ ] TestMigrationIdempotency 验证幂等性
---
### [ ] H-03 日志 flush 错误监控
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 3h
```
**文件修改**:
- `internal/routing/logwriter.go`
**验收标准**:
- [ ] 添加 flush 错误计数
- [ ] 添加 Prometheus 指标暴露
- [ ] 超过阈值告警
---
### [ ] H-04 Prometheus 指标暴露
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 6h
```
**文件新建**:
- `internal/metrics/metrics.go`
**文件修改**:
- `internal/app/http_api.go`
- `go.mod`
**依赖**:
- `github.com/prometheus/client_golang/prometheus`
**验收标准**:
- [ ] HTTP 请求指标(总量、延迟)
- [ ] 业务指标(导入、对账)
- [ ] /metrics 端点可访问
---
### [ ] H-05 移除 Dockerfile 默认值
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 1h
```
**文件修改**:
- `Dockerfile`
**文件新建**:
- `scripts/docker-entrypoint.sh`
**验收标准**:
- [ ] 移除 SUB2API_CRM_ADMIN_TOKEN 默认值
- [ ] 添加启动时强制检查
- [ ] 缺少必需变量时优雅退出
---
## 🟡 MEDIUM 任务(可选完成)
### [ ] M-01 测试代码 panic 替换
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 2h
```
**文件修改**:
- `internal/store/sqlite/packs_repo_test.go:208`
- `internal/store/sqlite/providers_repo_test.go:316`
**修改内容**:
```go
// panic("unexpected QueryRowContext")
// ->
t.Fatalf("unexpected QueryRowContext")
```
---
### [ ] M-02 错误信息字符串匹配优化
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 3h
```
**文件新建**:
- `internal/errors/errors.go`
**修改目标**:
- 多处测试使用 `strings.Contains(err.Error(), ...)`
- 改为使用 `errors.Is()`
---
### [ ] M-03 边界测试补充
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 4h
```
**文件修改**:
- `internal/app/*_test.go`
**测试场景**:
- [ ] 空字符串参数
- [ ] 超长参数256+ 字符)
- [ ] 特殊字符参数
- [ ] 边界数值参数
---
### [ ] M-04 添加版本信息端点
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 3h
```
**文件修改**:
- `internal/app/http_api.go`
- `Makefile``Dockerfile`
**验收标准**:
- [ ] GET /version 端点返回版本信息
- [ ] 包含 version、commit、build_time
---
## 📅 执行日历
### Week 1: BLOCKER 修复
| 日期 | 任务 | 状态 |
|------|------|------|
| Mon | B-01 HTTP Server 超时 | [ ] |
| Tue | B-02 日志结构化 | [ ] |
| Wed | B-03 日志轮转 | [ ] |
| Thu | B-04 CI/CD 配置 | [ ] |
| Fri | BLOCKER 集成测试 | [ ] |
### Week 2: HIGH 修复
| 日期 | 任务 | 状态 |
|------|------|------|
| Mon | H-01 testutil 测试 | [ ] |
| Tue | H-02 migrations 测试 | [ ] |
| Wed | H-03 日志 flush 监控 | [ ] |
| Thu | H-04 Prometheus | [ ] |
| Fri | H-05 Dockerfile | [ ] |
### Week 3: MEDIUM + 验收
| 日期 | 任务 | 状态 |
|------|------|------|
| Mon | M-01 panic 替换 | [ ] |
| Tue | M-02 错误匹配优化 | [ ] |
| Wed | M-03 边界测试 | [ ] |
| Thu | M-04 版本端点 | [ ] |
| Fri | 全量回归测试 | [ ] |
---
## 📝 任务状态更新日志
<!-- 在此记录任务进度 -->
### 2026-06-01
- 任务清单创建完成
- 状态:初始状态,未开始
---
## 🎯 完成标准
### BLOCKER 完成检查
- [ ] B-01 代码审查通过
- [ ] B-02 代码审查通过
- [ ] B-03 代码审查通过
- [ ] B-04 代码审查通过
- [ ] 所有 BLOCKER PR 合并
- [ ] BLOCKER 集成测试通过
### HIGH 完成检查
- [ ] H-01 代码审查通过
- [ ] H-02 代码审查通过
- [ ] H-03 代码审查通过
- [ ] H-04 代码审查通过
- [ ] H-05 代码审查通过
- [ ] 所有 HIGH PR 合并
### 最终验收
- [ ] 综合评级从 B 提升到 A
- [ ] 全量测试通过
- [ ] 性能测试达标
- [ ] 安全扫描通过
- [ ] 生产就绪评审通过
---
**清单版本**: v1.0
**生成时间**: 2026-06-01
**对应 Review**: 2026-06-01-SYSTEMATIC-REVIEW-REPORT.md
---
## 🔧 最佳实践补充任务(审核后添加)
### 高优先级补充任务4 项10h
#### [ ] H-1a: 日志敏感信息脱敏
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 2h
依赖: B-02
```
**文件新建**:
- `internal/log/sanitize.go`
**实现内容**:
```go
func Sanitize(fields map[string]interface{}) map[string]interface{}
// 自动脱敏: token, password, key, secret, credential
```
---
#### [ ] H-2a: CI/CD 安全扫描
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 3h
依赖: B-04
```
**文件修改**:
- `.github/workflows/ci.yml`
**添加步骤**:
```yaml
- name: Run govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest && govulncheck ./...
- name: Run gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@latest && gosec ./...
- name: Run staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@latest && staticcheck ./...
```
---
#### [ ] H-3a: Dockerfile 非 root 用户
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 1h
依赖: H-05
```
**文件修改**:
- `Dockerfile`
**添加指令**:
```dockerfile
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
USER appuser
```
---
#### [ ] H-4a: 新建故障处理手册
```yaml
优先级: P1
状态: 待处理
负责人: 待分配
预计工时: 4h
依赖: -
```
**文件新建**:
- `docs/RUNBOOK.md`
**内容章节**:
- 启动失败诊断
- 数据库连接问题
- 宿主 API 连接超时
- 导入失败回滚
- 对账异常处理
- 日志排查指南
- 告警响应流程
---
### 中优先级补充任务5 项15h
#### [ ] M-1a: 添加 ReadHeaderTimeout
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 1h
依赖: B-01
```
**修改**:
```go
server: &http.Server{
ReadTimeout: 30 * time.Second,
ReadHeaderTimeout: 10 * time.Second, // 新增
WriteTimeout: 30 * time.Second,
IdleTimeout: 120 * time.Second,
}
```
---
#### [ ] M-2a: 添加 trace_id 支持
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 3h
依赖: B-02
```
**文件修改**:
- `internal/log/log.go`
- `internal/app/middleware.go`
**实现**:
- 生成 trace_id
- 注入 context
- 所有日志携带 trace_id
---
#### [ ] M-3a: 添加模糊测试
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 4h
依赖: -
```
**文件新建**:
- `internal/provision/import_fuzz_test.go`
- `internal/pack/validate_fuzz_test.go`
---
#### [ ] M-4a: 添加业务指标
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 3h
依赖: H-04
```
**文件修改**:
- `internal/metrics/business.go`
**添加指标**:
- `import_runs_total`
- `import_success_rate`
- `reconcile_drift_total`
- `route_proxy_duration`
---
#### [ ] M-5a: API 限流实现
```yaml
优先级: P2
状态: 待处理
负责人: 待分配
预计工时: 4h
依赖: -
```
**文件新建**:
- `internal/app/ratelimit.go`
**实现**:
```go
// Token bucket rate limiter
// 100 req/s, burst 10
// 按 IP 和按 Token 双维度
```
---
## 📊 更新后任务统计
| 类别 | 原始任务 | 补充任务 | 总计 | 工时 |
|------|----------|----------|------|------|
| BLOCKER | 4 | 0 | 4 | 16h |
| HIGH | 5 | 4 | 9 | 30h |
| MEDIUM | 4 | 5 | 9 | 27h |
| **总计** | **13** | **13** | **22** | **73h** |
---
**任务清单版本**: v2.0(审核后更新)
**更新时间**: 2026-06-01
**更新原因**: 最佳实践审核发现 9 项补充任务

View File

@@ -0,0 +1 @@
{"key":{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"active","quota_status":"ok","created_at":""},"plaintext_key":"sk-relay-69237400bb990d35eb196a7c82bb314c"}

View File

@@ -0,0 +1 @@
{"error":{"message":"Upstream service temporarily unavailable","type":"upstream_error"}}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"","logical_group_id":"","allowed_models":null,"admin_status":"paused","quota_status":"","created_at":""}

View File

@@ -0,0 +1 @@
{"id":"resp_0b7d92f03dbfe646016a24365dd68481a29116f3592a690856","object":"chat.completion","created":1780758114,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":148,"total_tokens":3446,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_02b3ac2c15de29a5016a24369d48f0819ca80057c3006701ce","object":"chat.completion","created":1780758178,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":222,"total_tokens":3520,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_05d1147c9b5af733016a2436a563d081a1b34b84bcabf0ffe0","object":"chat.completion","created":1780758183,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"Ready."},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":99,"total_tokens":3397,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0b4dfacd2999f96d016a2436ab3f84819c88ed0d3068e04ed6","object":"chat.completion","created":1780758189,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":89,"total_tokens":3387,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0fae06ec0d09e615016a2436b08c54819e8d01da5b6b49df6d","object":"chat.completion","created":1780758195,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":104,"total_tokens":3402,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_04dc6fd6373ae2e9016a2436bb71bc819f88bc782f21b36a38","object":"chat.completion","created":1780758206,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"Ready."},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":115,"total_tokens":3413,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_064a2c5c9e29f38e016a2436c0b72c819184c4365c3e01c99e","object":"chat.completion","created":1780758211,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":121,"total_tokens":3419,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_045047f137adc636016a2436c60b6c819cb51285d48108008d","object":"chat.completion","created":1780758216,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":107,"total_tokens":3405,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_088a9efef0353a98016a2436cb1dac81a1a53c602df5b43855","object":"chat.completion","created":1780758221,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":86,"total_tokens":3384,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_024fb47c3ba1bc40016a2436d0a70c81a3a540db60dfb0a2be","object":"chat.completion","created":1780758227,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":97,"total_tokens":3395,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_00c62aecdc5b41d9016a2436d66a008192a0af8e1cff1b0f17","object":"chat.completion","created":1780758233,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"Ready."},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":126,"total_tokens":3424,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0b5e1448114477ae016a2436649fd88191ad4815ad2cc28819","object":"chat.completion","created":1780758120,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":171,"total_tokens":3469,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0952ee1f977e49e7016a2436dcc6e081a2bd5b325036246cb1","object":"chat.completion","created":1780758239,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":75,"total_tokens":3373,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0be69bb95b789d1f016a2436e2864881919659f3319d33ba24","object":"chat.completion","created":1780758245,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":93,"total_tokens":3391,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0ecf8f4bafcab4ac016a2436e8ea08819d9a8395d44d841b65","object":"chat.completion","created":1780758252,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":134,"total_tokens":3432,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_05f0307ae5658b3b016a2436f03cb081a0a631dc58aa7e4bc5","object":"chat.completion","created":1780758258,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":99,"total_tokens":3397,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0f5ce828ae5701d7016a2436f5ef5c8192b143e1f82e60031e","object":"chat.completion","created":1780758264,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":87,"total_tokens":3385,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0a23ef3605c6dc60016a2436fbc1e4819cbad17c0825ae1c94","object":"chat.completion","created":1780758269,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":81,"total_tokens":3379,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0bfe5bd05856ff6e016a243701fbe081a18c56b4bd3e5c1e75","object":"chat.completion","created":1780758277,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":99,"total_tokens":3397,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0261646ca17e8b61016a243709a26481a28177c917c719a081","object":"chat.completion","created":1780758285,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":119,"total_tokens":3417,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_06a6ff93252fbef2016a243710ce60819cbec1b1d32a7e6af2","object":"chat.completion","created":1780758291,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":108,"total_tokens":3406,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_09f94cb56690617e016a243719177881a2a3fb006fa99a9e30","object":"chat.completion","created":1780758299,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":71,"total_tokens":3369,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_04c565a481bffdca016a24366d40848191902911b9c4816aa7","object":"chat.completion","created":1780758127,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":89,"total_tokens":3387,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_084de987afc36f16016a24371e0ef4819daa062d347872e6fc","object":"chat.completion","created":1780758306,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":155,"total_tokens":3453,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_02f4245ebce5d147016a2437256c5081a0a245fd88fba2d897","object":"chat.completion","created":1780758311,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":75,"total_tokens":3373,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_09ac366cb712cb72016a24372c774881929be86b3d2d6e59f1","object":"chat.completion","created":1780758319,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":88,"total_tokens":3386,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0d4f4746004b0028016a243732c44481a28dfa077d94d1c0e7","object":"chat.completion","created":1780758325,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":85,"total_tokens":3383,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_085f27af59e08f5a016a24373a8f1081a2b185e3127fa97745","object":"chat.completion","created":1780758334,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":103,"total_tokens":3401,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0768193622433b46016a243741abc081a09d7cbabe11b706c7","object":"chat.completion","created":1780758344,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":320,"total_tokens":3618,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_048a69936ce3e810016a24374b678481a2af5de72c5bcbe55d","object":"chat.completion","created":1780758351,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":126,"total_tokens":3424,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_06077fd8b4d44dea016a24375305f08191bf16269445819169","object":"chat.completion","created":1780758357,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"Ready."},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":55,"total_tokens":3353,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_05cd1150bec33b54016a243758d1b081a2bb29d82595746fca","object":"chat.completion","created":1780758365,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":129,"total_tokens":3427,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0389282ec92aec54016a24376078bc81a1a0a61cddce5c0269","object":"chat.completion","created":1780758371,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":88,"total_tokens":3386,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0ebc6ae4dae17b35016a2436721e3881918861706706d3e43b","object":"chat.completion","created":1780758132,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":104,"total_tokens":3402,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_009e975f82fe5d75016a2437695194819181be88ffd8c82d8e","object":"chat.completion","created":1780758381,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":110,"total_tokens":3408,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_039dd887d4a943d3016a24376fc3dc819f8011db366e51cc7b","object":"chat.completion","created":1780758387,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":145,"total_tokens":3443,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_026d4518998767db016a2437760bf481a1a22dd5111d2f4993","object":"chat.completion","created":1780758392,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":88,"total_tokens":3386,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_06a375cb27a70166016a24377e88bc8191b5de3a628364382b","object":"chat.completion","created":1780758401,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"Ready."},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":126,"total_tokens":3424,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_00e80785b0174ffe016a2437845afc81a3a50343757fb47351","object":"chat.completion","created":1780758410,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":75,"total_tokens":3373,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0c21703a01214d2f016a24378c6fcc81a19298e25db6b66c1a","object":"chat.completion","created":1780758415,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"Ready."},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":134,"total_tokens":3432,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0c77b1070e2953d0016a243792138481a1b51aa5538d885cc4","object":"chat.completion","created":1780758422,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":168,"total_tokens":3466,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_06e68b71ed95f985016a2436780790819dba061a2c0eea85f8","object":"chat.completion","created":1780758138,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":119,"total_tokens":3417,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0898ef6aa6edcb1e016a24367d7948819fa790444dec72d920","object":"chat.completion","created":1780758144,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":97,"total_tokens":3395,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0034d2f0b932ed4a016a24368348a081a180a7cb86222d38a9","object":"chat.completion","created":1780758149,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":92,"total_tokens":3390,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_0261fff06c6fd3b7016a243688e3ac819eabf0598c0510ad15","object":"chat.completion","created":1780758155,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":103,"total_tokens":3401,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_03796c111d5c680a016a24368f27bc8192a55b8479652a2821","object":"chat.completion","created":1780758161,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":106,"total_tokens":3404,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"id":"resp_022751bb8bf6c2b7016a2436950c548191a75cdf5b9285f843","object":"chat.completion","created":1780758168,"model":"gpt-5.4","choices":[{"index":0,"message":{"role":"assistant","content":"pong"},"finish_reason":"stop"}],"usage":{"prompt_tokens":3298,"completion_tokens":98,"total_tokens":3396,"prompt_tokens_details":{"cached_tokens":2816}}}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

View File

@@ -0,0 +1 @@
{"key_id":"key_sxzh7kokphn9","masked_preview":"sk-****314c","display_name":"probe-v2-20260606_230107","logical_group_id":"gpt-shared","allowed_models":["gpt-5.4"],"admin_status":"paused","quota_status":"ok","created_at":"2026-06-06T15:01:08Z"}

Some files were not shown because too many files have changed in this diff Show More