1ba29b9a09
Scope desktop media accounts by the authenticated desktop client_id so the same user logging in from Mac and Windows no longer sees a shared account list. The list, identity lookup, upsert, patch, tombstone and async health sink paths now all require matching client_id, and the active uniqueness index moves from (workspace, platform, uid) to (workspace, client, platform, uid). Also strengthen the desktop client_id seed: when the OS machine id is unavailable, fall back to a hashed fingerprint of stable hardware MAC addresses before the random installation id, so the same hardware keeps the same client across reinstalls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 KiB
61 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.