Commit Graph

462 Commits

Author SHA1 Message Date
root eda90ea1e4 fix(admin-web): make article copy robust
Frontend CI / Frontend (push) Successful in 2m54s
2026-05-20 17:00:57 +08:00
root 6359a2ddd3 feat(workbench): implement workbench window management and navigation state
Deployment Config CI / Deployment Config (push) Successful in 24s
Desktop Client Build / Resolve Build Metadata (push) Successful in 39s
Frontend CI / Frontend (push) Successful in 3m3s
Backend CI / Backend (push) Successful in 16m18s
Desktop Client Build / Build Desktop Client (push) Successful in 24m1s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 35s
2026-05-20 15:44:26 +08:00
root dd082e2ed1 feat: scope articles by brand 2026-05-20 15:37:25 +08:00
root 5fb9d0b0dd perf(scheduler): harden jobs for scalable execution 2026-05-20 12:19:27 +08:00
root 4b09a34748 refactor(knowledge): migrate deleted-item cleanup from polling scheduler to event-driven worker
Replaces the scheduler-polled KnowledgeDeletedCleanupWorker with an
event-driven KnowledgeDeletedCleanupEventWorker in tenant-api; cleanup
events are now enqueued transactionally at delete time instead of swept
periodically. Also fixes statement_timeout parameterization in
MonitoringRetentionWorker and propagates errors from cleanupDeletedKnowledgeItem.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 11:22:37 +08:00
root e82ae56236 feat: add ops scheduler control center 2026-05-20 10:46:49 +08:00
root 98f73c5bea feat(objectstorage): add Aliyun OSS support and auto-detect provider in deploy workflows
Introduces Aliyun OSS as an alternative to MinIO; deploy scripts and CI
workflows now read object_storage.provider from config and conditionally
include or skip MinIO resources in both Docker Compose and k3s paths.
Also adds ops scheduler domain and its migration tables.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 10:25:02 +08:00
root 00eb514efc feat(imitation): simplify form fields and make brand_name required
Deployment Config CI / Deployment Config (push) Successful in 25s
Frontend CI / Frontend (push) Successful in 2m51s
Backend CI / Backend (push) Successful in 14m47s
Remove industry, target_audience, content_goal, tone, and length_goal from the imitation form; brand_name is now mandatory with autocomplete from brand library, keywords are pre-populated from the selected brand's search keywords, and output length is hardcoded to ~2000 characters in the prompt.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 02:16:45 +08:00
root c44ddc55a6 feat(doc):add command docx to docs
Deployment Config CI / Deployment Config (push) Successful in 27s
Frontend CI / Frontend (push) Successful in 2m28s
Backend CI / Backend (push) Successful in 15m2s
2026-05-20 01:28:42 +08:00
root c89cad6643 feat(keywords): rename brand-question terminology to search-keyword + add entity exclusion
- Rename UI/prompt labels: "品牌主问题" → "优化关键词", "搜索问题" → "搜索词"
- Add brand/competitor entity exclusion filter in question expansion (AI distill path)
- Refactor combination question text normalization, remove manual question-mark appending
- Update prompts to emphasize commercial-intent search queries over editorial phrasing
- Sync prompt changes across server/configs, deploy, and k3s configs
- Update i18n, frontend views (BrandQuestionCreate, TemplateWizard), and test fixtures

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 01:27:14 +08:00
root 28633cf570 feat(monitoring): fail same-client queued tasks on desktop authorization failure
Desktop Client Build / Resolve Build Metadata (push) Successful in 44s
Backend CI / Backend (push) Successful in 17m5s
Desktop Client Build / Build Desktop Client (push) Successful in 25m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 42s
When a desktop monitoring task fails with a non-retryable authorization failure
(login expired, challenge required, risk control), all pending same-client/same-platform
tasks for the same business day are immediately bulk-failed as non-retryable, avoiding
wasted execution attempts. Adds preflight authorization checks before task execution,
enriches failure payloads with disposition metadata (code, category, retryable flags),
and triggers account health reports on auth state degradation.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 23:50:50 +08:00
root 5bbbbc5cf1 feat(desktop): remember login credentials
Desktop Client Build / Resolve Build Metadata (push) Successful in 49s
Frontend CI / Frontend (push) Successful in 5m47s
Desktop Client Build / Build Desktop Client (push) Successful in 42m28s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 2m38s
2026-05-14 21:49:27 +08:00
root 639516f374 fix desktop account status display 2026-05-14 21:43:25 +08:00
root 75b407ec6b fix free create clipboard copy 2026-05-14 21:20:15 +08:00
root 765dae4bf1 fix task article link drawer
Frontend CI / Frontend (push) Successful in 5m6s
Backend CI / Backend (push) Successful in 16m45s
2026-05-14 21:14:27 +08:00
root 34dda524d7 fix(admin-web): use verb form for schedule action tooltip
Frontend CI / Frontend (push) Successful in 3m34s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 13:23:41 +08:00
root 01dbb9c8d3 fix(styles): increase z-index for message and notification components
Deployment Config CI / Deployment Config (push) Successful in 13s
Frontend CI / Frontend (push) Successful in 3m38s
2026-05-14 13:16:47 +08:00
root 09e3db5b34 fix(web): self-heal SPA chunk 404 after deploys
Frontend CI / Frontend (push) Has been cancelled
Port admin-web's chunk-reload guard to ops-web (vite:preloadError +
router.onError) so a stale tab landing on a lazy-loaded route triggers
a single reload instead of a hard 404. Also force index.html through
revalidation on both apps so the reload actually fetches a fresh entry
referencing the new chunk hashes; hashed asset URLs keep their long
immutable cache.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 13:12:42 +08:00
root b939cfa2fa feat(auth): support per-deploy login password key override
Deployment Config CI / Deployment Config (push) Successful in 27s
Backend CI / Backend (push) Successful in 15m4s
Multi-replica deployments need every Pod/container to share one RSA private key, otherwise public keys handed to the browser may not match the key that decrypts the resulting ciphertext. Introduce a `*.local.yaml` override layer that ops-config and tenant-config both load on top of the base config, ship example overrides plus compose/k3s wiring, and tolerate PEM bodies that arrive folded or escaped from Secrets.
2026-05-14 11:54:40 +08:00
root 2bc192b3c7 fix(prompts): refine region output guidance for geographic terms
Deployment Config CI / Deployment Config (push) Successful in 27s
Desktop Client Build / Resolve Build Metadata (push) Successful in 40s
Frontend CI / Frontend (push) Successful in 4m3s
Backend CI / Backend (push) Successful in 16m31s
Desktop Client Build / Build Desktop Client (push) Successful in 26m53s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 53s
2026-05-14 11:16:23 +08:00
root 036377f02e feat(admin-web): add 404 page for unknown routes
Unknown URLs previously rendered a blank page. Add a catch-all route
under AppShell that shows the requested path plus back / workspace
actions, with zh-CN and en-US copy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 11:15:09 +08:00
root 879677516f fix: harden login for MLPS requirements 2026-05-14 11:05:20 +08:00
root ecf3ee1ef0 fix(ci): prune old registry package versions
Deployment Config CI / Deployment Config (push) Successful in 19s
Frontend CI / Frontend (push) Successful in 11m18s
Backend CI / Backend (push) Successful in 17m54s
2026-05-13 23:22:58 +08:00
root b3bd23e238 feat(admin-web): improve responsive admin layout
Frontend CI / Frontend (push) Has been cancelled
2026-05-13 22:29:46 +08:00
root 34ef5873ca feat: load question expansion prompts from yaml
Deployment Config CI / Deployment Config (push) Successful in 27s
Backend CI / Backend (push) Successful in 16m5s
2026-05-13 20:24:51 +08:00
root 8890cd1ca4 style(admin-web): refine edit button hover and card shadow polish
Frontend CI / Frontend (push) Successful in 4m21s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 20:12:36 +08:00
root 887f5b672e chore: update tenant repository generated models
Backend CI / Backend (push) Successful in 17m58s
2026-05-13 19:54:23 +08:00
root 0823e47d46 feat: tighten desktop presence loop and refine admin-web UX
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m46s
Backend CI / Backend (push) Failing after 7m52s
Desktop Client Build / Build Desktop Client (push) Successful in 27m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 59s
- Shrink desktop presence TTL to 30s and heartbeat to 15s so unexpected
  client exits surface within one TTL even if the explicit offline call
  is missed; keep migration default aligned.
- Trust a known presence miss in resolveDesktopClientOnline instead of
  falling back to the recent-heartbeat heuristic, so a still-cached
  LastSeenAt cannot mask an offline client.
- Release the runtime session before clearing renderer desktop sessions
  on shutdown to avoid leaving stale leases behind.
- Auto-refresh the MediaView account list every 5s and revamp card
  layout (inline platform badge, status tags, UID row, meta box).
- Let the brand-question AI wizard accept multiple seed topics via a
  tag-style input; candidates from each topic are merged and deduped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 19:36:24 +08:00
root 18cdbf25f8 fix: harden competitor create and batch kol stats
Backend CI / Backend (push) Failing after 6m48s
2026-05-13 17:31:22 +08:00
root 7aa786fbf4 feat(template-wizard): enhance competitor management and update UI messages
Frontend CI / Frontend (push) Successful in 3m27s
2026-05-13 17:10:31 +08:00
root 1eae6fb6d4 feat(questions): make brand questions the primary monitoring & template axis
Deployment Config CI / Deployment Config (push) Successful in 29s
Frontend CI / Frontend (push) Successful in 4m4s
Backend CI / Backend (push) Failing after 7m12s
- add /questions/combination-fill endpoint with AI-driven, IP-region-aware matrix fill
- extract ip2region resolver from ops/app into shared/ipregion for cross-service use
- thread question_id filter through dashboard composite, citation summary, and collect-now
- switch template wizard from keyword inputs to brand-question selection (primary + supplemental)
- pass brand_question and supplemental_questions through assist/title/outline prompts
- add AiWaitingModal + 45s client timeout and request_timeout error mapping for long AI flows

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 15:59:39 +08:00
root 37b0b32327 feat(admin-brand): add question expansion service and related functionality
- Implemented QuestionExpansionService for generating and materializing questions based on combinations and AI distillation.
- Added question metadata classification logic to infer intent and layer of questions.
- Created API handlers for question expansion operations including combination preview, AI distillation, metadata classification, and materialization.
- Introduced database migrations to support new question-related fields and constraints in brand_questions and brand_keywords tables.
- Added caching mechanism for AI distillation results to improve performance.
- Defined JSON schemas for question distillation responses to ensure data integrity.
2026-05-12 21:53:36 +08:00
root 77d542c282 feat(server): make tenant login guard toggleable via config
Frontend CI / Frontend (push) Successful in 3m38s
Backend CI / Backend (push) Successful in 14m43s
Add auth.login_guard.enabled config (default on) so the tenant login
brute-force / rate-limit guard can be disabled per environment.
Surfaces an AUTH_LOGIN_GUARD_ENABLED env override and a startup warning
when disabled. Wired through Diff() so hot reload picks up changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:32:39 +08:00
root 77f3e5ee99 perf(admin-web): relax template wizard assist poll cadence to 3s
Polling analyze/title/outline task results every 1.2s was over-eager
for AI tasks that typically run 15-30s. Bump interval to 3s and lower
max attempts to 40, extending total timeout from 72s to 120s while
roughly halving request volume.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:32:06 +08:00
root 01fa2b8309 fix quota reset reservation race
Desktop Client Build / Resolve Build Metadata (push) Successful in 28s
Frontend CI / Frontend (push) Successful in 3m57s
Backend CI / Backend (push) Successful in 17m3s
Desktop Client Build / Build Desktop Client (push) Successful in 26m8s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 51s
2026-05-12 02:24:57 +08:00
root 1aad002a3e feat(ops): use 'reset' quota status for plan-usage reset and invalidate quota cache
When ops staff reset a tenant's current-plan usage, the existing
'refunded' terminal status conflated user-initiated refunds with
ops-driven resets, and tenants still saw the old balance in the top-nav
chip until the quota-summary cache TTL expired.

- Introduce a dedicated 'reset' status for quota_reservations, separate
  from 'refunded'. Both the initial and an incremental migration widen
  the CHECK constraint to allow it; the down migration folds 'reset'
  rows back into 'refunded' before tightening the constraint.
- resetQuotaReservations / resetAIPointReservations now write 'reset'
  without touching refunded_amount, and stop cascading into
  ai_point_usage_logs (carried no audit value for ops resets).
- AdminUserService gains an optional cache dependency and calls
  invalidateQuotaSummaryCache(tenant_id) immediately after a successful
  reset so the tenant's top-nav chip refreshes on the next request
  without waiting on TTL.
- Wire the existing appCache into AdminUserService at boot.
- Drop the now-unused ai_point_usage_logs field from the reset response
  and from the ops-web AdminUsersView type.
- Add a unit test covering the cache-key invalidation contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:55:29 +08:00
root 51d32fa96d fix(admin-web): invalidate workspace cache after every AI-points-consuming call
Top-nav quota chip (会员到期 / 生成文章 / AI 点数) only refreshes when its
query is invalidated. Several mutations and stream-based flows that debit
points or article quota on the server were not invalidating it, so users
had to refresh the page to see updated balances.

- TemplateWizardView: invalidate `['workspace']` inside `endAssistTask()`,
  covering analyze / title / outline assist tasks in one place.
- FreeCreateView: invalidate after `articlesApi.create` success.
- GenerateTaskDrawer: add `['workspace']` to the instant-generate
  `Promise.all` alongside the existing `articles` / `instantTasks` keys.
- KolPromptEditor: invalidate in the `finally` of both `runAiAssistStream`
  (generate) and `generateSelectionAiPreview` (optimize) so abort / error
  paths also refresh.
- ArticleEditorCanvas: bring in `useQueryClient` and invalidate in the
  selection-optimize stream `finally`.

Together with the existing invalidations in TemplateWizard.generate,
ImitationGenerate, KolGenerate, and article-regenerate, every quota-
debiting call site now feeds the cache refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:54:12 +08:00
root 793c310560 refactor(desktop-client): harden external-window load flow with loading page and timeout watchdog
- Introduce `navigateRemoteURL` / `showLocalPage` / `showErrorPage` helpers
  that centralize remote navigation, watchdog wiring, and error fallback,
  replacing the ad-hoc logic inside `loadWindowURLSafely`.
- Show a localized loading page (`loadingPageDataURL`) while a remote URL
  is fetching, so the window no longer sits on blank white during slow
  navigations.
- Add a 25s remote-load timeout watchdog that switches the window to the
  error page when the target never finishes loading, plus an active load
  token so stale watchdogs from earlier navigations cannot fire on the
  current attempt.
- Track `localPageKind` and `activeTargetURL` per window so blank-page
  retries, did-fail-load handlers, and ready-for-detection checks behave
  correctly when the window is currently showing a local loading/error
  page.
- Escalate the blank-page watchdog: after the retry attempt, if the page
  is still blank, surface the error page instead of looping silent
  reloads.
- Restyle the error page (drop gradients, use a neutral light/dark token
  palette, single primary retry button) and add a dedicated loading page
  template with the same look.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:31:50 +08:00
root b6cc12cefe feat(admin-web): show centered modal in Chinese when AI points are insufficient
- Add `ai_points_insufficient` / `ai_points_unavailable` Chinese mappings in
  errors.ts so the toast copy is localized.
- Add `showAiPointsInsufficientModal()` helper that renders a centered
  `Modal.confirm` with localized title/body and a "查看点数明细" action that
  routes to `/account/ai-points`. The helper is debounced so concurrent
  failed requests do not stack multiple modals.
- Trigger the modal globally from the admin-web response interceptor when
  the backend returns `ai_points_insufficient`, so every AI-generating
  endpoint surfaces the same prominent prompt without per-callsite changes.
- Drop the English `detail` for ai_points_insufficient in `formatError` so
  the secondary toast stays pure Chinese.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:31:02 +08:00
root 635782041a feat(admin-web): preserve template wizard entry source and refresh AI banner
- Carry `from=workspace` query from the workbench into the wizard so cancel
  and post-generate redirects return to the workbench instead of always
  landing on /articles/templates.
- AppShell now resolves an effective navKey from `route.query.from`, so the
  sidebar highlight and breadcrumb track the entry source while inside the
  wizard.
- Redesign the brand-info AI analyze CTA into a standalone banner with
  template-aware copy (default / product_review / research_report) and add
  the matching i18n keys.
- Drop the unused 批量生成文章 button and its styling from the templates
  page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:12:01 +08:00
root f06c8dfc01 fix(knowledge): always retry source fetch via lightpanda on trigger status
Backend CI / Backend (push) Successful in 15m15s
LinkReader 500 (or other trigger_status) used to be gated by an extra
allowed_domains whitelist on the tenant API side, so URLs like
m.baidu.com/bh/m/detail/... fell straight through to the user with a raw
"webpage parser failed" message. Drop the whitelist gate — enabled +
trigger_status is enough — and surface a friendly Chinese prompt when
both LinkReader and the lightpanda fallback give up. Full error chain
is kept in the logger for debugging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 19:48:21 +08:00
root 83c5cc76d6 feat(bilibili): enhance article submission process and error handling
Desktop Client Build / Resolve Build Metadata (push) Successful in 29s
Frontend CI / Frontend (push) Successful in 5m28s
Desktop Client Build / Build Desktop Client (push) Successful in 26m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 39s
2026-05-11 19:37:14 +08:00
root 18011a7892 fix(admin-web): auto-reload on stale dynamic-import chunks after deploy
Listen for vite:preloadError and router onError, force a one-shot reload
(10s cooldown via sessionStorage) when a hashed lazy-loaded module 404s
because a new deploy replaced it. Eliminates the user-visible "Failed to
fetch dynamically imported module" error on login and route navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:47:51 +08:00
root c16a684add fix(browser-fetch): allow baidu source fallback
Deployment Config CI / Deployment Config (push) Successful in 1m35s
Backend CI / Backend (push) Successful in 17m20s
2026-05-11 14:30:58 +08:00
root 2113bcb601 ci(browser-fetch): include browser-fetch image in build and deploy pipelines
Backend CI / Backend (push) Successful in 14m25s
Add browser-fetch to backend-ci image list, NAS compose/K3s deploy options
and rollout loops, and the offline package bundle so the new service ships
through the same pipelines as the rest of the backend.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:58:48 +08:00
root 3d396e4ac8 fix(docker-compose): update healthcheck command syntax for service
Deployment Config CI / Deployment Config (push) Successful in 12s
2026-05-11 12:37:08 +08:00
root 6b177be6fd chore(browser-fetch): enable lightpanda by default and widen allowlist
Deployment Config CI / Deployment Config (push) Failing after 10s
Desktop Client Build / Resolve Build Metadata (push) Successful in 25s
Frontend CI / Frontend (push) Successful in 3m38s
Backend CI / Backend (push) Successful in 16m45s
Desktop Client Build / Build Desktop Client (push) Successful in 26m27s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 39s
Turn the lightpanda-backed fetch service on, bump worker concurrency to
3, and add baidu.com plus weixin.sogou.com to the allowed domains so the
knowledge URL fallback can resolve those sources without a config edit.
2026-05-11 12:27:13 +08:00
root 8c0fbc8ffa fix(desktop-task): drop LEFT JOIN in lease query so FOR UPDATE locks only desktop_tasks
Postgres rejects FOR UPDATE on the nullable side of a LEFT JOIN, which
made LeaseNextQueuedDesktopTask fail under contention. Replace the join
with a NOT EXISTS subquery, scope the row lock to the dt alias, and add
a regression test plus warn-level logging on lease query failures so
similar issues are easier to diagnose.
2026-05-11 12:26:54 +08:00
root 6fa9a6c052 feat(dongchedi): translate platform "server exception" into actionable copy
Map dongchedi adapter failures (raw "server exception" or
dongchedi_platform_exception) to a Chinese prompt steering the user to
the dongchedi backend, so renderer/admin views and desktop-task error
payloads no longer surface the opaque platform message.
2026-05-11 12:26:38 +08:00
root f34c6f2ceb feat(admin-web): surface generation error message and speed up active polling
Hoists hasActiveGenerationStatus into the shared display helper so all
views agree on what counts as in-flight generation, shows the backend
generation_error_message inline on the imitation list and detail drawer
when status is failed, and drops the workspace/templates/imitation poll
interval from 10s to 3s (with a 5s fallback when streaming is enabled)
plus explicit query-cache invalidation so failed/completed states show
up promptly.
2026-05-11 11:11:40 +08:00