e68db14802
Desktop Client Build / Resolve Build Metadata (push) Successful in 30s
Frontend CI / Frontend (push) Successful in 5m4s
Desktop Client Build / Build Desktop Client (push) Successful in 26m59s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 52s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
80 KiB
80 KiB
Progress Log
Session: 2026-04-30
Phase 37: k3s Deployment Foundation
- Status: complete
- Actions taken:
- Recovered the existing Docker Compose deployment topology and runtime command set.
- Added a self-contained
deploy/k3skustomize deployment with namespace, config, placeholder secrets, infra StatefulSets, app Deployments/Services, migration/minio-init Jobs, and Traefik Ingress. - Included all server-side runtime services:
tenant-api,worker-generate,kol-assist-worker,scheduler,ops-api, plusfrontendandops-web. - Added
Dockerfile.ops-webso the operations frontend can be built as a deployable nginx image. - Updated the offline packaging script to build/save
ops-api,kol-assist-worker, andops-web, and to include the k3s directory in generated deploy packages. - Updated the offline compose override and
.env.examplewith the missing ops/security knobs.
- Files created/modified:
Dockerfile.ops-web(created)deploy/k3s/(created)deploy/docker-compose.yaml(updated)deploy/scripts/package.sh(updated)deploy/docker-compose.offline.yaml(updated)deploy/.env.example(updated)task_plan.md/findings.md/progress.md(updated)
Phase 38: k3s Verification
- Status: complete
- Verification:
kubectl kustomize deploy/k3srendered 30 Kubernetes objects.- Local YAML parsing of the rendered manifest passed.
bash -n deploy/scripts/package.sh && bash -n deploy/scripts/load-and-start.shpassed.git diff --checkpassed.pnpm --filter ops-web buildpassed.pnpm --filter admin-web typecheckpassed.
- Notes:
kubectl apply --dry-run=clientcould not complete locally because the configured kube-apiserver at127.0.0.1:26443is not running; run live API validation on the target k3s node.
Session: 2026-04-20
Phase 20: Tracking Collect-Now Repair
- Status: complete
- Actions taken:
- Re-read the
admin-webtracking page, monitoring API client, and tenant monitoring handler/service chain to isolate why立即采集still depended on the removed browser-plugin runtime. - Confirmed the frontend was still blocking on
monitoring-pluginreadiness and trying to kickoff a plugin cycle even though monitoring collection is now meant to run silently throughdesktop-client. - Added monitoring dashboard runtime state so the page now knows whether the current logged-in user's own desktop client is online.
- Tightened
collect-nowserver validation to only accept requests when the current actor has an online desktop client, instead of falling back to another online client in the same workspace. - Updated
TrackingView.vueto remove the plugin kickoff path, call only the backendcollect-nowendpoint, and disable the CTA with an explicit reason tooltip when brand/keyword/client-online requirements are not met. - Added the missing
desktop_client_offlinefrontend error mapping plus new i18n strings for the button gating reasons.
- Re-read the
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)apps/admin-web/src/views/TrackingView.vue(updated)apps/admin-web/src/i18n/messages/zh-CN.ts(updated)apps/admin-web/src/i18n/messages/en-US.ts(updated)apps/admin-web/src/lib/errors.ts(updated)packages/shared-types/src/index.ts(updated)server/internal/tenant/app/monitoring_service.go(updated)
Phase 15: Desktop Scheduler Design & Integration
- Status: complete
- Actions taken:
- Re-read the planning files and recovered the current desktop AI monitoring scope from the existing repo changes.
- Audited the desktop runtime controller, process metrics sampler, runtime snapshot, session registry, and monitor adapter surface.
- Confirmed the current desktop task executor is global-serial, monitor-task staleness dropping is already implemented, and no durable local queue/cache exists yet.
- Confirmed
playwright-coreis installed butconnectOverCDP()is not wired, while hidden Electron execution already exists viaBrowserWindowandWebContentsView. - Added
monitor-scheduler.tsas a durable file-backed local scheduler for monitor tasks, including same-day persistence, stale cross-day pruning, per-platform mutual exclusion, question-level cooldowns, and lease-miss backoff. - Refactored
runtime-controller.tsso publish tasks keep a conservative explicit queue while monitor tasks are selected through the local scheduler with adaptive max concurrency from Electron process metrics. - Extended runtime diagnostics to surface the monitor scheduler snapshot and made the lease manager track multiple active leases instead of a single global lease placeholder.
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)apps/desktop-client/src/main/monitor-scheduler.ts(created)apps/desktop-client/src/main/runtime-controller.ts(updated)apps/desktop-client/src/main/lease-manager.ts(updated)apps/desktop-client/src/main/runtime-snapshot.ts(updated)
Phase 16: Hidden Playwright CDP Execution Layer
- Status: complete
- Actions taken:
- Added
playwright-cdp.tsas a reusable hidden-browser manager that launches hidden ElectronBrowserWindowinstances on account-bound sessions and attaches Playwright viachromium.connectOverCDP(). - Enabled Electron remote debugging in bootstrap so the app exposes a CDP endpoint for local Playwright attachment.
- Extended adapter context with an optional Playwright
{ browser, page }handle and wired the runtime controller to acquire/release hidden Playwright pages when an adapter declaresexecutionMode: "playwright". - Kept the existing hidden
WebContentsViewpath intact so current adapters like Doubao continue to work unchanged.
- Added
- Files created/modified:
apps/desktop-client/src/main/playwright-cdp.ts(created)apps/desktop-client/src/main/bootstrap.ts(updated)apps/desktop-client/src/main/adapters/base.ts(updated)apps/desktop-client/src/main/runtime-controller.ts(updated)
Phase 17: Verification & Delivery
- Status: in_progress
- Actions taken:
- Added optional scheduler metadata to desktop task events in shared types and server publishers so the local scheduler can make safer fan-out decisions before leasing.
- Ran
gofmton the modified Go files after the event metadata changes. - Verified
pnpm --filter @geo/desktop-client typecheckpasses. - Verified
pnpm --filter @geo/desktop-client buildpasses. - Verified
pnpm --filter admin-web typecheckstill passes after the shared-type event additions. - Verified
go test ./internal/tenant/app/...passes fromserver/.
- Files created/modified:
packages/shared-types/src/index.ts(updated)server/internal/tenant/app/desktop_task_events.go(updated)server/internal/tenant/app/desktop_task_service.go(updated)server/internal/tenant/app/publish_job_service.go(updated)
Phase 18: Qwen Adapter & Auth Relaxation
- Status: complete
- Actions taken:
- Ported the browser-extension
qwenmonitoring flow into a new desktop Playwright adapter that drives Tongyi's in-page managers viapage.evaluate()and extracts answer/source data from__qianwenChatAPI. - Registered the new
qwenmonitor adapter in the desktop runtime so monitor tasks can execute through the hidden Playwright CDP layer. - Tightened generic AI auth fingerprinting to ignore CSRF-only cookies like
XSRF-TOKEN, which Qwen sets even for anonymous visits. - Added a Qwen-specific bind detector so the auth window can auto-close once a real session footprint is present, even if the page has not yet rendered an obvious avatar/name signal.
- Updated monitor preflight policy so only
yuanbao,kimi, anddeepseekrequire active login before execution;qwen,doubao, andwenxinare allowed to run anonymously when needed.
- Ported the browser-extension
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)apps/desktop-client/src/main/adapters/qwen.ts(created)apps/desktop-client/src/main/adapters/index.ts(updated)apps/desktop-client/src/main/runtime-controller.ts(updated)apps/desktop-client/src/main/account-binder.ts(updated)
Phase 19: Qwen Verification & Delivery
- Status: complete
- Actions taken:
- Verified
pnpm --filter @geo/desktop-client typecheckpasses after the Qwen adapter, bind-flow, and auth-policy updates. - Verified
pnpm --filter @geo/desktop-client buildpasses after the same changes. - Followed up on a real Qwen bind stall reported by the user, inspected the machine's persisted
pending-qwen-*partition, and confirmed logged-in cookies liketongyi_sso_ticket,tongyi_sso_ticket_hash, andb-user-idare present. - Reworked Qwen account detection so bind/probe can succeed from those persisted auth cookies even when the page nickname/avatar heuristics do not trigger.
- Verified
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)
Session: 2026-04-04
Phase 13: Prompt Centralization
- Status: complete
- Actions taken:
- Read the current planning files and reopened repository context for the new prompt-centralization request.
- Searched runtime and seed paths for all currently used hard-coded prompts instead of only matching the obvious template seed strings.
- Confirmed the prompt surface spans template seeds, template generation fallback prompts, template assist fallback prompts, prompt-rule generation supplements, and knowledge prompt injection.
- Added a dedicated
server/internal/tenant/promptspackage to centralize platform template seed prompts and runtime prompt fragments. - Refactored
cmd/dev-seed,template_prompt.go,template_assist.go,prompt_generate_service.go, andknowledge_service.goto read prompt text from the new package. - Corrected invalid JSON quoting in the seed
custom_placeholderfields while moving the template card-config blobs.
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)server/internal/tenant/prompts/runtime.go(created)server/internal/tenant/prompts/template_seeds.go(created)server/cmd/dev-seed/main.go(updated)server/internal/tenant/app/template_prompt.go(updated)server/internal/tenant/app/template_assist.go(updated)server/internal/tenant/app/prompt_generate_service.go(updated)server/internal/tenant/app/knowledge_service.go(updated)
Phase 14: Prompt Verification & Delivery
- Status: complete
- Actions taken:
- Ran
gofmtacross all changed Go files after the prompt extraction. - Re-scanned the runtime and seed callers to confirm the long prompt literals were removed from business functions and now only live under
server/internal/tenant/prompts. - Ran
go test ./internal/tenant/... ./cmd/dev-seedfromserver/and confirmed the affected packages compile and tests pass.
- Ran
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)
Session: 2026-03-31
Phase 10: Interface Coverage Audit & Visual Mapping
- Status: complete
- Actions taken:
- Re-read the backend router and transport/app layers to inventory every currently exposed tenant-facing HTTP interface.
- Confirmed the remaining frontend-backed API groups are
templates/articlesandbrands, whilecustom/media/tracking/knowledgestill lack matching backend routes in this repo. - Recovered the reference screenshot layouts with position-aware OCR so the implementation can follow actual placement and grouping instead of just textual labels.
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)
Phase 11: Admin-Web Full Interface Delivery
- Status: in_progress
- Actions taken:
- Added a minimal
vue-i18nsetup withzh-CNanden-USmessage bundles, locale persistence, and Ant Design locale switching. - Reworked
LoginView,WorkspaceView,TemplatesView,ArticleDetailDrawer,TemplateGenerationDrawer,PageHero, andBrandsViewto stop using inline styles and to use component-local<style>blocks. - Restored
AppShell.vueto the user-preferred version and only moved its inline style attributes into named classes. - Fixed the broken
pnpm dev:adminstartup path by adding the missingBrandsView.vue, runningpnpm install, and re-runningpnpm typecheck:adminpluspnpm dev:admin.
- Added a minimal
- Files created/modified:
apps/admin-web/package.json(updated)apps/admin-web/src/i18n/index.ts(created)apps/admin-web/src/i18n/messages/zh-CN.ts(created)apps/admin-web/src/i18n/messages/en-US.ts(created)apps/admin-web/src/main.ts(updated)apps/admin-web/src/App.vue(updated)apps/admin-web/src/router/meta.d.ts(updated)apps/admin-web/src/router/index.ts(updated)apps/admin-web/src/lib/api.ts(updated)apps/admin-web/src/lib/display.ts(updated)apps/admin-web/src/components/PageHero.vue(created)apps/admin-web/src/components/ArticleDetailDrawer.vue(created)apps/admin-web/src/components/TemplateGenerationDrawer.vue(created)apps/admin-web/src/views/LoginView.vue(updated)apps/admin-web/src/views/WorkspaceView.vue(updated)apps/admin-web/src/views/TemplatesView.vue(created)apps/admin-web/src/views/BrandsView.vue(created)apps/admin-web/src/views/FeatureStubView.vue(updated)apps/admin-web/src/layouts/AppShell.vue(updated)packages/shared-types/src/index.ts(updated)apps/admin-web/src/styles.css(pending next cleanup pass)task_plan.md(updated)findings.md(updated)progress.md(updated)
Phase 6: Frontend Scope Recovery
- Status: complete
- Actions taken:
- Read the planning files, Claude-side plan artifact, and architecture documents to recover the interrupted task context.
- Confirmed the backend chain is complete locally and the repository still has no
apps/orpackages/directories. - Locked the next useful slice to a tenant-facing
admin-webfoundation rather than platform-side frontend work.
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)
Phase 7: Frontend Foundation
- Status: complete
- Actions taken:
- Created the root pnpm workspace, root package scripts, and frontend-oriented
.gitignore. - Added shared frontend packages for TS config, API types, and an Axios-based client with auth refresh handling.
- Scaffolded
apps/admin-webwith Vite 8, Vue 3, TypeScript, Ant Design Vue, Pinia, Vue Router, and Vue Query.
- Created the root pnpm workspace, root package scripts, and frontend-oriented
- Files created/modified:
.gitignore(created)package.json(created)pnpm-workspace.yaml(created)packages/tsconfig/base.json(created)packages/shared-types/package.json(created)packages/shared-types/src/index.ts(created)packages/http-client/package.json(created)packages/http-client/src/index.ts(created)apps/admin-web/package.json(created)apps/admin-web/.env.example(created)apps/admin-web/index.html(created)apps/admin-web/tsconfig.json(created)apps/admin-web/vite.config.ts(created)
Phase 8: Admin-Web Initial Features
- Status: complete
- Actions taken:
- Implemented the app bootstrap, Ant Design locale wiring, session persistence helpers, and auth store.
- Implemented the login page with seeded local credentials and redirect-aware sign-in flow.
- Implemented the protected shell layout, navigation, quota teaser, workspace dashboard, and placeholder routes for the rest of the information architecture.
- Files created/modified:
apps/admin-web/src/App.vue(created)apps/admin-web/src/main.ts(created)apps/admin-web/src/styles.css(created)apps/admin-web/src/lib/session.ts(created)apps/admin-web/src/lib/errors.ts(created)apps/admin-web/src/lib/api.ts(created)apps/admin-web/src/stores/pinia.ts(created)apps/admin-web/src/stores/auth.ts(created)apps/admin-web/src/router/meta.d.ts(created)apps/admin-web/src/router/index.ts(created)apps/admin-web/src/layouts/AppShell.vue(created)apps/admin-web/src/views/LoginView.vue(created)apps/admin-web/src/views/WorkspaceView.vue(created)apps/admin-web/src/views/FeatureStubView.vue(created)
Phase 9: Frontend Verification & Delivery
- Status: complete
- Actions taken:
- Ran
pnpm installfor the new workspace and generatedpnpm-lock.yaml. - Fixed the initial frontend build errors related to Node typings and typed Axios wrapper method parameters.
- Switched Ant Design Vue registration from full-plugin mode to per-component registration to reduce the main bundle size.
- Ran
pnpm build:adminsuccessfully and confirmed production assets were emitted. - Ran
pnpm --filter admin-web preview --host 127.0.0.1 --port 4173and verified/loginreturnedHTTP/1.1 200 OKwith built asset references. - Attempted browser automation verification, then fell back to HTTP verification after the local Playwright MCP environment failed on
/.playwright-mcp. - After Playwright became usable again, started the Vite dev server plus
tenant-api, discovered the login CTA was not submitting on click, fixed the handler binding, and re-ran browser verification successfully with Playwright CLI.
- Ran
- Files created/modified:
apps/admin-web/package.json(updated)apps/admin-web/tsconfig.json(updated)apps/admin-web/vite.config.ts(updated)apps/admin-web/src/main.ts(updated)apps/admin-web/src/views/LoginView.vue(updated)packages/http-client/src/index.ts(updated)pnpm-lock.yaml(created)task_plan.md(updated)findings.md(updated)progress.md(updated)
Phase 1: Progress Verification
- Status: complete
- Started: 2026-03-31
- Actions taken:
- Read the task-specific design document.
- Inspected top-level repository layout and backend directory tree.
- Read the planning-with-files skill instructions and initialized planning files.
- Inspected
server/Makefile,server/cmd/tenant-api/main.go, andserver/internal/bootstrap/bootstrap.go. - Verified there are 19 migration files and inspected
cmd/dev-seed/main.go. - Inspected
sqlc.yaml, repository directory contents, and current repository integration test placeholders. - Inspected auth/workspace/template/article/brand services and route registration to compare actual implementation with the design doc.
- Files created/modified:
task_plan.md(created)findings.md(created)progress.md(created)
Phase 2: Gap Analysis and Scope Lock
- Status: complete
- Actions taken:
- Compared the repository contents against the design doc's expected
sqlcand repository layout. - Confirmed Step 4 is the earliest incomplete milestone because the generated code directory and repository wrappers are missing.
- Ran
make sqlc-generateand observed a failing schema path insqlc.yaml.
- Compared the repository contents against the design doc's expected
- Files created/modified:
task_plan.md(updated)findings.md(updated)progress.md(updated)
Phase 3: Implementation
- Status: complete
- Actions taken:
- Fixed
server/internal/tenant/repository/sqlc.yamland regeneratedsqlcoutput underserver/internal/tenant/repository/generated/. - Added repository wrappers for auth, workspace, template, article, quota, and audit queries.
- Refactored auth/workspace/template services and handlers to use the new repository layer.
- Reworked template generation flow to use repository-backed transactional operations.
- Implemented atomic refresh token rotation in Redis and added
session_storetests. - Cleaned existing lint violations that were blocking local verification.
- Fixed
- Files created/modified:
server/internal/tenant/repository/sqlc.yaml(updated)server/internal/tenant/repository/generated/*(generated)server/internal/tenant/repository/common.go(created)server/internal/tenant/repository/auth_repo.go(created)server/internal/tenant/repository/workspace_repo.go(created)server/internal/tenant/repository/template_repo.go(created)server/internal/tenant/repository/article_repo.go(created)server/internal/tenant/repository/quota_repo.go(created)server/internal/tenant/repository/audit_repo.go(created)server/internal/tenant/app/auth_service.go(updated)server/internal/tenant/app/workspace_service.go(updated)server/internal/tenant/app/template_service.go(updated)server/internal/shared/auth/session_store.go(updated)server/internal/shared/auth/session_store_test.go(created)server/internal/tenant/transport/auth_handler.go(updated)server/internal/tenant/transport/workspace_handler.go(updated)server/internal/tenant/transport/template_handler.go(updated)
Phase 4: Testing & Verification
- Status: complete
- Actions taken:
- Re-ran
make sqlc-generateafter the final code state and confirmed generation succeeds. - Ran
go test ./..., thenmake test, and confirmed all tests pass. - Ran
make lint, fixed the reported warnings, and re-ran until it passed cleanly. - Verified the tenant-scope guard script exists and checked for CI workflow files.
- Re-ran
- Files created/modified:
server/internal/tenant/repository/tx.go(updated)server/cmd/dev-seed/main.go(updated)server/internal/shared/auth/middleware_test.go(updated)server/internal/tenant/app/article_service.go(updated)server/internal/tenant/app/brand_service.go(updated)task_plan.md(updated)findings.md(updated)progress.md(updated)
Phase 5: Delivery
- Status: complete
- Actions taken:
- Added backend CI workflow under
.github/workflows/. - Added
tenant-scope-guardto the backendMakefileso CI and local verification use the same entrypoint. - Re-ran
make tenant-scope-guard,make test, andmake lintafter the CI-related edits. - Updated the backend
Makefileto rungolang-migratethroughgo run -tags postgresinstead of requiring a preinstalledmigratebinary. - Ran
make dev-initsuccessfully, including Docker startup, migrations, and seed data. - Started
tenant-apiand verified health endpoints plus auth login/me/refresh/logout behavior with positive and negative checks.
- Added backend CI workflow under
- Files created/modified:
.github/workflows/backend-ci.yml(created)server/Makefile(updated)task_plan.md(updated)findings.md(updated)progress.md(updated)
Test Results
| Test | Input | Expected | Actual | Status |
|---|---|---|---|---|
| Repository inspection | ls, rg --files, sed |
Establish current backend coverage | Backend skeleton, migrations, services, and transport files exist | pass |
| Migration count | `find server/migrations -name '*.up.sql' | wc -l` | 19 schema migrations | 19 |
| SQLC generation | make sqlc-generate |
Generate typed code | Passed after fixing sqlc.yaml schema path |
pass |
| Go tests | go test ./... |
All packages compile and tests pass | Passed | pass |
| Make tests | make test |
Roadmap acceptance command passes | Passed | pass |
| Lint | make lint |
Roadmap acceptance command passes | Passed after fixing errcheck/ineffassign warnings | pass |
| CI workflow presence | find . -path '*/.github/workflows/*' -type f |
At least one CI workflow if Step 9 is complete | .github/workflows/backend-ci.yml exists |
pass |
| Tenant scope guard | make tenant-scope-guard |
Tenant SQL filter guard passes | Passed | pass |
| Dev init | make dev-init |
Infra, migrations, and seed complete successfully | Passed after fixing Makefile-managed migrate driver tags | pass |
| Live health | GET /api/health/live |
HTTP 200 with alive status | Returned code=0, status=alive |
pass |
| Ready health | GET /api/health/ready |
HTTP 200 with ready status | Returned code=0, status=ready |
pass |
| Login | POST /api/auth/login with admin@geo.local / Admin@123 |
Receive access/refresh tokens and user info | Passed | pass |
| Me | GET /api/auth/me with fresh access token |
Current user payload returned | Passed | pass |
| Refresh | POST /api/auth/refresh with original refresh token |
Receive rotated access/refresh token pair | Passed | pass |
| Logout revoke | POST /api/auth/logout, then GET /api/auth/me with old access token |
Old access token rejected | Returned 40103 token_revoked |
pass |
| Refresh rotate invalidate | Reuse old refresh token after refresh | Old refresh token rejected | Returned 40121 refresh_session_expired |
pass |
| Workspace overview | GET /api/tenant/workspace/overview |
Aggregated stats return successfully | Returned code=0, article/brand counts present |
pass |
| Workspace recent articles | GET /api/tenant/workspace/recent-articles |
Recent list returns successfully | Returned code=0 |
pass |
| Workspace quota summary | GET /api/tenant/workspace/quota-summary |
Quota summary returns successfully | Returned code=0, balance/total present |
pass |
| Workspace template cards | GET /api/tenant/workspace/template-cards |
Template cards return successfully | Returned code=0, count=4 |
pass |
| Template generate flow | POST /api/tenant/templates/{id}/generate + article detail/version checks |
Article generation completes end-to-end | Article 1 completed, versions count 1, quota 100 -> 99 |
pass |
| Brand soft delete and recreate | Create brand, delete, recreate same name | Recreate succeeds after soft delete | Original brand 1 deleted, recreated as brand 2 |
pass |
| Question version history | Create question, update, list versions | Version history retained | Returned 2 versions, latest text updated | pass |
| Competitor CRUD basic flow | Create competitor then list | Competitor visible under brand | Returned count 1 |
pass |
| Frontend workspace install | pnpm install |
Workspace dependencies install cleanly | Passed | pass |
| Frontend build | pnpm build:admin |
admin-web compiles and emits production assets |
Passed | pass |
| Frontend preview login HTML | curl -I http://127.0.0.1:4173/login |
Preview route returns 200 OK |
Returned HTTP/1.1 200 OK |
pass |
| Frontend preview asset shell | curl -s http://127.0.0.1:4173/login |
HTML references built CSS/JS assets | Returned built asset tags for index-CtRpygQP.js and index-DFz5-Rsr.css |
pass |
| Frontend browser login flow | pnpm dlx @playwright/test test .tmp-playwright/admin-web.spec.js --reporter=line |
Login succeeds and workspace renders | Passed after binding the login CTA directly to handleSubmit |
pass |
Error Log
| Timestamp | Error | Attempt | Resolution |
|---|---|---|---|
| 2026-03-31 | None yet | 1 | N/A |
| 2026-03-31 | make sqlc-generate failed due to invalid schema path in sqlc.yaml |
1 | Fixed by changing schema path to ../../../migrations/ |
| 2026-03-31 | make lint failed on several existing warnings |
1 | Fixed all reported warnings and re-ran lint successfully |
| 2026-03-31 | make dev-init failed because go-run migrate lacked the postgres driver tag |
1 | Updated MIGRATE_CMD to go run -tags postgres ... and reran successfully |
| 2026-03-31 | Gemini CLI returned 429 MODEL_CAPACITY_EXHAUSTED on gemini-3.1-pro-preview |
1 | Stopped pursuing Gemini once the user said not to use Gemini |
| 2026-03-31 | Initial frontend build failed on missing Node typings and implicit any parameters |
1 | Removed the Node type dependency from app TS config, simplified the Vite config, and typed the API client methods explicitly |
| 2026-03-31 | Playwright MCP browser open failed on /.playwright-mcp |
1 | Used preview HTTP verification instead of blocking on browser environment setup |
| 2026-03-31 | Browser click on the login CTA did not submit the form, so Playwright stayed on /login |
1 | Added an explicit @click=\"handleSubmit\" binding to the CTA and re-ran the E2E flow successfully |
Phase 22: Monitoring Daily Collection Review
- Status: complete
- Actions taken:
- Read the existing planning files and restored context for the monitoring scheduler/runtime work.
- Inspected
cmd/scheduler, the shared cron helper,ScheduleDispatchWorker, monitoring handlers, monitoring service, phase2 desktop task dispatch, migrations, and deployment config. - Queried local Postgres/Monitoring Postgres containers for current task evidence.
- Verified the data-detail/dashboard read path with existing 2026-04-24 monitoring data.
- Findings so far:
- Current DB evidence shows 2026-04-24 monitoring collection tasks are
desktop/manual/plugin_standard, not daily automatic tasks. tenant_monitoring_quotasis configured ascollect_frequency = daily, but the inspected runtime does not contain a daily monitoring task generation worker.
- Current DB evidence shows 2026-04-24 monitoring collection tasks are
Phase 23: Monitoring Daily Task Generation Repair
- Status: complete
- Actions taken:
- Added
server/internal/tenant/app/monitoring_daily_task_worker.go. - Wired
MonitoringDailyTaskWorkerintoserver/cmd/scheduler/main.go. - Added
server/internal/tenant/app/monitoring_daily_task_worker_test.gofor midnight-after materialization, existing-task idempotency, and deterministic plan ordering. - Implemented stable jitter after midnight, global/plan/brand batch caps, daily hard-cap selection, and brand-level advisory locking.
- Implemented due desktop dispatch claim with
FOR UPDATE SKIP LOCKED,last_dispatched_at,dispatch_attempts, and a retry cooldown. - Kept automatic daily desktop tasks pending when no eligible desktop account/client is available; no legacy fallback is applied for this path.
- Fixed the P0 rollout-disabled case: daily generation now requires
desktop_tasksrollout plusprimary_client_id; otherwise it skips the plan and recordsSkippedPlanCountrather than creating orphanautomatic/legacyrows. - Removed Go runtime and dev-seed dependency on
tenant_monitoring_quotas: daily plans now come fromdesktop_clients, dashboard/projection use default monitoring platforms, and primary client selection is derived from recent/registered desktop clients. - Fixed the P0 RabbitMQ publish context issue in daily worker:
publishMonitorDesktopTaskAvailablenow receives a 5-second child context derived from the worker tick context instead ofcontext.Background().
- Added
- Verification:
go test ./internal/tenant/app -run 'Test.*MonitoringDaily|Test.*Monitoring|TestEncodeMonitoringProjectionRebuildEnvelope|TestBuildMonitoringRawPayload' -count=1passed.go test ./cmd/scheduler ./cmd/dev-seed ./internal/tenant/app -count=1passed.docker exec geo-monitoring-postgres psql ... EXPLAIN ...passed for the new claim SQL.
Phase 24: Monitoring Daily Observability Hardening
- Status: complete
- Actions taken:
- Completed the plan/brand scoped error-isolation path so transient failures increment summary failure counts and do not stop other tenants/brands in the same tick.
- Added
monitoring_daily_task_metrics.gowith atomic counters/gauges for worker runs, fatal and partial failures, plan/brand failures, skipped plans, task stage counts, last timestamps, duration, business date, and last fatal error code/message. - Recorded metrics on every
runOnceresult, including zero-work ticks and fatal errors. - Exposed
/metricsin Prometheus text format and/api/internal/metrics/monitoring/daily-tasksas JSON. - Started the scheduler's health/metrics HTTP server on
scheduler.http_portdefault8081. - Reworked daily hard-cap accounting so existing materialized tasks are counted from DB, full candidate horizons are preserved for de-duplication, and remaining capacity is decremented only by rows inserted in the current tick.
- Split daily materialization limit from desktop dispatch limit, so a full daily cap does not stop already-pending tasks from being dispatched.
- Replaced the hard-coded daily plan defaults with subscription/config-driven rules: active subscription required, max brands from plan/config, platforms from live bound desktop accounts, and per-brand task cap from configured active questions capped by
brand_library. - Changed dashboard and projection platform selection so unbound platforms are not silently shown or scheduled.
- Verification:
go test ./internal/tenant/app -run 'Test.*MonitoringDaily' -count=1passed.go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestReconcile|TestResolve|TestIntersect|TestFilter' -count=1passed.go test ./cmd/scheduler ./internal/bootstrap ./internal/shared/config -count=1passed.go test ./cmd/scheduler ./cmd/dev-seed ./internal/tenant/app -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 25: Heartbeat Primary Stability Hardening
- Status: complete
- Actions taken:
- Replaced heartbeat primary resolution with a per-tenant/per-workspace
desktop_client_primary_leaseslease row. - The current primary renews the lease on heartbeat; other desktop clients are non-primary while the incumbent lease is live.
- Failover now happens only when the lease has expired or the recorded primary desktop client is unavailable/revoked.
- Updated daily monitoring plan selection to prefer the sticky lease primary before deterministic fallback.
- Removed
last_seen_atordering from the current-user registered-client lookup so UI platform selection is not heartbeat-driven. - Added migration
20260424130000_add_desktop_primary_leaseswith the lease table, backfill, and active desktop-client lookup indexes. - Added a unit test for the lease-claim decision matrix.
- Replaced heartbeat primary resolution with a per-tenant/per-workspace
- Verification:
go test ./internal/tenant/app -run 'TestShouldClaimHeartbeatPrimaryLease|Test.*MonitoringDaily|TestReconcile|TestResolve|TestIntersect|TestFilter' -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 26: Scheduler Metrics HTTP Hardening
- Status: complete
- Actions taken:
- Added
scheduler.http_hostwith default127.0.0.1. - Added
scheduler.internal_metrics_token, with env overridesSCHEDULER_INTERNAL_METRICS_TOKEN/SCHEDULER_METRICS_TOKEN. - Protected
/metricsand/api/internal/metrics/monitoring/daily-taskswith token auth. - Changed
scheduler.http_port < 0to mean explicit HTTP disablement;0still defaults to8081. - Replaced
app.Engine.Run(... Fatalf ...)withhttp.Server.ListenAndServe, non-fatal error logging, and gracefulShutdown. - Added scheduler HTTP auth/address tests and config normalization/env tests.
- Added
- Verification:
go test ./cmd/scheduler ./internal/shared/config -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 27: Scheduler Worker Graceful Shutdown
- Status: complete
- Actions taken:
- Added blocking
Run(ctx)methods to scheduler workers while keeping existingStart(ctx)wrappers. - Updated
cmd/schedulerto create workers explicitly and run them under async.WaitGroup. - On signal, scheduler now stops the metrics HTTP server, cancels worker loops, and waits up to 60 seconds for workers to finish.
- Changed scheduler worker loops so shutdown cancellation prevents the next tick but does not immediately cancel an active
runOnce; active work still has the existing per-worker timeout. - Added tests for worker wait completion and timeout behavior.
- Added blocking
- Verification:
go test ./cmd/scheduler ./internal/scheduler ./internal/tenant/app -run 'TestScheduler|TestShouldClaimHeartbeatPrimaryLease|Test.*MonitoringDaily' -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 28: Monitoring Platform Authorization UI Contract
- Status: complete
- Actions taken:
- Added explicit monitoring platform authorization status to dashboard runtime and question-detail API responses.
- Added shared frontend type
MonitoringPlatformAuthorizationStatus. - Updated
TrackingViewto keep dashboard platform rows stable and disable collect-now for no-authorized or selected-unauthorized platform states without rendering a no-authorized dashboard alert. - Updated
TrackingQuestionDetailViewto show an explicit unavailable state and suppress the platform tabs/detail grid when no platforms are authorized. - Added i18n strings for the new no-desktop, no-authorized, and selected-unauthorized states.
- Added a Go unit test for the authorization-status decision matrix.
- Verification:
go test ./internal/tenant/app -run 'TestMonitoringPlatformAuthorizationStatus|TestReconcileEnabledMonitoringPlatforms|TestFilterMonitoringPlatforms|TestResolveDashboardDateWindowAt|TestParseDetailDateRangeAt' -count=1passed.pnpm typecheck:adminpassed.- Browser regression against admin-web with
platform_authorization_status = no_authorized_platformspassed for dashboard and question detail; dashboard does not show a no-authorized alert. go test ./...passed fromserver/.pnpm build:adminpassed; it still reports existing bundle/CSS warnings unrelated to this change.git diff --checkpassed.
Phase 29: Monitoring Six-Platform Display Contract
- Status: complete
- Actions taken:
- Changed
loadMonitoringProjectionPlatformsto return the canonical six-platform catalog instead of deriving display rows from same-day task rows. - Changed dashboard platform breakdown to use the same six-platform display catalog, so platforms with zero tasks/samples still appear.
- Added
authorized_monitoring_platform_idsto dashboard runtime and shared frontend types. - Updated
TrackingViewcollect-now gating to use the explicit authorized platform ID list instead of inferring authorization from visible platform rows. - Added unit coverage for the six-platform catalog copy and projection platform selection.
- Changed
- Verification:
go test ./internal/tenant/app -run 'TestDefaultMonitoringPlatformMetadata|TestLoadMonitoringProjectionPlatforms|TestMonitoringPlatformAuthorizationStatus|TestReconcileEnabledMonitoringPlatforms|TestFilterMonitoringPlatforms' -count=1passed.pnpm typecheck:adminpassed.- Browser regression confirmed a no-authorized-platform dashboard still renders all 6 platform names and keeps collect-now disabled.
go test ./...passed fromserver/.pnpm build:adminpassed; existing CSS/chunk warnings remain unrelated.git diff --checkpassed.
Phase 30: Workspace Scope And Daily Config Visibility
- Status: complete
- Actions taken:
- Added current-workspace context helpers and a
WorkspaceScopemiddleware withX-Workspace-IDsupport plus membership validation for non-primary workspace requests. - Wired the tenant route group through
WorkspaceScope. - Updated monitoring dashboard, question detail, and collect-now paths to use the current request workspace for quota/client/platform-account/access-state resolution.
- Documented
findLatestRegisteredClientForUseras created-at ordered and intentionally independent of online health. - Changed daily worker platform JSON decoding to return errors instead of swallowing malformed JSON.
- Counted malformed daily platform config as a plan failure and logged it with tenant/workspace/business-date context.
- Added unit coverage for current workspace fallback/override, workspace-id parsing, and daily platform JSON decode failures.
- Added current-workspace context helpers and a
- Verification:
go test ./internal/shared/auth ./internal/shared/middleware ./internal/tenant/app -run 'TestCurrentWorkspaceID|TestWorkspaceScope|TestRequestedWorkspaceID|TestDecodeDailyMonitoringEnabledPlatforms|Test.*MonitoringDaily|TestMonitoringPlatformAuthorizationStatus|TestDefaultMonitoringPlatformMetadata|TestLoadMonitoringProjectionPlatforms' -count=1passed.go test ./internal/tenant/transport -run TestProtectedRoutes -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 31: Heartbeat Primary Lease Scalability
- Status: complete
- Actions taken:
- Replaced per-heartbeat
BEGIN/SELECT ... FOR UPDATE/UPDATEprimary lease handling with read-mostly lease resolution. - Normal primary heartbeats now return from a plain read unless the renew interval has elapsed.
- Non-primary heartbeats return from a plain read while the incumbent lease is live and available.
- Missing, expired, unavailable, and race cases use single-statement
INSERTor CAS-styleUPDATEwrites instead of an explicit lock transaction. - Added heartbeat primary lease metrics for hit/miss outcomes, DB writes, contention, errors, and duration.
- Added token-protected tenant-api internal metrics endpoints for heartbeat primary lease JSON and Prometheus output.
- Documented the renew throttle relative to the 25s desktop heartbeat and 90s TTL.
- Replaced per-heartbeat
- Verification:
go test ./internal/tenant/app -run 'TestDecideHeartbeatPrimaryLease|TestMonitoringHeartbeatPrimaryLeaseMetrics|TestBuildMonitoringRawPayloadKimi' -count=1passed.go test ./internal/tenant/transport -run 'TestProtectedRoutes|TestPublicRoutes' -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 32: Monitoring Heartbeat Snapshot Scalability
- Status: complete
- Actions taken:
- Changed
MonitoringCallbackService.Heartbeatto batch-load current access snapshot state before deciding whether a monitoring DB transaction is required. - Stable unchanged platform access reports now skip snapshot upserts; unchanged rows refresh at most every 10 minutes.
- Primary-client inaccessible-platform reconciliation now first checks whether matching pending tasks exist, so stable inaccessible reports with no pending work do not open a write transaction.
- Added heartbeat snapshot metrics for platform reports, transaction opens, snapshot insert/update/refresh/skip counts, reconciled tasks, projection rebuilds, errors, and duration.
- Exposed heartbeat snapshot metrics through token-protected tenant-api internal JSON and Prometheus endpoints.
- Added a monitoring DB partial index for pending-platform reconciliation lookup.
- Changed
- Verification:
go test ./internal/tenant/app -run 'TestDecideMonitoringHeartbeatSnapshot|TestMonitoringHeartbeatSnapshotMetrics|TestDecideHeartbeatPrimaryLease|TestMonitoringHeartbeatPrimaryLeaseMetrics' -count=1passed.go test ./internal/tenant/app -count=1passed.go test ./internal/tenant/transport -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 33: Prometheus Metrics Exposition Hardening
- Status: complete
- Actions taken:
- Added
prometheus/client_golangand replaced custom hand-written Prometheus text builders withprometheus.Collectorimplementations pluspromhttp. - Kept existing JSON snapshot endpoints unchanged.
- Changed scheduler
/metricsto serve a dedicated registry containing daily-task metrics plus Go runtime and process collectors. - Changed tenant-api internal heartbeat Prometheus endpoints to serve through
promhttpas well. - Removed raw error-message labels from heartbeat snapshot Prometheus output; detailed messages remain available in JSON snapshots.
- Added explicit carriage-return normalization for label values before creating const metrics, because the local client_golang text path does not escape raw CR.
- Added tests covering scheduler runtime metrics and CR label normalization.
- Added
- Verification:
go test ./internal/tenant/app -run 'TestMonitoringDailyTaskMetrics|TestMonitoringDailyTaskPrometheus|TestMonitoringSchedulerMetricsPrometheusHandler|TestMonitoringHeartbeatPrimaryLeaseMetrics|TestMonitoringHeartbeatSnapshotMetrics' -count=1passed.go test ./cmd/scheduler ./internal/tenant/transport -run 'TestScheduler|TestProtectedRoutes|TestPublicRoutes|TestDesktopClientRoutes' -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 34: Daily Task Batch Materialization
- Status: complete
- Actions taken:
- Changed
ensureDailyMonitoringCollectTasksfrom per-candidatetx.Execto a single batchedINSERT ... SELECT FROM unnest(...). - Batched arrays carry
question_id,question_hash,ai_platform_id, anddispatch_after; tenant/brand/business date/collector/run mode/target client/shard key/execution owner remain constant per call. - Kept
ON CONFLICT DO NOTHING, so duplicate materialization still returns only the number of newly inserted rows viaRowsAffected.
- Changed
- Verification:
go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestMonitoringDailyTaskMetrics|TestMonitoringDailyTaskPrometheus|TestMonitoringSchedulerMetricsPrometheusHandler' -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 35: Daily Plan SQL Decomposition
- Status: complete
- Actions taken:
- Split
loadDailyMonitoringPlansintoloadDailyMonitoringPrimaryClientPlans,loadDailyMonitoringPlanPlatformJSON, and a pure assembly helper. - Kept the first query focused on active subscription admission, lease-preferred primary client selection, workspace scoping, and subscription/config-derived brand/question limits.
- Moved authorized platform aggregation to a second batched query keyed by
(tenant_id, workspace_id, client_id). - Added a helper test covering the race where a selected client loses its platform snapshot between the two reads; that candidate is skipped instead of becoming an empty executable plan.
- Split
- Verification:
go test ./internal/tenant/app -run 'TestBuildDailyMonitoringPlansFromSelectedClients|Test.*MonitoringDaily' -count=1passed.go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestMonitoringDailyTaskMetrics|TestMonitoringDailyTaskPrometheus|TestMonitoringSchedulerMetricsPrometheusHandler' -count=1passed.go test ./...passed fromserver/.git diff --checkpassed.
Phase 36: Monitoring Authorization And Detail Display Bug Fix
- Status: complete
- Actions taken:
- Changed monitoring platform authorization to mean a bound, non-deleted platform account on a supported AI platform;
platform_accounts.healthno longer has to belive. - Removed
health = 'live'from daily scheduled plan eligibility and platform aggregation, so daily automatic collection can materialize tasks for offline clients and non-live account states. - Kept immediate collection gated by desktop-client online state, and made the online check target the same desktop client that owns the authorized platform accounts.
- Changed question detail to display the canonical platform history instead of hiding existing data behind current
platform_authorization_status. - Updated frontend date validation to use the monitoring business date, so today's date such as 2026-04-24 is not rejected by local/browser timezone drift.
- Changed monitoring platform authorization to mean a bound, non-deleted platform account on a supported AI platform;
- Verification:
go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestMonitoringPlatformAuthorizationStatus|TestReconcileEnabledMonitoringPlatforms|TestFilterMonitoringPlatforms|TestDefaultMonitoringPlatformMetadata|TestLoadMonitoringProjectionPlatforms' -count=1passed.pnpm --filter admin-web typecheckpassed.go test ./...passed fromserver/.pnpm --filter admin-web buildpassed.git diff --checkpassed.
Phase 21: Foreground Publish Admission
- Status: complete
- Actions taken:
- Confirmed the current runtime only starts publish when
state.activeExecutions.size === 0, so an already-running monitor can block media publish. - Locked the implementation model: publish is foreground, monitor is background, publish receives reserved runtime capacity, and publish platform policy stays in a lightweight in-memory scheduler.
- Added
apps/desktop-client/src/main/publish-scheduler.tswith in-memory queueing, same-platform active locks, and 3-6 second platform cooldowns. - Refactored
runtime-controller.tsso publish can start while monitor is running, monitor pauses behind any publish backlog, and lease-in-flight is tracked separately for publish vs. monitor. - Added hardware/runtime adaptive total concurrency with
GEO_DESKTOP_MAX_TOTAL_CONCURRENCYas an optional cap and a reserved publish slot for monitor budgeting. - Exposed
publishSchedulerin the desktop runtime snapshot and added scheduler unit tests.
- Confirmed the current runtime only starts publish when
- Verification:
pnpm --filter @geo/desktop-client buildpassed.pnpm --filter @geo/desktop-client testpassed: 5 files, 26 tests.git diff --checkpassed.pnpm --filter @geo/desktop-client typecheckfailed before checking runtime changes becauseelectron.vite.config.tshas a Vite 5/8 plugin type mismatch.
2026-04-28 Dongchedi Publish Debug
- Status: in_progress
- Actions taken:
- Queried local
geo-postgresthroughdocker execbecausepsqlis not installed on the host. - Verified article
95reconstructs to normal markdown throughrepository.LoadArticleVersionContent; removed the temporary inspection test after use. - Updated
apps/desktop-client/src/main/adapters/dongchedi.tsso body images first try Dongchedispice/image; local/relative images use ImageX upload and then run throughspice/imagebefore replacement. - Added redacted Dongchedi publish rejection diagnostics to the adapter error payload/logs.
- Added
apps/desktop-client/src/main/adapters/dongchedi-content.tsand a unit test to downgrade table HTML to paragraph rows before Dongchedi submit. - Followed up after another
server exceptionretry where diagnostics showed no table tags, no local asset URL, and one body image. - Removed
entities from Dongchedi table-downgraded body HTML. - Changed body image handling so ImageX-uploaded local images try Dongchedi
spice/imagethrough both session and page-context requests before replacement. - After the platform returned
dongchedi_image_upload_failed:content_images_missing_1_of_1, tried an ImageX direct URL fallback; the next retry still returnedserver exceptionwithcontent_image_upload_strategies = ['imagex_direct_fallback']. - Removed the direct ImageX正文图 fallback. Local正文图片 that cannot be converted to a Dongchedi
spiceURL are now removed fromcontentinstead of failing early or submitting a rejected ImageX URL. - After a no-body-image retry still returned
server exception, changedextra.content_word_cntfrom the reference extension's hardcoded267to the actual text count of the final submitted HTML. - Added
content_word_cntandcomputed_text_countto Dongchedi rejection diagnostics. - Expanded rejection diagnostics with body image host summaries, body image upload strategies, tag/entity counts, content end excerpt, and cover upload dimensions/hosts.
- Queried local
- Verification:
pnpm --filter @geo/desktop-client typecheckpassed.pnpm --filter @geo/desktop-client test -- dongchedipassed.pnpm --filter @geo/desktop-client testpassed.pnpm --filter @geo/desktop-client buildpassed and refreshedout/main/bootstrap.cjs.git diff --checkpassed.
5-Question Reboot Check
| Question | Answer |
|---|---|
| Where am I? | Phase 9 complete |
| Where am I going? | Next useful slice is turning the placeholder routes into real pages, starting with template creation and brand management |
| What's the goal? | Resume the interrupted task by adding the missing admin-web frontend foundation on top of the finished backend |
| What have I learned? | The tenant backend is stable enough to support a real login + dashboard frontend slice, and a real browser pass was valuable because it caught a submit wiring bug that static checks missed |
| What have I done? | Added the pnpm frontend workspace, built apps/admin-web, wired auth and dashboard data to tenant-api, reduced the bundle size, and passed install/build/preview plus browser login verification |
2026-05-01T06:43:58Z - Platform template seed deployment
- Investigated the "普通通用模版" cards shown in the screenshot.
- Confirmed the four platform templates are stored in
article_templatesand currently seeded byserver/cmd/dev-seed/main.go. - Confirmed production deployment jobs only run database migrations, so a fresh environment can miss the four template records unless dev seed is run manually.
- Decision: add a production-safe platform-template initializer and wire it into the migrate job/image instead of running the broad dev seed path.
2026-05-01T07:15:00Z - Gitea Registry CI/CD cleanup
- Kept
deploy-config-ci.ymlvalidation-only after the user clarified it should not own images. - Scoped
frontend-ci.ymltoadmin-webandops-webplus shared packages/Dockerfiles; removed browser-extension typecheck from this workflow. - Added Gitea Registry publishing to frontend/backend CI with commit8 tags and skip-if-tag-exists behavior through
deploy/scripts/gitea-registry-images.sh. - Added commit8 image verification to compose/k3s/offline deployment paths so CD fails if CI has not produced the required image.
- Changed offline package defaults to use commit8 instead of tag names and to pull business images from the Gitea Registry.
- Verification passed: workflow YAML parse, deploy script
bash -n, andsh -nover all workflow run blocks.
2026-05-03T03:03:09Z - Stable PgBouncer Deployment
- Confirmed the existing repository topology uses application-side
pgxpooland direct Postgres service names; no PgBouncer service/config existed before this change. - Started Phase 40 to add stable PgBouncer deployment with session pooling, app runtime traffic through PgBouncer, and migration jobs remaining direct to Postgres.
- Added
pgbouncerandmonitoring-pgbouncerto production Docker Compose and k3s usingedoburu/pgbouncer:v1.24.1-p1,POOL_MODE=session, andAUTH_TYPE=scram-sha-256. - Changed runtime app configs to target PgBouncer while keeping Docker/k3s migration jobs direct to
postgres/monitoring-postgres. - Lowered application-side Postgres pools: tenant runtime uses 12 main / 8 monitoring connections per process; ops runtime uses 5 / 5.
- Made deployment passwords flow from
POSTGRES_PASSWORD/OPS_POSTGRES_PASSWORDplaceholders and changedDatabaseConfig.DSN()to URL-escape credentials for stronger production passwords. - Included PgBouncer in offline packaging and docs.
- Verification passed:
docker compose -f deploy/docker-compose.yaml --env-file deploy/.env.example configkubectl kustomize deploy/k3splus local YAML parsebash -n deploy/scripts/package.shgit diff --checkgo test ./internal/shared/config ./internal/shared/repository/postgres ./internal/ops/config- Temporary PgBouncer container attached to existing
server_defaultnetwork returnedSELECT 1through PgBouncer, then was removed.
2026-05-04T20:51:36Z - Compliance Detection Implementation
- Started Phase 41 for the Revision 8 content compliance detection design.
- Re-read the design document sections covering data model, API contracts, publish gate ordering, manual-review lifecycle, ops pages, and test requirements.
- Confirmed the current code has no compliance module yet and that publish job creation currently bypasses content compliance entirely.
- Added Phase 41-43 to
task_plan.mdand recorded the initial backend/frontend integration findings.
2026-05-05T09:30:00+08:00 - Compliance backend integration
- Added tenant compliance HTTP APIs for runtime status, plain/article check, latest check, record-level ack, manual-review submit/latest/cancel, and tenant whitelist/blacklist terms.
- Wired
PublishJobService.Create()throughGateForPublish, including effective article version resolution, target platform aggregation, block/needs_ack errors with serialized check details, and transactional ack consumption. - Exposed
ArticleDetailResponse.current_version_idand extended desktop publish job creation with article/version compliance metadata. - Added ops compliance service/handlers/routes for dictionaries, terms, policy, master switch, manual reviews, records, and stats.
- Verification passed:
go test ./internal/tenant/compliance ./internal/tenant/transport ./internal/tenant/app ./internal/tenant/repository ./internal/ops/app ./internal/ops/transport ./cmd/ops-api ./cmd/worker-generate.
2026-05-05T10:45:00+08:00 - Compliance completion recovery
- Continued after the 429 interruption and completed the remaining compliance display/API gap.
- Added ops-web shared type aliases, content-safety navigation, and pages for policy, dictionaries, dictionary editing, manual reviews, manual-review detail, records, and stats.
- Added admin-web compliance publish/editing integration, including editor checks, violation grouping, locate/highlight support, whitelist creation, publish gate handling, acknowledgement flow, and manual-review submission/cancel paths.
- Added LLM review AI-point reservation/completion/refund handling in tenant compliance jobs and wired the review worker to the configured LLM provider.
- Extended desktop publish task listing with publish-job compliance block metadata and updated desktop Publish Management to show
合规阻断, record id, intercepted time, and a readable reason summary. - Added admin-web publish status mapping/i18n for
blocked_by_compliance. - Verification passed:
go test ./internal/tenant/compliance ./internal/tenant/transport ./internal/tenant/app ./internal/worker/generate ./cmd/worker-generatego test ./...pnpm --filter admin-web typecheckpnpm --filter ops-web typecheckpnpm --filter @geo/desktop-client typecheckpnpm --filter admin-web buildpnpm --filter ops-web buildpnpm --filter @geo/desktop-client buildgit diff --check
- Notes:
- Admin-web and ops-web production builds still warn about large chunks from existing Ant Design / Milkdown bundles.
2026-05-05T20:09:10+08:00 - Remove tenant compliance policy overrides
- Removed the ops-web tenant override route, menu item, API helpers, and
ComplianceTenantOverridesView.vue. - Removed the ops-api tenant policy override routes, handlers, service methods, audit action, and tenant override resolver branch.
- Changed
ops.compliance_policiesto anid=1global singleton with noscope/tenant_idcolumns; seed migrations and tenant-api policy loading now read/update that singleton directly. - Updated the current compliance design doc, the archived v1 design doc, and planning notes so tenant policy overrides are no longer documented as a supported feature.
- Verification passed:
pnpm --filter ops-web typecheckgo test ./internal/ops/app ./internal/ops/transport ./internal/tenant/compliance ./cmd/ops-api
2026-05-05T21:20:00+08:00 - Article generation reliability hardening
- Started Phase 44 after the user requested large-company style safeguards: structured logs, verifiable states, no swallowed errors, and automatic alerts.
- Confirmed the remaining weak points are in article body generation worker paths, not title/outline assist paths:
- Initial task
runningupdates are ignored in template/custom/imitation generation execution. - Failure cleanup logs status update errors but still swallows quota ledger/refund errors.
- Recovery requeue/finalization logs do not carry a consistent event/stage/anomaly schema yet.
- Initial task
- Scope locked to generation worker/app observability and state checks, avoiding unrelated deployment/compliance dirty files.
2026-05-05T23:45:00+08:00 - Article generation reliability verification
- Added structured article-generation task log context and counters for transitions, failures, cleanup failures, queue failures, recovery actions, state anomalies, and state-check failures.
- Added bounded scheduler-owned generation state consistency checks with configurable interval/timeout/batch/lookback and partial DB indexes; this is a low-frequency safety net, not a full-table polling loop.
- Added internal JSON/Prometheus metrics endpoints and Prometheus alert rules for cleanup failures, state anomalies, state-check failures, queue failures, failure spikes, and recovery finalization.
- Fixed compile/test follow-ups: matched the state-check DB interface to
pgx.Rowsand made the Prometheus label assertion order-independent. - Verification passed:
cd server && go test ./internal/shared/config ./internal/tenant/app ./internal/tenant/transport ./internal/worker/generate ./cmd/scheduler ./cmd/worker-generatecd server && go test ./...git diff --checkruby -e 'require "yaml"; YAML.load_file("deploy/monitoring/article-generation-alerts.yml"); puts "ok"'
2026-05-06T13:05:00+08:00 - Desktop client account isolation
- Fixed the desktop media account cross-device leak reported from Mac/Windows login:
/api/desktop/accountsnow lists accounts by the authenticated desktopclient_id, notworkspace_id + user_id.- Desktop account identity lookup and upsert now use
(workspace_id, client_id, platform_id, platform_uid), preventing one machine from overwriting another machine's row for the same third-party UID. - Desktop-side patch/delete and async health sink updates now also require matching
client_id. - Added migration
20260506120000_scope_platform_accounts_to_desktop_clientto update the active uniqueness index. - Added MAC-address fingerprint fallback for desktop client ID generation while keeping OS machine ID as the preferred stable source.
- Verification passed:
cd server && make sqlc-generatecd server && go test ./internal/tenant/app ./internal/tenant/repository ./internal/tenant/transport -count=1pnpm --filter @geo/desktop-client typecheckpnpm --filter @geo/desktop-client exec vitest run src/main/device-id.test.tsgit diff --check
- Caveat:
pnpm --filter @geo/desktop-client test -- src/main/device-id.test.tsran unrelated existing tests and failed indeepseek.test.tsdue to a pre-existing missingelectron/mainmock; the new device-id test passes when run directly with vitest.
2026-05-07T11:26:26+08:00 - Admin-web publish management start
- Started Phase 48/49 for the user's content-management "发文管理" request.
- Confirmed desktop-client already has a publish management table with the requested columns/actions, but admin-web needs tenant HTTP APIs because Electron IPC is unavailable in the browser.
2026-05-09T17:40:00+08:00 - Desktop publisher page.evaluate packaging fix
- Investigated
page.evaluate: ReferenceError: wO is not definedreported for desktop-client Bilibili publishing and then confirmed dongchedi has the same risk pattern. - Root cause: packaged desktop builds run
build:obf;scripts/obfuscate.cjsobfuscatedout/main/*.cjs, and Playwrightpage.evaluatecallbacks then carried obfuscator helper names into the browser page context where those helpers do not exist. - Updated
apps/desktop-client/scripts/obfuscate.cjsso the Electron main bundle is left unobfuscated and only renderer assets are obfuscated. This aligns the post-build obfuscation step with the existing Vite main-processminify: falseguard. - Verification passed:
pnpm --filter @geo/desktop-client typecheckpnpm --filter @geo/desktop-client build:obfpnpm --filter @geo/desktop-client exec vitest run src/main/adapters/dongchedi.test.tspnpm --filter @geo/desktop-client exec vitest run src/main/adapters/baijiahao.test.ts- Searched
apps/desktop-client/out/main/bootstrap.cjsforwO,_0x...,stringArray,javascript-obfuscator, and['evaluate']; no obfuscator helper traces were present afterbuild:obf.
- Scoped implementation to tenant publish task list/retry endpoints plus a new admin-web
/publish-managementpage under 内容管理. - Noted existing dirty files in i18n/Knowledge/TemplateWizard/config/swagger/knowledge service and will avoid reverting or overwriting unrelated changes.
2026-06-23T23:54:39+08:00 - Doubao thinking-reference fallback
- Investigated the Doubao monitor failure where the answer page showed "已完成思考 / 搜索 N 个关键词,参考 N 篇资料" links but the adapter returned
unknown. - Current Doubao behavior observed from user screenshots:
- citation/source links now live inside the thinking block rather than next to the final answer;
- one answer can contain multiple "搜索 X 个关键词,参考 Y 篇资料" groups;
- "已完成思考,参考 N 篇资料" is a broad thinking summary control, while the search groups hold the concrete blue source links;
- already-expanded groups may still show a chevron, so clicking blindly can collapse useful references.
- Updated
apps/desktop-client/src/main/adapters/doubao.tsso/chat/completionandtext/event-streamresponses remain the preferred SSE source, while a high-quality page answer can be used when SSE has not finished. - Strengthened page fallback to expand/reference-scan Doubao's thinking search groups, skip already-expanded nearby-link groups, merge multiple thinking reference groups, and filter favicon/asset CDN links.
- Added helper coverage in
doubao.test.tsfor unfinished SSE + usable page answer, finished SSE precedence, recoverable timeout with anchored page answer, and multi-group thinking references. - Follow-up fix: the
unknownmessage "未从正文或思维链兜底抓到可提交答案,仅抓到参考资料" still happened because the implementation only useddomAnsweras the fallback answer and did not submitdomReasoning. The adapter now allows a high-quality thinking-chain text fallback when SSE/page answer text is missing but references and anchored page context were captured. - Local anonymous Playwright could open Doubao only to the logged-out/home page, so live account-specific MCP/page content was not directly readable in this session.
- Verification passed:
pnpm --filter @geo/desktop-client exec vitest run src/main/adapters/doubao.test.tspnpm --filter @geo/desktop-client typecheckpnpm --filter @geo/desktop-client testgit diff --check
2026-06-24T01:20:00+08:00 - Doubao SSE capture and challenge handling
- Confirmed from the latest user screenshot that Doubao can trigger an official-site image captcha after a prompt is submitted. This is an account/platform challenge, not an answer parsing failure.
- Hardened
apps/desktop-client/src/main/adapters/doubao.ts:- capture Doubao
/chat/completionSSE in-page through fetch/XHR stream cloning and keep SSE as the primary answer/source path; - keep DOM/page extraction as fallback, including thinking/reference panels for
search_resultswithout promoting reference lists toanswer; - verify composer write/readback before sending, avoid selecting voice/microphone controls as send buttons, and add a Playwright keyboard/mouse submit fallback when the page does not observe the user question;
- detect Doubao captcha/risk-control surfaces such as image selection, drag-to-area, human verification, security verification, and frequent-access prompts;
- return
doubao_challenge_requiredas failed/non-retryable AI platform authorization when a captcha is visible, so the desktop UI alerts the user instead of writingunknown.
- capture Doubao
- Updated
apps/desktop-client/src/main/platform-auth-adapters.tssodoubao_challenge_requiredis classified as a challenge. - Updated
apps/desktop-client/src/main/runtime-controller.tsso Doubao challenge states show a specific user-facing activity: complete Doubao human verification in the desktop client before continuing collection. - Verification passed:
pnpm --filter @geo/desktop-client exec vitest run src/main/adapters/doubao.test.ts src/main/platform-auth-adapters.test.tspnpm --filter @geo/desktop-client typecheckgit diff --checkpnpm --filter @geo/desktop-client build
- Remote SSH to
39.105.229.239with the provided credentials failed with authentication failure, so remote logs/deployment could not be inspected in this pass.
2026-06-24T02:22:00+08:00 - Doubao captcha display, admission, and default mode
- Updated desktop HomeView issue aggregation so Doubao human-verification/account challenge failures collapse into one actionable item: "豆包需要人工验证"; the summary count now follows displayed issue rows instead of raw failed task rows.
- Added monitor admission filtering for blocked AI platforms:
- desktop runtime computes an eligible monitor platform whitelist from current local account health;
- Doubao
challenge_required/expired/revoked states are excluded from local monitor selection, desktop-task monitor lease fallback, legacy monitoring lease fallback, and resume calls; - other AI platforms remain eligible, so a Doubao captcha no longer blocks Qwen/Kimi/DeepSeek/etc. work.
- Extended
/api/desktop/tasks/leasewith optionalplatform_idsfor monitor leases and filtered the server-side monitor candidate SQL by that whitelist. - Changed Doubao execution to use the default visible mode directly:
- removed active in-page switching to "专家"/"思考" and removed deep-think selection parameters from Doubao query execution;
provider_modelnow reportsdoubao-web-fastfor default/fast and for any observed expert label, with nodoubao-web-expertremaining.
- Verification passed:
pnpm --filter @geo/desktop-client exec vitest run src/main/adapters/doubao.test.ts src/main/platform-auth-adapters.test.tspnpm --filter @geo/desktop-client typecheckpnpm --filter @geo/desktop-client buildcd server && go test ./internal/tenant/app ./internal/tenant/transportgit diff --check
2026-06-24T02:29:25+08:00 - Doubao DOM source strictness
- Refined Doubao citation extraction after the user clarified that captcha/risk-control pages may legitimately have no reference sources.
- Kept SSE as the preferred and broad source path, including structured references that embed Doubao redirect URLs in source payloads.
- Tightened DOM/page fallback so
search_resultsonly comes from real link/card URLs and redirect URL attributes; gray search-query/explanatory text such as "search N keywords, reference N sources" is no longer converted into citation sources. - Removed the page-side fallback that scraped arbitrary
httpURLs from element text, so expanded blue reference links are still captured while gray search keyword text is ignored. - Verification passed:
pnpm --filter @geo/desktop-client exec vitest run src/main/adapters/doubao.test.ts src/main/platform-auth-adapters.test.tspnpm --filter @geo/desktop-client typecheckpnpm --filter @geo/desktop-client buildgit diff --check
2026-07-12T12:15:00+08:00 - Hunyuan SSE/search and Markdown diagnosis
- Started Phase 50 for the requested Hunyuan collection repair.
- Locked the desired execution order to official API SSE first, page RPA only when SSE is missing or unusable.
- Included explicit web-search enablement and end-to-end Markdown display repair in scope.
- Added an API-priority regression test at the final Yuanbao answer-selection boundary.
- Confirmed the test fails because the current quality score selects a longer DOM/tooling string over valid SSE Markdown.
2026-07-12T00:00:00+08:00 - Desktop Hunyuan/Yuanbao CDP diagnosis resumed
- Confirmed
npxandplaywright-coreare available and connected Playwright to the running Electron CDP endpoint on port 9339. - Located two authenticated Yuanbao chat pages and inspected the live composer/tool controls.
- Reproduced a web-search verification defect: the page had only
深度思考active while联网搜索remained an unselected tools-menu item, but the adapter can optimistically return enabled when the menu item exposes no ARIA state. - Captured
apps/desktop-client/output/playwright/yuanbao-tools.pngas local visual evidence. - Existing API-vs-DOM priority regression test remains red pending the implementation fix.
- Submitted a short search-enabled query through the real desktop Yuanbao page over CDP and captured the safe request/response shape.
- Verified the official chat SSE endpoint, real search request flags, final
meta.endConv, and the large ratio ofdeepSearchprocess frames to answertextframes. - Added regression coverage for strict API priority, page fallback, current-chat SSE filtering, Markdown blank-line preservation, and exclusion of nested deep-search text from the final answer.
- Initial live-test attempt selected a stale hard-coded conversation ID and failed before adapter execution. The selector was corrected to any current Yuanbao chat page.
- One CDP probe called
browser.close()and stopped the attached Electron Chromium. The existingelectron-vitedevelopment process restarted Electron automatically; subsequent probes exit without sending a remote close command. - Opened the bound Yuanbao account again through the desktop AI-platform card and ran the actual updated adapter through CDP.
- Live adapter verification passed: API SSE source selected, web search verified active, exactly one current chat SSE captured, and answer non-empty.
- Final verification passed:
pnpm --filter @geo/desktop-client exec vitest run src/main/adapters/yuanbao.test.ts(16/16)pnpm --filter @geo/desktop-client typecheckpnpm --filter admin-web typecheckpnpm --filter @geo/desktop-client buildpnpm --filter admin-web build(existing large-chunk warning only)- targeted Prettier formatting and
git diff --check
2026-07-12T13:30:00+08:00 - AI platform multi-account support started
- Added Phases 53-56 for storage/runtime audit, binding/UI changes, same-platform monitor failover, and verification.
- Initial hypothesis: server uniqueness already permits multiple platform UIDs per desktop client, while desktop projection/binding and monitor task targeting still enforce effective single-account behavior.
- Phase 53 audit completed. No server migration is needed; implementation is scoped to desktop dedupe/binding, platform-blocking, local account-pool failover, diagnostics, and the AI account-management UI.
- Added a tested monitor-account pool with preferred-first/LRU ordering, blocked/cooldown filtering, failover classification, and reason-specific cooldowns.
- Removed desktop AI platform-only deduplication and same-platform replacement cleanup; distinct platform UIDs now retain independent server rows and local session partitions.
- Added same-platform monitor attempts inside one leased task, final-result-only submission diagnostics, account health reporting, runtime switch activities, and per-account risk-control alerts.
- Rebuilt AI Platform Management as a media-account-style multi-account page and verified its desktop layout over Electron CDP.
2026-07-12T14:20:00+08:00 - AI platform multi-account server invariant
- Confirmed server monitor targeting remains one target per platform even when several same-platform accounts are bound.
uniqueMonitorDesktopTaskPlatformIDs()de-duplicates requested platforms before account lookup, andselectMonitorDesktopTaskTargetsWithOptions()selects a single best target from each platform's account candidates.- Added focused assertions covering duplicate platform specs and the one-target result for multiple same-platform accounts.
2026-07-12T14:35:00+08:00 - AI platform multi-account verification complete
- Focused server targeting tests passed, including duplicate platform de-duplication and one-target selection for multiple same-platform accounts.
- Focused desktop account-pool, account-health, scheduler, and Doubao tests passed: 3 files / 38 tests.
- Full desktop verification passed: 30 files / 206 tests, Vue typecheck, production Electron build, targeted Prettier check, and
git diff --check. - Electron CDP UI verification remains valid at 1420x960: six platform selectors, three separately managed AI accounts, add-account choices for all six platforms, working Doubao filtering, and no overflow or overlap.
- Residual live-test limitation: the UI was exercised with real bound accounts, but automatic failover could not be triggered against two simultaneously usable Doubao accounts in this environment. The selection, cooldown, error classification, and final-result-only behavior are covered by deterministic tests.
2026-07-12T14:50:00+08:00 - AI/media account UI alignment started
- Added Phases 57-58 after the user clarified that AI Platform Management must visually match Media Account Management, not only expose equivalent account-management functions.
- Audited both live Vue views and identified the mismatch: AI used compact selector cards plus a custom account table, while media uses larger authorization cards and a shared hero-card table shell.
- Locked the change to renderer composition and styles; multi-account runtime behavior and account actions remain unchanged.
- First Electron CDP comparison command failed because
playwright-coreis workspace-local and cannot be resolved from the repository root. The retry runs fromapps/desktop-client, where the dependency is installed.
2026-07-12T15:15:00+08:00 - AI/media account UI alignment implemented
- Removed the global “添加 AI 账号” dropdown; platform cards are now the only binding entry, matching the media account workflow.
- Replaced compact AI selectors with the media page's large card geometry, status dot, bound/unbound treatment, and “新增账号 / 绑定账号” actions.
- Rebuilt the AI authorized-account list with the same hero-card shell, toolbar, filters, transparent table header, row spacing, avatar/platform cells, status tags, and three-action layout used by Media Account Management.
- Retained AI-specific multi-account counts, account health/session data, reauthorization/probe behavior, and row-level risk-control warnings.
- Electron CDP desktop and narrow-width comparisons passed with matching geometry and no page overflow.
2026-07-12T15:25:00+08:00 - Missing-citation failover diagnosis
- Confirmed the existing account-pool classifier returned success as soon as any non-empty answer existed, regardless of empty
citationsandsearch_resultsarrays. - Added a red regression test proving a source-less successful answer previously returned no failover reason.
- Added
missing_citationsas a current-task failover reason. It has zero account cooldown because missing sources can be question-specific and should not mark the account unhealthy for later tasks.
2026-07-12T15:35:00+08:00 - AI account UI and missing-citation failover verified
- Full desktop tests passed: 30 files / 206 tests.
- Desktop Vue typecheck and production Electron build passed.
- Targeted Prettier checks and
git diff --checkpassed. - CDP confirmed AI and media platform cards have matching geometry at 1420x960; the AI page also passed 1024x800 responsive inspection with no page overflow.
- The live DOM contains only the hero actions “一键检测账号” and “刷新状态”; the removed global “添加 AI 账号” button is absent.
- Successful answers now require at least one item in
citationsorsearch_resultsto stop same-platform account failover. When every account lacks sources, the existing loop preserves and submits the final non-empty answer with attempt diagnostics.
2026-07-12T15:50:00+08:00 - Admin AI account management extraction started
- Added Phases 60-62 for a new tracking-side “AI 账号管理” menu after “外部文章标记”.
- Confirmed the existing tracking status panel collapses multiple accounts to the first account per platform even though the API returns every account.
- Confirmed account removal and delete-request APIs can be reused from Media Account Management; implementation needs no server migration.
- Browser verification fallback note: the first isolated Playwright mock command failed because
run-codeexpects one callback expression rather than consecutive top-level statements. No page state or backend data was changed; the retry wraps the setup in one async callback. - The callback retry reached API interception but the CLI sandbox did not expose the global
URLconstructor. Replaced URL parsing with deterministic request-string normalization before rerunning the isolated fixture. - The first successful fixture execution remained on login because the SPA auth store had initialized before test local storage was written. Moved the isolated session seed to
page.addInitScriptso it runs before the next document and Pinia bootstrap.
2026-07-12T16:40:00+08:00 - Admin AI account management extraction complete
- Added “AI 账号管理” immediately after “外部文章标记” and moved account status out of Data Details.
- The new admin page renders one card per AI account, preserves same-platform accounts independently, and reuses the tenant account health, node, delete-request, and unbind lifecycle.
- Matched
/medialive geometry: toolbar 74.78px and standard account card 270.09px at desktop width; mobile verification showed no horizontal overflow. - Browser network interception added a second Qwen account temporarily; both Qwen cards rendered independently and total card count increased from three to four.
- Confirmed all three live AI account avatars load as real remote images in the admin browser.
- Fixed the desktop AI authorized-account table to render
record.avatarUrl; initials now appear only when an account has no avatar. - Verification passed: admin production build, desktop-client Vue typecheck, targeted Prettier formatting, browser desktop/mobile inspection, and
git diff --check.