- Implemented a new BrandAssetCleanupWorker to handle the cleanup of brand-related assets after a brand is deleted.
- Added SQL queries for cleaning up articles, keywords, questions, competitors, and monitoring data associated with a brand.
- Introduced a new API endpoint to delete publish records.
- Updated the router to include the new delete publish record endpoint.
- Added tests for the BrandAssetCleanupWorker to ensure proper functionality.
- Created migration scripts to support soft deletion of publish records and to add the brand asset cleanup scheduler job.
Make GET /api/tenant/brands/:id/questions return a paginated
QuestionListResponse (items/total/page/page_size) with optional `q`
full-text filter, validated page/page_size query params, and per-params
cache keys. Add a usePaginatedBrandQuestions composable backing the
imitation, template-wizard, and tracking question selects with
search-as-you-type and infinite scroll, plus ensure-loaded-by-id so a
deep-linked or pre-selected question is fetched even when off the first
page. Brands view now drives its questions table via server pagination.
Also redesign the Tracking hot-questions and cited-articles lists
(mention-rate badges/bars, metric groups, refreshed styling) and fall
back to citation-fact article_id/title when no high-confidence URL alias
matches, so cited articles surface even without an alias row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a cover mode to schedule tasks so auto-publish can pick a random cover
image instead of a fixed one, scoped to all images or a specific folder.
- migration: add cover_mode / cover_random_scope / cover_random_folder_id
columns and check constraints on schedule_tasks
- backend: validate cover mode/scope/folder on create & update; the dispatch
worker resolves a random active image (signed asset URL) at enqueue time
- frontend: new CoverSourceSelector component wired into GenerateTaskDrawer
and PublishArticleModal, plus coverSource i18n strings
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add scripts/bump-version.cjs and run it ahead of package:mac/win/linux
so every build gets a fresh patch version. Supports DESKTOP_VERSION for
an explicit version, or major/minor/patch via argument or
DESKTOP_VERSION_BUMP. Version moves 0.1.0 -> 0.1.1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The chunked upload complete request used the global 30s axios timeout,
but the server merges chunks, hashes the file and writes ~100MB to OSS
in that step, so large installers failed with "timeout of 30000ms
exceeded" after all chunks were uploaded.
- give the complete request a dedicated 10min timeout
- let http.post pass through an AxiosRequestConfig
- normalize client-side timeout errors to "request_timeout"
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Challenge detection previously regex-matched the entire page innerText, so
chat transcripts or console copy containing words like 验证码/安全验证/verify
flagged healthy accounts as challenge_required. Detection is now scoped to
real evidence only (visible captcha vendor widgets, short modal copy, sparse
interstitial pages) via a shared challenge-signals module used by the generic
AI probe, doubao/kimi/qwen auth rules, and the deepseek runtime snapshot.
Platform API error codes (e.g. baijiahao_challenge_required) keep working.
Account health also could not recover after lid-close sleep or a network
drop: offline probes misread cached console pages as expired, and expired
records null out nextProbeAt so they were never re-probed. Probing is now
skipped while offline (network_error backoff instead), and powerMonitor
resume/unlock plus an offline-to-online transition watch schedule jittered
recovery probes for all tracked accounts, including expired ones. Challenge
rechecks wait 8s so transient widgets during page load no longer stick.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add WordPress as an enterprise-site CMS type alongside pbootcms, and let
schedule tasks auto-publish generated articles to enterprise sites.
- WordPress connection/publisher service and tests; register wordpress
media platform and relax cms_type CHECK constraint
- New publish_enterprise_site_targets JSONB column on schedule_tasks with
array type constraint; thread targets through scheduler dispatch,
prompt/KOL generation, and worker
- Admin UI: enterprise-site targets in generate/schedule/publish flows,
KOL package form, MediaView, and i18n strings
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge the standalone enterprise-panel intro into the connector panel
header on the tenant media view: move the "新增站点" action into the
panel head, retitle the panel to 企业自建站点, and refresh the
description copy. Presentation-only restructuring; no logic affected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply repo-wide Prettier/lint normalization across admin-web,
desktop-client and ops-web: single quotes, no semicolons, trailing
commas, consistent line wrapping, and import ordering. Also drop an
unused brand-logo import in DesktopShell.vue.
No behavior changes — formatting only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add GET /api/tenant/publish-records: brand-scoped paginated list that merges
in-flight (queued/publishing) records ahead of history (success/failed/cancelled),
enriched with article title and latest desktop task id; wire up
service/handler/router/swagger/router_test
- Rework PublishManagementView to consume publish-records instead of desktop
publish tasks; add publishRecordsApi + shared-types
(ListPublishRecordsParams, PublishRecordListResponse)
- Enterprise site Update: distinguish explicit null from missing PATCH fields via
EnterpriseSitePatchString, dedup site_url before write, verify RowsAffected,
and map unique-constraint violations to a clear conflict
- MediaView: enterprise site edit/delete flows with favicon fallback handling
- Localize enterprise site / PBootCMS error messages to Chinese across the
backend and the admin-web error map, plus legacy raw-message translation
- deploy: gate migration-coupled service rollouts behind RUN_MIGRATIONS unless
ALLOW_SKIP_MIGRATIONS_FOR_APP_ROLLOUT=true; handle empty SERVICES safely
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added new fields to DesktopAccountInfo for tracking account session and task consumer online status, along with queued publish task count and oldest queued publish task timestamp.
- Updated DesktopDispatchEvent to include server time for better synchronization.
- Implemented separate presence management for task consumers, including marking presence and loading presence state.
- Enhanced DesktopAccountService to apply publish queue summaries and manage task consumer presence.
- Introduced new methods for replaying queued publish tasks in DesktopDispatchHandler.
- Updated tests to cover new presence management logic and ensure correct behavior of account session and task consumer online status.
Add a resource cache sync entrypoint (RunMediaResourceSyncOnce) driven
by the new scheduler job, and rework the backlink/sync worker around it.
Tune the meijiequan client and slow the default backlink sync interval
from 10m to 30m to reduce upstream pressure.
Trim unused public/transport surface (handler + router + swagger) and
simplify admin-web order management and ops-web media-supply views,
dropping stale shared-types fields.
- Extend DesktopClientReleaseCheckResponse with platform, arch, and channel fields.
- Introduce DesktopClientDownloadableRelease and DesktopClientDownloadableReleaseListResponse interfaces for managing downloadable releases.
- Implement ListDownloadable method in DesktopClientReleaseService to retrieve downloadable releases based on the specified channel.
- Update DesktopClientReleaseCheckResult to include platform, arch, and channel information.
- Add resolveInstallerDownloadURL method to handle download URL resolution for releases.
- Create new endpoint in DesktopReleaseHandler for listing downloadable releases.
- Update router to include the new downloadable releases route.
- Enhance tests to cover the new functionality for resolving download URLs and listing downloadable releases.
feat(clipboard): implement copyTextToClipboard utility function
feat(desktop): add upload timeout for desktop client release API
feat(k3s): add nginx config and update kustomization for ops-web
The desktop publish queue could stall for a long time and end users assumed
the software was broken. Root cause: a hung adapter held its execution slot
with no wall-clock timeout while auto-renewing its lease forever, so the
server never reclaimed it and every queued task behind it stayed 等待发布.
Auto-recovery also risked silently re-posting a non-idempotent article.
Client (Electron):
- per-task wall-clock deadline + abort; progress-gated lease renewal that
stops and aborts a stalled task instead of renewing it forever
- decouple the concurrency cap from CDP-induced CPU/memory pressure
(admission gate instead of self-throttling collapse); 15s watchdog pump
- all adapter network I/O now has fetch timeouts and honors context.signal;
bounded image-upload concurrency with per-image timeout
- surface live adapter progress, elapsed time, queue position and a
working-vs-queued distinction in the publish view
Server (tenant-api):
- publish lease-recovery worker (every 3m) + supporting index: reclaim
expired in_progress publish leases, requeue (<3 attempts) or terminal-fail
- 3-minute lease TTL with client-presence-gated extension; max 3 attempts
Idempotency (production-grade core):
- durable publish_submit_started_at marker, set before the irreversible
platform submit POST; recovery and abort route a maybe-submitted task to
unknown (manual reconcile, kept in the dedup set) instead of re-posting
- desktop UI requires explicit confirmation before retrying a possibly-
already-published task
Verified: go build/vet/test (incl. resolvePublishRecoveryOutcome), vue-tsc,
vitest 141/141, gofmt all clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce an end-to-end media-supply feature: tenant-side resource sync
service/worker backed by a Meijiequan supplier client, ops-side management
APIs, and admin/ops web views for resources, orders, favorites and
submission. Adds a shared digitocr helper, MediaSupply config blocks for
tenant and ops, shared types, and migrations for supplier media resources,
price overrides, customer visibility and order refunds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consolidate per-platform cover/image fetch failure prompts into a single
PUBLISH_IMAGE_FETCH_FAILED_MESSAGE constant shared by baijiahao, bilibili,
dongchedi, qiehao, smzdm, and zol adapters, and generalize the normalizer
to match any *_image_fetch_failed / *_cover_fetch_failed code. Also split
desktop publish list loading into initial vs manual-refresh states so the
refresh button no longer blanks the table, and fix admin-web active-task
detection to cover all pending statuses.
In the admin publish modal, fetch the article's publish records, disable
accounts that already succeeded for the same article/platform, label
queued/publishing accounts inline, and route the success notification by
created vs existing task counts (with a dedicated warning for the
`desktop_publish_duplicate` server error).
Replace the "再次发送" mutation/popconfirm on both admin and desktop publish
management views with a "重新创建发布任务" action that calls the same Create
endpoint, only enables on failed/aborted/unknown rows, and reports created
vs existing task counts (with a tailored warning for `unknown` results
that may have already succeeded).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add SMZDM to the cover-required platform list on both client and server,
register a 800x800 native cover spec in the admin cover catalog, and
normalize the desktop-client `smzdm_image_fetch_failed` adapter error to a
user-friendly Chinese prompt across the publisher error pipeline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rework the Doubao monitor adapter so success answers come exclusively from
CHUNK_DELTA SSE text and require an SSE_REPLY_END finish event — DOM fallbacks
and FULL_MSG_NOTIFY user echoes can no longer pose as the model reply. Also
auto-switch to the 思考 answer mode, repair mixed-mojibake fragments per run,
unwrap Doubao redirect URLs, scrub "unknown" source metadata, recover from
mid-query navigation by returning unknown for retry, and surface stream/finish
counters in diagnostics.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>