Commit Graph

121 Commits

Author SHA1 Message Date
root ae0e4b0209 feat(admin-web): make KOL dashboard trend chart responsive with tooltip
Chart now adapts to container size via useElementSize and adds a hover
tooltip with per-point overlay. Prevents grid/flex blowout with min-width
and layers the SVG absolutely inside its wrapper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 15:25:52 +08:00
root e04593f4af fix(desktop): guard Kimi adapter against incomplete and keyword-blob answers
Add heuristics to distinguish keyword fragments from substantive answers,
enforce a grace period before returning incomplete content, and mark timed-out
or reasoning-only captures as unknown so later passes can re-collect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:34:05 +08:00
root 4f4f063200 refactor(monitoring): simplify brand dashboard and harden citation rendering
- drop brand_time_buckets and sparkline/coverage UI; dashboard now returns a single day
- compute mention rate from total actual samples instead of averaging per-platform rates
- canonicalize ai_platform_id across services and aggregate platform-overview snapshots
- strip mojibake and non-answer noise from callback payloads and question detail answers
- keep Kimi citations panel-only; still store raw search_results for audit
- render linked [n] inline citations for qwen/yuanbao answers with scroll-to-source behavior
- restrict立即采集 to today's business date with a clear i18n hint
- refresh content-citations into an ant-design table with truncation and hover styling

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:11:53 +08:00
root ce028c56bf feat(desktop): auto-recover in-progress desktop tasks on client lifecycle events
- reset stale in_progress tasks owned by a client on startup, offline, and lease expiry
- monitor tasks re-queue for another pick; publish tasks move to unknown for manual reconcile
- send startup=true flag on first heartbeat so the server can trigger recovery
- finalize the linked desktop task when a phase2 monitor callback arrives via desktop_tasks path
- short-circuit the desktop monitor attempt write after the callback already finalized it

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:11:23 +08:00
root f91d2645d3 feat(desktop): add Kimi and Yuanbao monitoring adapters
- implement kimi/yuanbao monitor adapters with dedicated citation panel detection
- detect Kimi session via kimi-auth cookie during account binding
- harden hidden Playwright and bound windows with skipTaskbar/focusable/hiddenInMissionControl to stop stealing focus
- tag hidden bootstrap windows with a unique token so CDP retention resolves the correct page
- enable yuanbao/kimi/wenxin platforms in dev-seed and default monitoring quota
- update kimi loginUrl to www.kimi.com

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:09:20 +08:00
root 4142c53fa6 feat(monitoring): dispatch monitoring tasks to desktop via AMQP outbox
Replace SSE /desktop/events with priority AMQP dispatch for monitoring
runs, and add phase1/phase2 infrastructure so desktop workers can lease,
resume, report, skip, and cancel monitoring tasks over the existing
dispatch WebSocket.

- Add monitoring collect outbox worker and phase2 desktop task fields
- Add /desktop/monitoring/tasks/{lease,resume,result,skip,cancel} routes
- Introduce execution-devtools and network-observer on desktop runtime
- Refactor runtime-controller, LoginView, and doubao adapter for the new flow
- Add channelName column to tracking views

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:24:21 +08:00
root 749b6b99cd Refactor(desktop-client): code structure for improved readability and maintainability 2026-04-20 21:55:54 +08:00
root 9fa091c150 feat(desktop): push publish tasks via AMQP topic dispatch WebSocket
Introduce a desktop.task.dispatch topic exchange with per-client routing
keys. Tenant-api publishes a task_available frame keyed by target client
ID when a publish job is created; every instance binds its own transient
queue and forwards to the matching WebSocket (/api/desktop/dispatch) it
owns. Desktop-client now prefers this push channel and only falls back
to HTTP /lease polling when the socket is down. Also drop admin-web
monitoring-plugin remnants and scope the publish modal account list to
publish platforms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 19:46:59 +08:00
root 7abac1e9c4 feat: Implement Qwen adapter and enhance AI platform detection
- Added a new Qwen adapter to facilitate monitoring through Playwright, leveraging internal text/chat managers.
- Updated account detection logic to recognize Qwen sessions based on persisted cookies, improving binding reliability.
- Relaxed authentication requirements for monitor tasks, allowing anonymous execution for certain AI platforms.
- Enhanced the generic AI platform detection to include Qwen-specific logic, ensuring accurate session identification.
- Modified the monitoring dashboard to include runtime state indicating if the current user's desktop client is online.
- Updated various files including `account-binder.ts`, `runtime-controller.ts`, and `monitoring_service.go` to support new features and improvements.
2026-04-20 19:10:35 +08:00
root 69fd182755 refactor(desktop): narrow home health board to expired/revoked accounts
Home 看板只保留已过期或已停用的账号,问题计数改用阻塞态 authState;新增 formatVerifiedAtLabel,统一校验通过时间的展示粒度。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 17:25:58 +08:00
root 55e1c2e74b feat(desktop): add monitor scheduler, Playwright CDP layer, and account health
Move monitor-task scheduling authority onto the client with a durable
file-backed queue that survives restart, drops stale cross-day tasks,
enforces per-platform serialism, and adapts global concurrency from
Electron process metrics. Publish tasks keep their existing FIFO.

Add a hidden Playwright CDP manager that attaches to Electron Chromium
on account session partitions, lets adapters opt into `executionMode:
"playwright"`, and leaves the existing hidden WebContentsView path in
place for current adapters.

Introduce an account-health subsystem with silent probes, projected
health/auth states, and IPC invalidation events so the renderer can
show accurate auth/probe status and verification timestamps.

Server-side, derive and forward title/business_date/scheduler_group_key/
question_text metadata on desktop task events so the local scheduler
can defer same-question fan-out before leasing.
2026-04-20 17:16:15 +08:00
root 07881a66d0 style(desktop): refresh Home and Publish views with modern card layout
Inline the card styling on HomeView and PublishManagementView instead of
leaning on the generic MetricCard/SurfaceCard wrappers — larger numerics,
softer radii, clearer section headers, and a stats strip on the Publish hero.
No behavioral changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:04:39 +08:00
root 40c9c36653 feat(desktop): show live device name in shell and keep stored info fresh
Sidebar now pulls the device name from the runtime snapshot (the client the
backend sees) instead of the stale copy persisted at login, so a rebinding or
hostname change is visible without relogin. Session composable resolves a more
accurate fallback device name/OS from userAgentData and silently re-persists
desktopClient.{device_name,os,cpu_arch} on boot when the resolved values differ
from what's stored. Also replaces the text logout link with an icon button and
adds a status dot to the device tag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:04:32 +08:00
root ad9a784e8c fix(accounts): hide AI-platform accounts from publish-only views
After splitting AI platforms into their own catalog, the admin MediaView and
desktop AccountsView still showed yuanbao/kimi/wenxin/deepseek/doubao/qwen
rows alongside publish platforms. Filter by publish catalog membership so
those views stay scoped to publish accounts only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:44:51 +08:00
root 09295d11a1 feat(monitoring): decouple AI platforms from media_platforms and expand catalog to 6
Add ai_platforms table + shared catalog (yuanbao/kimi/wenxin/deepseek/doubao/qwen),
drop FKs from platform_accounts and desktop_tasks to media_platforms, and wire
target_account_id + platform into DesktopTaskEvent so the desktop runtime no
longer has to infer them from local state. Desktop client gains generic AI page
detection for binding, drops stale-business-date monitor tasks at the edge, and
refactors AccountsView/AiPlatformsView around the shared catalog. Admin tracking
view surfaces per-platform sampling status cards.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:40:18 +08:00
root 25dad49ed3 i18n(desktop): localize runtime activity titles and details to Chinese
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:17:56 +08:00
root 5ff2e2e74c refactor(tenant): drop legacy plugin_installations, migrate monitoring to desktop_clients
Hard cutover from the browser-extension plugin flow to desktop clients:
remove plugin_installations/plugin_sessions tables and related service,
handler, router, and generated model code; migrate monitoring quotas
and collector types to desktop_clients (UUID primary_client_id);
recreate platform_access_snapshots keyed by client_id; update dev-seed
and callback types accordingly; mark legacy design docs as historical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 13:52:35 +08:00
root f5a1cd81b2 style(admin-web): truncate long client status tag with tooltip
Long desktop client status labels overflowed the media card; cap tag width with ellipsis and expose the full text via tooltip on hover.
2026-04-20 12:00:10 +08:00
root 9bfe0fab48 fix(desktop): report real hostname/platform/arch in heartbeat
Renderer was registering clients with navigator.platform ("MacIntel") and
a hardcoded "renderer-preview" cpu_arch. Source device info from the main
process (os.hostname + process.platform/arch) via a new device-info IPC,
and let heartbeats always send the authoritative runtime values so stale
registrations self-heal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:59:35 +08:00
root 4d0c4510ef feat(desktop): add zhihu publish adapter
Ship a Zhihu publish adapter that reuses the shared session fetch and
image pipeline: converts markdown to HTML via marked, uploads cover
and inline images through Zhihu's image token flow, creates a draft,
and publishes it, returning external article URLs. Wire it into the
adapter barrel and runtime-controller's publish adapter selector so
Zhihu publish tasks stop falling through to the scaffold result.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:45:08 +08:00
root dc68ad044c refactor(publish): collapse pending_review/unknown task states into failed
Treat ambiguous terminal states as failures end-to-end: server
normalizes unknown desktop task completions and views to failed, drops
the pending_review aggregate branch, and remaps pending_review to
failed in publish record conversion. admin-web removes the
pending_review status option from article list filters, pushes
pending_review through the failed tone, and folds lingering
publishing/pending entries under the publishing bucket. desktop-client
relabels unknown as 发送失败 in PublishManagement/TasksView, rewrites
the scaffold adapter result to a proper failed error envelope, and
sanitises legacy scaffold-only error messages to a user-friendly note.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:44:47 +08:00
root 4014eff427 feat(desktop): dedupe bind windows per platform and cap concurrency at 2
Track active bindPublishAccount calls in a per-platform map so a repeat
invocation reuses and focuses the existing window instead of spawning
a second one, and reject new platforms once 2 bind windows are already
open. Surface desktop_account_bind_limit_reached as a warning modal in
the renderer so users know to finish or close an existing authorization
before starting another.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:11:21 +08:00
root 12f972882b style(admin-web): refresh publish article modal to flat neutral palette
Swap the gradient hero, rounded shadows, and blue-tinted accents for a
neutral card system (gray-50/100 surfaces, indigo eyebrow chip, blue-500
selection ring), tighten checkmark sizing with a fade-in transition, and
normalise list/tag spacing so the modal reads consistently with the
rest of admin-web.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:08:17 +08:00
root 73dfbbe8b5 perf(desktop): lazy-load renderer routes and pause polling when hidden
Drop the eager Antd global import in favour of unplugin-vue-components
on-demand resolution, async route components, defineAsyncComponent for
the shell/login split, and a dynamic Modal import inside
showClientActionError. Pair that with a visibility-aware runtime poller
that stops the 15s snapshot refresh when the window is hidden and kicks
off an immediate refresh on re-show. Refresh DesktopShell nav with
inline icons and a calmer active/hover treatment, and land
ActionButton/DisclosurePanel/PaginationBar primitives for upcoming
views.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:08:09 +08:00
root ef868f81a1 feat(desktop): add hot view retain/release lifecycle and process metrics
Replace single-shot acquireHotView with retainHotView/releaseHotView
plus a minute-level reaper that closes views idle beyond 5 minutes and
never evicts a view while it still has live retainers. Wrap adapter
calls in try/finally so a failing publish/query still releases the
view. Sample process metrics every minute and expose hot-view policy
and process snapshot via the runtime snapshot for diagnostics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:07:58 +08:00
root a46ed4b9f6 fix(tenant): resolve desktop retry article id via publish record/batch
Fall back to looking up article_id from publish_records or publish_batches
when the desktop task payload lacks article_id at the top level. Covers
payloads that only carry content_ref.{article_id,id}, publish_record_id,
or publish_batch_id, preventing spurious 40096 errors when retrying
older desktop tasks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 11:07:48 +08:00
root a617d39a4a feat(desktop): drop parked review flow, add publish management
SaaS 侧人工审核后才创建 publish job,desktop 不再做二次审核:移除
manual/waiting_user/parked/from_parked 状态机与 LeaseFromParked 查询,
desktop client 只执行发布并新增"发布管理"页(待发布队列 / 历史 / 再次
发送)。同时抽离 @geo/publisher-platforms 共享适配器包、新增 Redis-based
desktop_presence 与 publish_record_support,刷新 admin-web 发布弹窗与
媒体库;plan A / spec 文档同步口径。
2026-04-20 09:52:48 +08:00
root b16e9f0bd1 feat(desktop): implement workspace foundation + desktop-client skeleton
Plan 0 (workspaces): add workspaces + workspace_memberships schema, extend
JWT/Actor/claims with primary_workspace_id, seed default workspace per tenant,
thread workspace_id through tenant monitoring quota.

Plan A (desktop skeleton): new Electron app (apps/desktop-client) with main/
preload/renderer, shared Vue component package (packages/ui-shared), and server
surface — desktop client registration + token rotation + heartbeat, SSE task
event stream, desktop accounts/tasks/content handlers, publish job endpoint,
and supporting repositories, services, sqlc queries, and migrations.

Hard cutover per plan: remove browser-extension monitoring callback endpoints,
stub legacy media API in admin-web, and delete monitoring_callback_handler.go.
2026-04-19 14:18:20 +08:00
root 98f9e95875 docs(plans): add Plan 0 (workspace foundation) and Plan A (desktop skeleton)
Plan 0 · Workspace 底座一等化 (2-3 weeks, blocks Plan A):
  - Phase 0.1 workspaces + workspace_memberships tables with default
    seed; backfill workspace_id onto existing platform_accounts and
    tenant_monitoring_quotas.
  - Phase 0.2 Actor/Claims/JWT add PrimaryWorkspaceID; Login/Refresh
    inject via GetPrimaryWorkspaceForUser query.
  - Phase 0.3 WorkspaceScope middleware driven from Actor only (query
    params rejected); wired to /api/tenant/events / accounts /
    publish-jobs / tasks / monitoring whitelist.
  - Phase 0.4 sqlc queries for platform_accounts and
    tenant_monitoring_quotas filter by workspace_id; ≥10
    cross-workspace penetration test cases.
  - Phase 0.5 workspace-sensitive cache keys.
  - Phase 0.6 monitoring domain migration: rename
    primary_installation_id → primary_client_id; service / handler /
    projection / recovery / cleanup / seed all consume workspace_id;
    regression tests.
  - Phase 0.7 /api/auth/me returns primary_workspace; admin-web memo.
  - Phase 0.8 CI lint guard enforces workspace_id injection on
    desktop lines.
  - Phase 0.9 server-derived SSE topic library + exit-bar smoke +
    code review checklist.

Plan A · 桌面客户端骨架穿透 (5-6 weeks):
  - Phase A.0 CDP spike matrix for Doubao (0.5w, blocks A.4).
  - Phase A.1 server protocol + DB: desktop_clients /
    platform_accounts / desktop_tasks / publish_jobs / attempts /
    traces; lease / LeaseFromParked (strict CAS) / Park / Extend /
    Complete / ReconcileTask / WebCancel queries; RabbitMQ fanout +
    Redis presence + offline→online reclaim; 11-case lease protocol
    integration suite.
  - Phase A.2 Electron desktop-client runtime with modules:
    session-registry, view-pool (hot/cold), vault + vault-export,
    lease-manager, rate-limiter, keep-alive, circuit-breaker,
    crash-recovery, api-client, sse-client, tracing (Alpha scope).
  - Phase A.3 packages/ui-shared H1: design tokens (CSS vars +
    AntD theme light/dark); useAccountSelection composable;
    MarkdownPreview / AccountCard / TagMultiSelect / HealthBadge /
    useSseSubscription components; admin-web no-regress integration.
  - Phase A.4 Doubao monitor adapter based on A.0 matrix.
  - Phase A.5 Toutiao publish adapter with manual parked recovery.
  - Phase A.6 PublishArticleModal H2 rewrite (account-level
    multi-select on useAccountSelection; SSE progress panel; deep
    link for manual review).
  - Phase A.7 fake server + fake platforms + Playwright _electron
    E2E + Mac notarization CI + autoUpdater unit tests.
  - Phase A.8 exit-bar: real-account smoke playbook + chaos test
    (multi-instance SSE routing / parked survival across restarts)
    + plan-a-complete tag.

Plan 0 must complete and tag `plan-0-complete` before Plan A starts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 23:47:13 +08:00
root e2f26b7468 docs(desktop-client): spec v2.5 closes 5 contract gaps from round-5 review
Fifth-round codex+gemini final verification: Gemini gave Ready-to-plan;
codex gave Ready-with-caveats with 5 surgical contract gaps. All 5
closed in v2.5:

1. reconcile status=retry semantics pinned: original task returns to
   queued with attempts+1, no cloning, no new job. §6.4 route note,
   §7.5 UNKNOWN reconcile table (renamed from "重新创建任务" to "重新
   运行"), and §15.1 Mermaid all agree.
2. content_ref workspace boundary rule (Phase 1): tenant-native
   entities (article_draft/template_gen/video/brand_asset) must
   belong to actor's primary workspace, otherwise 422. Added to
   Plan 0 cross-workspace pentration test exit bar.
3. WorkspaceScope input surface unified: removed workspace_id= query
   from §6.8.2 modal example; scope solely derived from Actor.
4. Contract drift cleanup: GET /api/desktop/accounts?client=self
   return fields add delete_requested_at; retry path clarified to
   JSON body.
5. Parked Web cancel endpoint: new POST /api/tenant/tasks/{id}/cancel
   (WorkspaceScope) for aborting parked/queued tasks; §15.1 Mermaid
   updated with queued→aborted edge and endpoint labels.

Header upgraded to v2.5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 23:32:03 +08:00
root 256f507bff docs(desktop-client): spec v2.3 from architect-level review
Fourth-round Claude+Codex+Gemini architect review produced 1C + 7W
issues. All applied:

Plan 0 scope lock-in (Codex C1 Partial → Closed):
- §12 Plan 0 explicitly adopts narrow-workspace Phase 1 strategy:
  workspace first-class ONLY on desktop_clients / platform_accounts /
  desktop_tasks / desktop_publish_jobs / tenant_monitoring_quotas.
  Existing articles / brands / kol-templates / publish-batches /
  images lines keep tenant==workspace (no multi-workspace UI).
- WorkspaceScope middleware attached to a specific route whitelist only.
- Eight concrete Plan 0 deliverables with three exit-bar categories.

Spec consistency sweep (Codex W3):
- §6.4 idempotency contract rewritten: pause/resume references
  removed; correct new lease ops enumerated (extend/cancel/result/
  park/trace + lease + lease?from_parked).
- §7.5 crash recovery: lease_client_id → target_client_id (the former
  never existed after the v2.2 schema restructure).
- §6.6 platform_accounts DDL gains delete_requested_at column so
  §6.8.6 two-phase delete protocol actually has its storage.
- §6.4 routes table adds POST /api/tenant/tasks/{id}/reconcile and
  POST /api/tenant/accounts/{id}/request-delete (previously only in
  prose).
- §14 Waiting-user glossary rewritten to reflect parked+CAS model.
- §13 v2.2 changelog annotated with "v2.3+ supersedes".

Parked / reconcile protocol closure (Codex W2 Partial → Closed):
- §5.3 adds Parked Recovery Protocol: strict CAS SQL sketch for
  POST /tasks/{id}/lease?from_parked, five error scenarios with
  client action mapping, idempotent repeat-request rule, and five
  target_client-offline/revoke/swap/72h-timeout strategies with
  a "never auto-rebind" core principle.
- Reconcile moved from /api/desktop/* to /api/tenant/* (Web owns
  reconciliation).
- Parked auto-abort threshold lifted 24h → 72h to avoid weekend
  false-kills.

Mermaid diagrams pulled forward (Gemini W10):
- §15.1 Lease state machine (Mermaid stateDiagram-v2) inlined.
- §15.2 Account CAS + Tombstone resync sequence diagram inlined.
- §15.3 reserves three remaining diagrams for Plan A.

Spike operability (Codex W4):
- §12 Plan A Spike specs owner pair (runtime + provider owner),
  artifact (electron-chromium-cdp-matrix.md with capture/screenshot
  evidence), three-state outcome (supported / degraded / blocked),
  and fallback decision tree for blocked case.

Modal refactor split (Gemini C1):
- §12 Plan A Block H splits into H1 (weeks 1-2: ui-shared skeleton +
  design tokens + useAccountSelection composable + shared components)
  and H2 (weeks 4-5: PublishArticleModal rewrite on top of H1).

Design tokens explicit (Gemini W2):
- H1 now required to produce CSS variables (light/dark) + Ant Design
  Theme Config as first deliverables of ui-shared.

credential_holder DDL promise softened (Codex W3 Partial → Closed):
- §2 hard constraint 9 reverts to naming soft-convention only; DDL
  keeps workspace_id / client_id / target_client_id.
- §11 risk note adjusted.

Header status updated to v2.4. Total effort unchanged at 28-33 weeks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 23:19:49 +08:00
root 70d1d96c57 chore: update .gitignore to include Playwright and log files 2026-04-18 22:13:38 +08:00
root ef978ddbbf docs(desktop-client): spec v2.3 from architect-level review
Third-round Claude+Codex+Gemini architect review surfaced foundation-
level issues that prior local patches missed. Codex verdict was
Needs-rework; Gemini verdict was Ready-with-caveats. v2.3 lands all
2 Critical + 9 Warning + 3 Info.

Critical:
- C1 workspace-as-first-class: Prior drafts added a WorkspaceScope
  middleware, but Codex verified code: Actor/Claims carry only tenant_id,
  cache_support keys scope to tenant, workspaces table migration does
  not exist, tenant_monitoring_quotas tracks primary_installation_id.
  Add a new Plan 0 (Workspace foundation uplift, 2-3w, blocks Plan A)
  covering workspaces + memberships migrations, claims extension,
  cache-key rewrite, and the full monitoring-domain migration checklist
  (new §6.1.1). §2 hard-constraint 8 rewritten; new hard-constraint 9
  reserves credential_holder / account_home naming for future evolution.
- C2 CDP stream-capture path was still inconsistent: Fetch.continueResponse
  + takeResponseBodyAsStream cannot chain per CDP semantics. v2.3 moves
  EventSource to Network.eventSourceMessageReceived, fetch-stream to
  Network.streamResourceContent + dataReceived (Chromium >=120, OK on
  Electron 41), and reserves Fetch only for must-mutate scenarios
  without chained continueResponse. Plan A now requires a provider x
  transport spike matrix (0.5w) before any adapter work.

Warning:
- W1 Patch-channel minimal loop (G1) promoted from Plan C to Plan B,
  so Beta exit criteria are satisfiable.
- W2 waiting_user decoupled from lease: becomes a parked state that
  releases the lease, survives hours of human review, and is resumed
  via POST /tasks/{id}/lease?from_parked=true.
- W3 credential_holder/account_home evolution seam formalized.
- W4 §6.1.1 lists 8 monitoring-domain migration items that were
  previously hidden inside "sqlc rename".
- W5 Deep-link nonce becomes a one-time opaque code bound to
  target_client_id, Redis-jti consumed on verify.
- W6 §10.3 block H raised from 1.5w to 2.5-3w after Gemini verified
  PublishArticleModal's accounts[0] assumption needs a real rewrite.
- W7 MarkdownPreview extracted into packages/ui-shared so Web preview
  and Desktop manual review use the same renderer.
- W8 packages/http-client gains a standardized SseClient (backoff +
  Last-Event-ID + snapshot + dedup), shared by both apps.
- W9 Trace viewer now runs inside a CSP-sandboxed iframe with hash
  routing for file:// loads; trace data flows in via postMessage.

Info:
- I1 §14 adapter map appendix; Hunyuan renamed to Yuanbao with the
  correct entry domain (yuanbao.tencent.com).
- I2 UNKNOWN tasks gain a reconcile workflow (mark-succeeded /
  mark-failed / ignore / recreate), plus weekly in-app nudge.
- I3 New §15 listing the 5 Mermaid diagrams Plan A must produce
  (sequence, lease state machine, account resync, multi-instance
  topology, component tree).

Total effort re-estimated from 24-28w to 28-33w; split expands from
3 plans to 4 (Plan 0 -> A -> B -> C).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 22:12:53 +08:00
root a83faff211 docs(desktop-client): spec v2.2 applies 4C+9W from second cross-review
Second-round Claude+Codex+Gemini cross-review surfaced implementation-
level gaps in the v2.1 admin-web coordination layer. All 4 Critical
and 9 Warning findings addressed:

Critical:
- C1 (multi-account routing): desktop_tasks now has first-class columns
  job_id, target_account_id, target_client_id, platform with indexes;
  new desktop_publish_jobs aggregation table; §6.3 SSE only pushes to
  target_client_id; lease rejects non-target requesters.
- C2 (account consistency): Replace vague "client=SoT, server=projection"
  with CAS + Tombstone protocol. platform_accounts gains sync_version
  and deleted_at; all client writes require if_sync_version CAS; web-side
  delete writes delete_requested_at intent, client resync completes the
  delete via normal DELETE path. Added 3-way merge rules and concurrent
  case table in §6.8.6.
- C3 (/api/tenant/events auth): WorkspaceScope middleware required
  (TenantScope insufficient); topics must be server-derived from
  actor+workspace, never accept free query params; symmetric contract
  table between /api/desktop/events and /api/tenant/events (multi-
  instance fanout, Last-Event-ID replay, snapshot first frame, monotonic
  event_id, client dedup).
- C4 (route migration): Full migration map added in §6.8.4 listing
  media/platform-accounts -> accounts, articles/:id/publish-batches ->
  publish-jobs, publish-records -> publish-jobs/{id} subtasks.

Warning:
- Kimi binary-framed gRPC-Web path added to §5.2 transport table;
  login methods (Kimi: wechat/phone; Hunyuan: wechat/qq/email +
  loopback) noted in §4.4.
- Offline->online dual-sided reclaim: server scans queued tasks and
  re-pushes task_available; client heartbeats+resyncs then enters
  lease(limit=20) loop until empty.
- GET /api/desktop/accounts?client=self added to §6.4 for resync.
- Account.tags added; Modal gains tag multiselect + search + three-
  level batch select.
- §6.8.5 exposes queue_ahead + eta_seconds for capacity feedback.
- Deep link gains intermediate-state modal + manual-launch/copy
  fallbacks + one-time nonce JWT on tasks/<id>/review; Windows/mac/
  Linux protocol registration specified.
- content_ref is now polymorphic {type, id} supporting article_draft /
  template_gen / video / brand_asset.
- retry endpoint accepts JSON body, not query string.

Info: §10.3 title corrected to 9 blocks; §12 opening synced to 24-28
weeks; §6.8.3 adds "attention-needed accounts" card + per-platform
summary; monitoring LLM UI switched to Grid/Tag responsive layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:48:02 +08:00
root c41222706b docs(desktop-client): spec v2.1 adds admin-web coordination + 2 LLMs
User feedback integrated:

- LLM monitoring scope: 3 → 5 providers (add Hunyuan + Kimi).
  Keep-alive table in §4.4 gets 2 rows (default 8 min heartbeat,
  re-evaluate on integration). Block B effort 2-3w → 4-5w; total
  22-26w → 24-28w; Plan B scope updated.
- New §6.8 "admin-web coordination" covering:
  - Publish modal with *account-level* selection (not platform-level):
    one workspace has many accounts per platform (e.g., 5 WeChat);
    one job expands to N desktop_tasks each bound to (platform, account).
  - Media data dashboards at account-level granularity (overview,
    publish history, monitoring results).
  - New /api/tenant/* aggregation + SSE event bus (separate channel
    from /api/desktop/events).
  - Offline degradation UX when client(s) are offline.
  - Account data consistency: client is SoT for account existence,
    server stores projection; startup resync on upsert/delete.
  - georankly:// deep links with installed-client detection fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:22:38 +08:00
root 2e1a5900ea docs(desktop-client): revise spec v2 with triple-review fixes
Address 6 Critical + 10 Warning findings from Claude + Codex + Gemini
cross-review:

- C1 Replace Network.responseReceivedExtraInfo path with EventSource /
  Fetch.takeResponseBodyAsStream routing per transport type; add
  Electron-Chromium CDP compatibility matrix commitment.
- C2 Default patch channel to pure-data DSL (no JS exec); executable
  fallback gated on utilityProcess + isolated-vm sandbox with frozen
  globals. Full TUF-style signing chain (patch_seq, hash, expires_at,
  key_id rotation, revokes, runtime hash re-verify).
- C3 Add RabbitMQ task_available fanout + Redis presence registry;
  SSE only pushes signals, task ownership decided atomically by
  lease endpoint.
- C4 platform_accounts gains platform_uid + account_fingerprint +
  UNIQUE(platform, platform_uid) enforcing workspace-exclusive
  binding in DB, not by client discipline.
- C5 Task protocol adds attempt_id + lease_token with
  extend/pause/resume/cancel endpoints; manual mode enters
  waiting_user status with extended lease; 409 on stale lease_token.
- C6 Rewrite scope estimate with 7 detect-only publish adapters and
  DeepSeek monitor placeholder called out explicitly; reshape as
  9-bucket 22-26 week effort; introduce Plan A/B/C split.

Warnings addressed: BrowserView->WebContentsView everywhere;
allowDowngrade spelling fix; client_token decoupled from
client_version with rotate/revoke APIs; safeStorage Linux
basic_text guard + separate vault-export for machine migration;
keep-alive token bucket + 429 backoff + resume warm-up;
packages/ui-shared carve-out (no admin-web cloning); state machine
gets failed/aborted/unknown terminal states; sqlc regeneration
footprint made explicit; crash recovery split by task.kind;
autoUpdater unit tests + pre-release smoke; trace phased
(Alpha=logs+shots, Phase 2=Playwright-compat export).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:05:41 +08:00
root 63667ed2d1 feat(membership): enforce tenant subscription plans with blocked UI
Add configurable membership plans (free/plus/pro) synced to DB on boot, a
subscription guard middleware that blocks tenant endpoints on expired or
missing plans, and a MembershipBlockedView that surfaces the reason so
the admin can contact the tenant owner. Quota and brand-library reads now
honor the active plan's policy JSON and expired subscriptions.
2026-04-18 20:56:05 +08:00
root 9ec9314aea docs(desktop-client): add Electron 桌面客户端 replacement design spec
Captures the full plan for replacing apps/browser-extension with an
Electron tray client: single main process with multi-session isolation,
embedded web-view login with OS-encrypted local cookie vault, CDP-based
LLM monitoring (no official APIs, cost-driven), unified PublishAdapter
and MonitorAdapter interfaces with dual-track updates (per-adapter patch
channel + full release channel), Playwright-grade tracing, new
/api/desktop/* protocol with SSE + 60s pull, and 5-arch multi-OS
packaging strategy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 20:28:42 +08:00
root 6e77f72c53 feat(kol): return to source page after generation and poll while busy
- Add a ?source=workspace|templates query param when opening the
  generate page so the back button and the post-submit redirect return
  to the originating page; invalidate articles + workspace caches on
  success so the new article shows up immediately.
- Poll recent articles every 10s in WorkspaceView and TemplatesView
  while any article is in queued/pending/generating/running, and stop
  the timer once nothing is active.
- Mark the new article as generating inside the generation Submit
  transaction so the client sees the right status as soon as the task
  is queued.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:17:17 +08:00
root fe4a4ffeaa feat(kol): enrich assist generate with URL references and template prompt
- Add kolAssistURLResolver that fetches reference articles via the Ark
  URL extractor when the user's description contains http(s) links, and
  merges up to kolAssistReferenceContentMaxRunes of extracted content
  into the generate description.
- Rewrite the generate user prompt into a strict template-authoring
  brief: output only the final prompt template in Chinese, parameterize
  variable info as {{placeholder}}, require at least 3 placeholders
  when references exist, and cover goal/topic/title/structure/style/
  interaction/constraints.
- Wire LLMConfig and logger through NewKolAssistService and the
  handler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:17:07 +08:00
root 052bf38dc4 feat(observability): enrich request logs with auth and knowledge context
- Collect per-request auth diagnostics (header presence, scheme, token
  fingerprint, failure stage/reason, subject, expiry) in the auth
  middleware and expose them through RequestLogContextFromGin so the
  shared logger middleware can emit them.
- Add route, query, user-agent, and referer fields to the request log.
- Log knowledge resolve outcome per stage (no_search_points,
  no_candidate_text, no_active_candidates, rerank_failed_fallback,
  resolved) with candidate/selected snippet previews and precise facts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:16:57 +08:00
root 4bbce5f083 feat(kol): add SSE streaming for prompt assist
- Extract assist runtime (prompt building, response parsing, finalize)
  from the worker into kol_assist_runtime so the sync streaming path
  and the async task path share the same logic.
- Add POST /kol/manage/assist/stream as a Server-Sent Events endpoint
  emitting start/delta/completed/error events, and wire it to a
  streamAssist helper on kolManageApi that reports ApiClientError with
  the server's error envelope.
- Stream generated content live in KolPromptEditor and KolGenerateView,
  switching KolPromptEditArea to a boolean aiBusy flag and refining the
  generator page layout.
- Add KolAssistStreamEvent to shared types.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 16:17:11 +08:00
root 79c65c1da7 feat(kol): expand variable schema and polish KOL UI
- Add length/range limits to KOL variable definitions: max_length and
  default_value for input/textarea, min_value/max_value/default_number
  for number. Backend validates and normalizes; frontend renders limit
  inputs in KolVariableConfig and applies limits at runtime in
  KolDynamicForm.
- Sort workspace cards by most recent prompt/package update, falling
  back to granted_at. Adds updated_at to KolWorkspaceCard.
- Polish TemplatesView, WorkspaceView, and KOL package management UI;
  route create/update/publish/archive/delete toasts through i18n and
  expand package form copy and status labels.
- Remove stale KnowledgeView.vue.patch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:01:40 +08:00
root 1dd316a34b feat(kol-web): add /kol/profile page with nav entry 2026-04-18 14:10:27 +08:00
root 4ac7339c2d feat(kol-web): add KolPersonaCard with inline editing 2026-04-18 14:09:20 +08:00
root 4026aa7dad feat(kol-web): add i18n keys for KOL profile page 2026-04-18 14:08:22 +08:00
root ccf7f8080b feat(kol-web): add updateProfile and uploadAvatar to kolManageApi 2026-04-18 14:07:01 +08:00
root d2922478ed feat(kol): expose PUT /kol/manage/profile and POST /kol/manage/profile/avatar 2026-04-18 14:06:20 +08:00
root 1393b25419 feat(kol): add avatar upload to KolProfileService 2026-04-18 14:05:09 +08:00
root 0e3515530f feat(kol): add KolProfileService.UpdateProfile 2026-04-18 14:03:49 +08:00