793 lines
60 KiB
Markdown
793 lines
60 KiB
Markdown
# 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 | pass |
|
|
| 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 ` ` 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`
|
|
|
|
## 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 `running` updates 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.
|
|
- 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.Rows` and 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-generate`
|
|
- `cd server && go test ./...`
|
|
- `git diff --check`
|
|
- `ruby -e 'require "yaml"; YAML.load_file("deploy/monitoring/article-generation-alerts.yml"); puts "ok"'`
|