Files
geo/progress.md
T
root 745cdd79cf feat(compliance): add content compliance detection across tenant, ops, and clients
Implements the Revision 8/9 compliance design: tenant + ops backends, ops-web
content-safety pages, admin-web editor/publish gate integration, desktop publish
block surfacing, and supporting migrations / shared types / config plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 20:48:14 +08:00

58 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/k3s kustomize 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, plus frontend and ops-web.
    • Added Dockerfile.ops-web so the operations frontend can be built as a deployable nginx image.
    • Updated the offline packaging script to build/save ops-api, kol-assist-worker, and ops-web, and to include the k3s directory in generated deploy packages.
    • Updated the offline compose override and .env.example with 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/k3s rendered 30 Kubernetes objects.
    • Local YAML parsing of the rendered manifest passed.
    • bash -n deploy/scripts/package.sh && bash -n deploy/scripts/load-and-start.sh passed.
    • git diff --check passed.
    • pnpm --filter ops-web build passed.
    • pnpm --filter admin-web typecheck passed.
  • Notes:
    • kubectl apply --dry-run=client could not complete locally because the configured kube-apiserver at 127.0.0.1:26443 is 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-web tracking 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-plugin readiness and trying to kickoff a plugin cycle even though monitoring collection is now meant to run silently through desktop-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-now server 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.vue to remove the plugin kickoff path, call only the backend collect-now endpoint, and disable the CTA with an explicit reason tooltip when brand/keyword/client-online requirements are not met.
    • Added the missing desktop_client_offline frontend error mapping plus new i18n strings for the button gating reasons.
  • 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-core is installed but connectOverCDP() is not wired, while hidden Electron execution already exists via BrowserWindow and WebContentsView.
    • Added monitor-scheduler.ts as 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.ts so 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.ts as a reusable hidden-browser manager that launches hidden Electron BrowserWindow instances on account-bound sessions and attaches Playwright via chromium.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 declares executionMode: "playwright".
    • Kept the existing hidden WebContentsView path intact so current adapters like Doubao continue to work unchanged.
  • 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 gofmt on the modified Go files after the event metadata changes.
    • Verified pnpm --filter @geo/desktop-client typecheck passes.
    • Verified pnpm --filter @geo/desktop-client build passes.
    • Verified pnpm --filter admin-web typecheck still passes after the shared-type event additions.
    • Verified go test ./internal/tenant/app/... passes from server/.
  • 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 qwen monitoring flow into a new desktop Playwright adapter that drives Tongyi's in-page managers via page.evaluate() and extracts answer/source data from __qianwenChatAPI.
    • Registered the new qwen monitor 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, and deepseek require active login before execution; qwen, doubao, and wenxin are allowed to run anonymously when needed.
  • 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 typecheck passes after the Qwen adapter, bind-flow, and auth-policy updates.
    • Verified pnpm --filter @geo/desktop-client build passes 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 like tongyi_sso_ticket, tongyi_sso_ticket_hash, and b-user-id are 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.
  • 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/prompts package to centralize platform template seed prompts and runtime prompt fragments.
    • Refactored cmd/dev-seed, template_prompt.go, template_assist.go, prompt_generate_service.go, and knowledge_service.go to read prompt text from the new package.
    • Corrected invalid JSON quoting in the seed custom_placeholder fields 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 gofmt across 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-seed from server/ and confirmed the affected packages compile and tests pass.
  • 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/articles and brands, while custom/media/tracking/knowledge still 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-i18n setup with zh-CN and en-US message bundles, locale persistence, and Ant Design locale switching.
    • Reworked LoginView, WorkspaceView, TemplatesView, ArticleDetailDrawer, TemplateGenerationDrawer, PageHero, and BrandsView to stop using inline styles and to use component-local <style> blocks.
    • Restored AppShell.vue to the user-preferred version and only moved its inline style attributes into named classes.
    • Fixed the broken pnpm dev:admin startup path by adding the missing BrandsView.vue, running pnpm install, and re-running pnpm typecheck:admin plus pnpm dev:admin.
  • 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/ or packages/ directories.
    • Locked the next useful slice to a tenant-facing admin-web foundation 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-web with Vite 8, Vue 3, TypeScript, Ant Design Vue, Pinia, Vue Router, and Vue Query.
  • 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 install for the new workspace and generated pnpm-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:admin successfully and confirmed production assets were emitted.
    • Ran pnpm --filter admin-web preview --host 127.0.0.1 --port 4173 and verified /login returned HTTP/1.1 200 OK with 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.
  • 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, and server/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 sqlc and repository layout.
    • Confirmed Step 4 is the earliest incomplete milestone because the generated code directory and repository wrappers are missing.
    • Ran make sqlc-generate and observed a failing schema path in sqlc.yaml.
  • 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.yaml and regenerated sqlc output under server/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_store tests.
    • Cleaned existing lint violations that were blocking local verification.
  • 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-generate after the final code state and confirmed generation succeeds.
    • Ran go test ./..., then make 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.
  • 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-guard to the backend Makefile so CI and local verification use the same entrypoint.
    • Re-ran make tenant-scope-guard, make test, and make lint after the CI-related edits.
    • Updated the backend Makefile to run golang-migrate through go run -tags postgres instead of requiring a preinstalled migrate binary.
    • Ran make dev-init successfully, including Docker startup, migrations, and seed data.
    • Started tenant-api and verified health endpoints plus auth login/me/refresh/logout behavior with positive and negative checks.
  • 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_quotas is configured as collect_frequency = daily, but the inspected runtime does not contain a daily monitoring task generation worker.

Phase 23: Monitoring Daily Task Generation Repair

  • Status: complete
  • Actions taken:
    • Added server/internal/tenant/app/monitoring_daily_task_worker.go.
    • Wired MonitoringDailyTaskWorker into server/cmd/scheduler/main.go.
    • Added server/internal/tenant/app/monitoring_daily_task_worker_test.go for 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_tasks rollout plus primary_client_id; otherwise it skips the plan and records SkippedPlanCount rather than creating orphan automatic/legacy rows.
    • Removed Go runtime and dev-seed dependency on tenant_monitoring_quotas: daily plans now come from desktop_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: publishMonitorDesktopTaskAvailable now receives a 5-second child context derived from the worker tick context instead of context.Background().
  • Verification:
    • go test ./internal/tenant/app -run 'Test.*MonitoringDaily|Test.*Monitoring|TestEncodeMonitoringProjectionRebuildEnvelope|TestBuildMonitoringRawPayload' -count=1 passed.
    • go test ./cmd/scheduler ./cmd/dev-seed ./internal/tenant/app -count=1 passed.
    • 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.go with 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 runOnce result, including zero-work ticks and fatal errors.
    • Exposed /metrics in Prometheus text format and /api/internal/metrics/monitoring/daily-tasks as JSON.
    • Started the scheduler's health/metrics HTTP server on scheduler.http_port default 8081.
    • 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=1 passed.
    • go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestReconcile|TestResolve|TestIntersect|TestFilter' -count=1 passed.
    • go test ./cmd/scheduler ./internal/bootstrap ./internal/shared/config -count=1 passed.
    • go test ./cmd/scheduler ./cmd/dev-seed ./internal/tenant/app -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 25: Heartbeat Primary Stability Hardening

  • Status: complete
  • Actions taken:
    • Replaced heartbeat primary resolution with a per-tenant/per-workspace desktop_client_primary_leases lease 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_at ordering from the current-user registered-client lookup so UI platform selection is not heartbeat-driven.
    • Added migration 20260424130000_add_desktop_primary_leases with the lease table, backfill, and active desktop-client lookup indexes.
    • Added a unit test for the lease-claim decision matrix.
  • Verification:
    • go test ./internal/tenant/app -run 'TestShouldClaimHeartbeatPrimaryLease|Test.*MonitoringDaily|TestReconcile|TestResolve|TestIntersect|TestFilter' -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 26: Scheduler Metrics HTTP Hardening

  • Status: complete
  • Actions taken:
    • Added scheduler.http_host with default 127.0.0.1.
    • Added scheduler.internal_metrics_token, with env overrides SCHEDULER_INTERNAL_METRICS_TOKEN / SCHEDULER_METRICS_TOKEN.
    • Protected /metrics and /api/internal/metrics/monitoring/daily-tasks with token auth.
    • Changed scheduler.http_port < 0 to mean explicit HTTP disablement; 0 still defaults to 8081.
    • Replaced app.Engine.Run(... Fatalf ...) with http.Server.ListenAndServe, non-fatal error logging, and graceful Shutdown.
    • Added scheduler HTTP auth/address tests and config normalization/env tests.
  • Verification:
    • go test ./cmd/scheduler ./internal/shared/config -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 27: Scheduler Worker Graceful Shutdown

  • Status: complete
  • Actions taken:
    • Added blocking Run(ctx) methods to scheduler workers while keeping existing Start(ctx) wrappers.
    • Updated cmd/scheduler to create workers explicitly and run them under a sync.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.
  • Verification:
    • go test ./cmd/scheduler ./internal/scheduler ./internal/tenant/app -run 'TestScheduler|TestShouldClaimHeartbeatPrimaryLease|Test.*MonitoringDaily' -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

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 TrackingView to 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 TrackingQuestionDetailView to 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=1 passed.
    • pnpm typecheck:admin passed.
    • Browser regression against admin-web with platform_authorization_status = no_authorized_platforms passed for dashboard and question detail; dashboard does not show a no-authorized alert.
    • go test ./... passed from server/.
    • pnpm build:admin passed; it still reports existing bundle/CSS warnings unrelated to this change.
    • git diff --check passed.

Phase 29: Monitoring Six-Platform Display Contract

  • Status: complete
  • Actions taken:
    • Changed loadMonitoringProjectionPlatforms to 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_ids to dashboard runtime and shared frontend types.
    • Updated TrackingView collect-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.
  • Verification:
    • go test ./internal/tenant/app -run 'TestDefaultMonitoringPlatformMetadata|TestLoadMonitoringProjectionPlatforms|TestMonitoringPlatformAuthorizationStatus|TestReconcileEnabledMonitoringPlatforms|TestFilterMonitoringPlatforms' -count=1 passed.
    • pnpm typecheck:admin passed.
    • Browser regression confirmed a no-authorized-platform dashboard still renders all 6 platform names and keeps collect-now disabled.
    • go test ./... passed from server/.
    • pnpm build:admin passed; existing CSS/chunk warnings remain unrelated.
    • git diff --check passed.

Phase 30: Workspace Scope And Daily Config Visibility

  • Status: complete
  • Actions taken:
    • Added current-workspace context helpers and a WorkspaceScope middleware with X-Workspace-ID support 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 findLatestRegisteredClientForUser as 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.
  • Verification:
    • go test ./internal/shared/auth ./internal/shared/middleware ./internal/tenant/app -run 'TestCurrentWorkspaceID|TestWorkspaceScope|TestRequestedWorkspaceID|TestDecodeDailyMonitoringEnabledPlatforms|Test.*MonitoringDaily|TestMonitoringPlatformAuthorizationStatus|TestDefaultMonitoringPlatformMetadata|TestLoadMonitoringProjectionPlatforms' -count=1 passed.
    • go test ./internal/tenant/transport -run TestProtectedRoutes -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 31: Heartbeat Primary Lease Scalability

  • Status: complete
  • Actions taken:
    • Replaced per-heartbeat BEGIN / SELECT ... FOR UPDATE / UPDATE primary 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 INSERT or CAS-style UPDATE writes 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.
  • Verification:
    • go test ./internal/tenant/app -run 'TestDecideHeartbeatPrimaryLease|TestMonitoringHeartbeatPrimaryLeaseMetrics|TestBuildMonitoringRawPayloadKimi' -count=1 passed.
    • go test ./internal/tenant/transport -run 'TestProtectedRoutes|TestPublicRoutes' -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 32: Monitoring Heartbeat Snapshot Scalability

  • Status: complete
  • Actions taken:
    • Changed MonitoringCallbackService.Heartbeat to 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.
  • Verification:
    • go test ./internal/tenant/app -run 'TestDecideMonitoringHeartbeatSnapshot|TestMonitoringHeartbeatSnapshotMetrics|TestDecideHeartbeatPrimaryLease|TestMonitoringHeartbeatPrimaryLeaseMetrics' -count=1 passed.
    • go test ./internal/tenant/app -count=1 passed.
    • go test ./internal/tenant/transport -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 33: Prometheus Metrics Exposition Hardening

  • Status: complete
  • Actions taken:
    • Added prometheus/client_golang and replaced custom hand-written Prometheus text builders with prometheus.Collector implementations plus promhttp.
    • Kept existing JSON snapshot endpoints unchanged.
    • Changed scheduler /metrics to serve a dedicated registry containing daily-task metrics plus Go runtime and process collectors.
    • Changed tenant-api internal heartbeat Prometheus endpoints to serve through promhttp as 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.
  • Verification:
    • go test ./internal/tenant/app -run 'TestMonitoringDailyTaskMetrics|TestMonitoringDailyTaskPrometheus|TestMonitoringSchedulerMetricsPrometheusHandler|TestMonitoringHeartbeatPrimaryLeaseMetrics|TestMonitoringHeartbeatSnapshotMetrics' -count=1 passed.
    • go test ./cmd/scheduler ./internal/tenant/transport -run 'TestScheduler|TestProtectedRoutes|TestPublicRoutes|TestDesktopClientRoutes' -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 34: Daily Task Batch Materialization

  • Status: complete
  • Actions taken:
    • Changed ensureDailyMonitoringCollectTasks from per-candidate tx.Exec to a single batched INSERT ... SELECT FROM unnest(...).
    • Batched arrays carry question_id, question_hash, ai_platform_id, and dispatch_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 via RowsAffected.
  • Verification:
    • go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestMonitoringDailyTaskMetrics|TestMonitoringDailyTaskPrometheus|TestMonitoringSchedulerMetricsPrometheusHandler' -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

Phase 35: Daily Plan SQL Decomposition

  • Status: complete
  • Actions taken:
    • Split loadDailyMonitoringPlans into loadDailyMonitoringPrimaryClientPlans, 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.
  • Verification:
    • go test ./internal/tenant/app -run 'TestBuildDailyMonitoringPlansFromSelectedClients|Test.*MonitoringDaily' -count=1 passed.
    • go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestMonitoringDailyTaskMetrics|TestMonitoringDailyTaskPrometheus|TestMonitoringSchedulerMetricsPrometheusHandler' -count=1 passed.
    • go test ./... passed from server/.
    • git diff --check passed.

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.health no longer has to be live.
    • 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.
  • Verification:
    • go test ./internal/tenant/app -run 'Test.*MonitoringDaily|TestMonitoringPlatformAuthorizationStatus|TestReconcileEnabledMonitoringPlatforms|TestFilterMonitoringPlatforms|TestDefaultMonitoringPlatformMetadata|TestLoadMonitoringProjectionPlatforms' -count=1 passed.
    • pnpm --filter admin-web typecheck passed.
    • go test ./... passed from server/.
    • pnpm --filter admin-web build passed.
    • git diff --check passed.

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.ts with in-memory queueing, same-platform active locks, and 3-6 second platform cooldowns.
    • Refactored runtime-controller.ts so 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_CONCURRENCY as an optional cap and a reserved publish slot for monitor budgeting.
    • Exposed publishScheduler in the desktop runtime snapshot and added scheduler unit tests.
  • Verification:
    • pnpm --filter @geo/desktop-client build passed.
    • pnpm --filter @geo/desktop-client test passed: 5 files, 26 tests.
    • git diff --check passed.
    • pnpm --filter @geo/desktop-client typecheck failed before checking runtime changes because electron.vite.config.ts has a Vite 5/8 plugin type mismatch.

2026-04-28 Dongchedi Publish Debug

  • Status: in_progress
  • Actions taken:
    • Queried local geo-postgres through docker exec because psql is not installed on the host.
    • Verified article 95 reconstructs to normal markdown through repository.LoadArticleVersionContent; removed the temporary inspection test after use.
    • Updated apps/desktop-client/src/main/adapters/dongchedi.ts so body images first try Dongchedi spice/image; local/relative images use ImageX upload and then run through spice/image before replacement.
    • Added redacted Dongchedi publish rejection diagnostics to the adapter error payload/logs.
    • Added apps/desktop-client/src/main/adapters/dongchedi-content.ts and a unit test to downgrade table HTML to paragraph rows before Dongchedi submit.
    • Followed up after another server exception retry where diagnostics showed no table tags, no local asset URL, and one body image.
    • Removed &nbsp; entities from Dongchedi table-downgraded body HTML.
    • Changed body image handling so ImageX-uploaded local images try Dongchedi spice/image through 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 returned server exception with content_image_upload_strategies = ['imagex_direct_fallback'].
    • Removed the direct ImageX正文图 fallback. Local正文图片 that cannot be converted to a Dongchedi spice URL are now removed from content instead of failing early or submitting a rejected ImageX URL.
    • After a no-body-image retry still returned server exception, changed extra.content_word_cnt from the reference extension's hardcoded 267 to the actual text count of the final submitted HTML.
    • Added content_word_cnt and computed_text_count to 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.
  • Verification:
    • pnpm --filter @geo/desktop-client typecheck passed.
    • pnpm --filter @geo/desktop-client test -- dongchedi passed.
    • pnpm --filter @geo/desktop-client test passed.
    • pnpm --filter @geo/desktop-client build passed and refreshed out/main/bootstrap.cjs.
    • git diff --check passed.

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_templates and currently seeded by server/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.yml validation-only after the user clarified it should not own images.
  • Scoped frontend-ci.yml to admin-web and ops-web plus 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, and sh -n over all workflow run blocks.

2026-05-03T03:03:09Z - Stable PgBouncer Deployment

  • Confirmed the existing repository topology uses application-side pgxpool and 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 pgbouncer and monitoring-pgbouncer to production Docker Compose and k3s using edoburu/pgbouncer:v1.24.1-p1, POOL_MODE=session, and AUTH_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_PASSWORD placeholders and changed DatabaseConfig.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 config
    • kubectl kustomize deploy/k3s plus local YAML parse
    • bash -n deploy/scripts/package.sh
    • git diff --check
    • go test ./internal/shared/config ./internal/shared/repository/postgres ./internal/ops/config
    • Temporary PgBouncer container attached to existing server_default network returned SELECT 1 through 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.md and 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() through GateForPublish, including effective article version resolution, target platform aggregation, block/needs_ack errors with serialized check details, and transactional ack consumption.
  • Exposed ArticleDetailResponse.current_version_id and 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-generate
    • go test ./...
    • pnpm --filter admin-web typecheck
    • pnpm --filter ops-web typecheck
    • pnpm --filter @geo/desktop-client typecheck
    • pnpm --filter admin-web build
    • pnpm --filter ops-web build
    • pnpm --filter @geo/desktop-client build
    • git 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_policies to an id=1 global singleton with no scope / tenant_id columns; 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 typecheck
    • go test ./internal/ops/app ./internal/ops/transport ./internal/tenant/compliance ./cmd/ops-api