Files
geo/findings.md
T
root de30497f59 feat: add tenant and user management with migrations, handlers, and tests
- Implemented tenant and user management features including:
  - Tenant creation and management with associated migrations.
  - User creation and management with associated migrations.
  - Tenant membership management with associated migrations.
  - Platform user roles management with associated migrations.
  - Quota management with associated migrations.
  - Article and template management with associated migrations.
- Added HTTP handlers for templates and workspaces.
- Created tests for protected and public routes.
- Introduced a script to check tenant scope in SQL queries.
- Documented task plan for backend completion and frontend foundation.
2026-04-01 00:58:42 +08:00

101 lines
13 KiB
Markdown

# Findings & Decisions
## Requirements
- Verify the repository against the 9-step implementation plan provided by the user.
- Use `/Users/liangxu/Documents/test/geo-rankly/docs/superpowers/specs/2026-03-31-admin-web-backend-core-design.md` as the source of truth for the next development slice.
- Continue development immediately after identifying the earliest unfinished step.
## Research Findings
- The repository already contains core backend scaffolding under `server/`, including `cmd/tenant-api`, `internal/bootstrap`, `shared`, `tenant`, `migrations`, and SQL query files.
- `server/Makefile` already defines `dev-init`, `dev-api`, `migrate-up`, `sqlc-generate`, `seed`, `lint`, and `test`.
- The bootstrap layer already exposes `/api/health/live` and `/api/health/ready`.
- The design doc defines a sequential 9-step delivery plan and expects `sqlc` generated code under `internal/tenant/repository/generated/`, plus repository wrappers around it.
- The repository has 19 migration `.up.sql` files, matching the plan's schema count, and `cmd/dev-seed` seeds `admin@geo.local` plus plan/quota/template data.
- `internal/tenant/repository/` currently contains only query SQL, `sqlc.yaml`, `tx.go`, and placeholder integration tests; there is no `generated/` directory and no repository wrapper implementations.
- `auth_service.go`, `workspace_service.go`, `template_service.go`, `article_service.go`, and `brand_service.go` still issue SQL directly against `pgxpool.Pool`, which contradicts the design doc's Step 4 target.
- Running `make sqlc-generate` currently fails because `server/internal/tenant/repository/sqlc.yaml` sets `schema: "../../migrations/"`, which resolves to a non-existent path. The correct repository-relative path should point to `server/migrations`.
- After fixing `sqlc.yaml`, `make sqlc-generate` succeeds and produces typed code in `server/internal/tenant/repository/generated/`.
- Repository wrappers now exist for auth, workspace, template, article, quota, and audit queries, and the auth/workspace/template services consume them on the main code path.
- Refresh token rotation is now atomic in Redis via a Lua script in `session_store.go`, with tests covering successful rotation and hash mismatch rejection.
- `make test` and `make lint` both pass locally after cleaning up existing lint violations.
- A GitHub Actions workflow now exists at `.github/workflows/backend-ci.yml`; it runs `sqlc` generation, verifies generated code is committed, executes the tenant SQL scope guard, runs tests, and runs `golangci-lint`.
- The `server/Makefile` now exposes `tenant-scope-guard`, so the tenant filter check is available both locally and in CI.
- The `server/Makefile` no longer depends on a preinstalled `migrate` binary; it now runs `golang-migrate` via `go run -tags postgres`, which allowed `make dev-init` to run successfully on this machine.
- `make dev-init` now completes end-to-end: Docker services start, all 19 migrations apply, and seed data creates tenant/user/plan/template records.
- Runtime verification succeeded for `/api/health/live`, `/api/health/ready`, `POST /api/auth/login`, `GET /api/auth/me`, `POST /api/auth/refresh`, and `POST /api/auth/logout`.
- Negative auth checks also passed at runtime: the old access token returns `40103 token_revoked` after logout, and the old refresh token returns `40121 refresh_session_expired` after rotation.
- Workspace runtime verification passed for all four first-screen endpoints: `overview`, `recent-articles`, `quota-summary`, and `template-cards`.
- Template generation runtime verification passed end-to-end: creating a generation task produced an article, article detail returned `generate_status=completed`, article versions returned one version, and quota balance decreased from 100 to 99.
- Brand runtime verification passed for create keyword/question/competitor flows, question version history returned two versions after update, and soft-deleted brands can be recreated with the same name.
- The repository still has no `apps/` or `packages/` directories, so neither `admin-web` nor `ops-admin-web` has been started.
- The frontend architecture doc recommends `pnpm workspace + Vue 3 + TypeScript + ant-design-vue + Vite`, with shared packages for UI, shared DTOs, HTTP client, and TS config.
- The current backend already exposes enough stable endpoints for a first `admin-web` slice: `POST /api/auth/login`, `GET /api/auth/me`, and the four workspace endpoints under `/api/tenant/workspace/*`.
- Backend responses use a consistent envelope: `code`, `message`, `data`, and `request_id`, which makes a shared frontend API client straightforward.
- Local toolchain support for the frontend is present on this machine: `node v22.20.0`, `npm 10.9.3`, and `pnpm 10.28.2`.
- A new pnpm workspace now exists at the repo root, with `apps/admin-web` plus shared packages under `packages/shared-types`, `packages/http-client`, and `packages/tsconfig`.
- `apps/admin-web` is now a working Vue 3 + TypeScript + Vite 8 app with Ant Design Vue, Pinia, Vue Router, and Vue Query wired in.
- The frontend implements a persistent auth session store, login flow, route guard, auto-refresh-capable API client, and a tenant-facing application shell.
- The workspace page is wired to live backend data through the four dashboard endpoints and renders template cards, stats, quota, and recent articles.
- Placeholder routes now exist for template creation, custom generation, optimization, media, brands, tracking, and knowledge so the navigation shell is ready for incremental page delivery.
- `pnpm build:admin` passes successfully, producing a production build under `apps/admin-web/dist/`.
- Static preview verification passed via `vite preview` and HTTP checks against `http://127.0.0.1:4173/login`, which returned `HTTP/1.1 200 OK` plus the built asset references.
- Gemini CLI was tested but then abandoned for this turn: `gemini-3.1-pro-preview` consistently returned `429 MODEL_CAPACITY_EXHAUSTED`, and the user explicitly requested not to use Gemini afterward.
- After the user indicated Playwright was fixed, browser-level verification succeeded through the Playwright CLI path rather than the broken MCP path.
- Browser testing exposed one real frontend bug: the login CTA rendered correctly but did not submit the form on click until it was explicitly bound to `handleSubmit`.
- After the login-button fix, a Playwright end-to-end flow successfully loaded `/login`, signed in with the seeded account, reached `/workspace`, and verified the presence of the workspace heading plus the template and recent-content sections.
- The production bundle size improved substantially after switching Ant Design Vue registration from full-plugin mode to per-component registration; the main JS chunk dropped from roughly `1.4 MB` to about `747 kB` before gzip.
- The currently exposed tenant-facing backend interfaces fall into four frontend-covered groups: auth, workspace, templates/articles, and brands.
- The reference screenshots were re-read using position-aware OCR extraction, which made the layout intent clear beyond the raw text labels.
- `docs/refer/工作台.png` places the main content in a left-heavy column with template cards above recent articles, while the right side holds the compact stats cluster; the quota/plan card sits in the left sidebar footer rather than the main canvas.
- `docs/refer/模板创作.png` uses a top page hero, a horizontal filter/action strip, an article table below it, and a separate template-selection layer before entering a 3-step generation flow.
- `docs/refer/文擎GEO/模版创作-新建模版-创建topx文章-步骤一.png` and `...步骤二.png` show the generation flow as a wizard: step 1 basic info plus brand/keyword/competitor context, step 2 title and structure selection, step 3 generation.
- `docs/refer/品牌词库.png` uses a top brand card rail, then a split content area with keyword navigation on the left and question management on the right; the competitor library lives under a sibling tab.
- `docs/refer/媒体管理.png` confirms the overall visual system: page hero under the content header, three-step guide card near the top, and white cards on a cool gray background with the same left navigation shell.
- The user explicitly asked for i18n and styling discipline during implementation: text should move behind translation keys, and component styles should live in `<style>` blocks rather than inline attributes.
- `pnpm dev:admin` regressed temporarily after the route graph referenced a missing `BrandsView.vue`; adding the missing view, installing the new frontend dependency set, and rerunning checks restored the Vite startup path.
- `pnpm typecheck:admin` now passes after introducing the i18n scaffold, restoring `AppShell.vue` to the user's preferred version, and removing inline styles from the Vue SFC templates.
## Technical Decisions
| Decision | Rationale |
|----------|-----------|
| Verify by code inspection first, then run targeted commands | Faster way to establish step coverage before making changes |
| Use the design doc as the acceptance reference when repository behavior is ambiguous | User explicitly pointed to this document for next-step development |
| Treat Step 4 as the current development target unless command verification disproves it | Earlier steps have visible artifacts, but repository/sqlc acceptance is not yet met |
| Fix `sqlc` generation and introduce repository wrappers before touching later roadmap items | This is the first broken acceptance gate and an architectural dependency for the service layer |
| Close Step 9 by adding repository-scoped CI rather than a repo-wide generic pipeline | The remaining missing acceptance item was backend CI plus the tenant scope guard |
| Resume into `admin-web` instead of `ops-admin-web` | Only tenant-facing APIs exist in the repository today, so this is the only frontend slice that can be meaningfully wired end to end |
| Keep the initial frontend page set broad in navigation but shallow in implementation | This gives the repo a usable admin shell now without inventing missing backend modules for later pages |
| Use templates/articles and brands as the primary implementation targets for this turn | They are the remaining backend-backed pages still missing real frontend coverage |
| Use screenshot-derived spatial structure as an implementation constraint | Needed to satisfy the user's requirement to follow layout and placement, not just labels |
| Introduce a minimal `vue-i18n` foundation now instead of leaving hard-coded strings in new pages | The user explicitly called out the current i18n approach as non-standard |
| Keep `AppShell.vue` on the user-preferred version and avoid structural/style rewrites there | The user said that file is managed elsewhere and only allowed inline-style cleanup |
## Issues Encountered
| Issue | Resolution |
|-------|------------|
| Repository is fully untracked in git status output | Avoid relying on git history; verify via filesystem and test commands instead |
| `make sqlc-generate` fails before any code is generated | Repair the `sqlc.yaml` schema path and then build repository wrappers around generated queries |
| `go run` migrate initially failed with `unknown driver postgres` | Added `-tags postgres` to the Makefile-managed migrate command |
| Playwright MCP could not open a browser session locally because it tried to create `/.playwright-mcp` | Use `vite preview` plus `curl` verification for this turn instead of spending time on browser tool plumbing |
## Resources
- `/Users/liangxu/Documents/test/geo-rankly/docs/superpowers/specs/2026-03-31-admin-web-backend-core-design.md`
- `/Users/liangxu/Documents/test/geo-rankly/server/Makefile`
- `/Users/liangxu/Documents/test/geo-rankly/server/cmd/tenant-api/main.go`
- `/Users/liangxu/Documents/test/geo-rankly/server/internal/bootstrap/bootstrap.go`
- `/Users/liangxu/Documents/test/geo-rankly/server/internal/shared/auth/session_store.go`
- `/Users/liangxu/Documents/test/geo-rankly/server/internal/tenant/repository/sqlc.yaml`
- `/Users/liangxu/Documents/test/geo-rankly/server/scripts/check_tenant_scope.sh`
- `/Users/liangxu/Documents/test/geo-rankly/.github/workflows/backend-ci.yml`
- `/Users/liangxu/Documents/test/geo-rankly/server/docker-compose.yaml`
- `/Users/liangxu/Documents/test/geo-rankly/apps/admin-web`
- `/Users/liangxu/Documents/test/geo-rankly/packages/shared-types/src/index.ts`
- `/Users/liangxu/Documents/test/geo-rankly/packages/http-client/src/index.ts`
## Visual/Browser Findings
- Reviewed the reference screenshots for `工作台.png` and `模板创作.png` and matched the new UI to the same left-nav plus airy card/table composition.
- Browser automation verification was attempted but blocked by the local Playwright MCP directory error; preview HTTP verification succeeded instead.
- Later browser verification succeeded with Playwright CLI, and the captured login/workspace screenshots matched the intended layout and data density.
- Position-aware OCR of the reference images confirmed the sidebar navigation occupies roughly the left 10-12% of the frame, with content titles aligned at the upper-left of the main canvas and most action buttons aligned to the right edge of page headers.
- The workspace screenshot places stats on the upper-right and the recent-articles table directly beneath the template card block, so the existing all-grid treatment should be tightened into a more asymmetric two-column composition.