diff --git a/docs/superpowers/plans/2026-07-21-forest-ai-api-backend.md b/docs/superpowers/plans/2026-07-21-forest-ai-api-backend.md new file mode 100644 index 0000000..7a019d0 --- /dev/null +++ b/docs/superpowers/plans/2026-07-21-forest-ai-api-backend.md @@ -0,0 +1,230 @@ +# 森林AI API And Backend Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 建立不兼容旧接口的 `/api/v1` camelCase 契约,并把后端拆分为职责清晰、以 identity 对外的业务模块。 + +**Architecture:** Gorm 模型继续集中在 `internal/models`,HTTP request/response DTO 放在各业务包。`httpx` 负责通用错误、identity 参数和 CORS;service 负责所有权与业务规则;handler 不直接构造存储路径或查询数据库。 + +**Tech Stack:** Go、Gin、Gorm、PostgreSQL、httptest。 + +## Global Constraints + +- 外部 API 前缀为 `/api/v1`,字段为 camelCase,对外 ID 为 UUIDv7 identity。 +- 数据库模型和表名前缀规则保持 `SenlinAgent` / `senlin_agent_`。 +- session token 必须签名并过期;handler 只从认证 middleware 读取用户。 +- 文件路径必须由文件服务构造;标签必须限定在项目内。 +- AI 请求必须限流并记录 provider、key 类型、action、status 和 error。 +- 允许不兼容旧 API,但不得自动删除生产数据。 + +--- + +### Task 1: 通用 v1 路由、错误和 identity 参数 + +**Files:** +- Create: `backend/internal/httpx/response.go` +- Create: `backend/internal/httpx/params.go` +- Create: `backend/internal/httpx/response_test.go` +- Modify: `backend/internal/httpx/router.go` +- Modify: `backend/internal/httpx/router_test.go` +- Modify: `backend/internal/config/config.go` +- Modify: `backend/etc/agent.dev.yaml` + +**Interfaces:** +- Produces: `Error(c, status, code, message)`, `IdentityParam(c, name) (string, bool)` and `/api/v1` route group. + +- [ ] **Step 1: Write failing response and routing tests** + +```go +func TestErrorUsesStableEnvelope(t *testing.T) { + recorder := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(recorder) + Error(ctx, http.StatusBadRequest, "invalid_request", "请求参数无效") + require.JSONEq(t, `{"error":{"code":"invalid_request","message":"请求参数无效"}}`, recorder.Body.String()) +} + +func TestStatusLivesUnderAPIV1(t *testing.T) { + router := NewRouter(config.Config{Env: "test"}) + req := httptest.NewRequest(http.MethodGet, "/api/v1/status", nil) + recorder := httptest.NewRecorder() + router.ServeHTTP(recorder, req) + require.Equal(t, http.StatusOK, recorder.Code) +} +``` + +- [ ] **Step 2: Verify tests fail** + +Run: `go test ./internal/httpx -run 'TestErrorUsesStableEnvelope|TestStatusLivesUnderAPIV1' -v` + +Expected: FAIL because helpers and route do not exist. + +- [ ] **Step 3: Implement response helpers and configured CORS** + +Use: + +```go +type ErrorBody struct { Code string `json:"code"`; Message string `json:"message"` } +type ErrorEnvelope struct { Error ErrorBody `json:"error"` } + +func Error(c *gin.Context, status int, code, message string) { + c.AbortWithStatusJSON(status, ErrorEnvelope{Error: ErrorBody{Code: code, Message: message}}) +} +``` + +Change the API group to `router.Group("/api/v1")`. Add `AllowedOrigins []string` to config and build the CORS map from config with safe development defaults. + +- [ ] **Step 4: Verify the package** + +Run: `go test ./internal/httpx -v` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add backend/internal/httpx backend/internal/config backend/etc/agent.dev.yaml +git commit -m "refactor(api): introduce v1 response contract" +``` + +### Task 2: 项目 DTO、identity 查询与项目更新 + +**Files:** +- Create: `backend/internal/logic/projects/dto.go` +- Create: `backend/internal/logic/projects/ownership.go` +- Modify: `backend/internal/logic/projects/service.go` +- Modify: `backend/internal/logic/projects/handlers.go` +- Modify: `backend/internal/logic/projects/handlers_test.go` +- Modify: `backend/internal/logic/projects/service_test.go` + +**Interfaces:** +- Produces: `ProjectDTO`, `CreateProjectRequest`, `UpdateProjectRequest`, `FindOwnedProject(userID, identity)`. + +- [ ] **Step 1: Write failing contract tests** + +Add tests that create a project, call `GET /api/v1/projects`, assert `id` equals its identity, assert no numeric `ID` field exists, and patch `name`, `identifier`, `icon`, `background`, `description` through `PATCH /api/v1/projects/:projectId`. + +- [ ] **Step 2: Verify failures** + +Run: `go test ./internal/logic/projects -run 'TestListProjectsUsesIdentityDTO|TestUpdateProject' -v` + +Expected: FAIL on old response and missing PATCH route. + +- [ ] **Step 3: Implement explicit DTO mapping** + +```go +type ProjectDTO struct { + ID string `json:"id"` + Name string `json:"name"` + Identifier string `json:"identifier"` + Icon string `json:"icon"` + Background string `json:"background"` + Description string `json:"description"` +} + +func projectDTO(project models.SenlinAgentProject) ProjectDTO { + return ProjectDTO{ID: project.Identity, Name: project.Name, Identifier: project.Identifier, Icon: project.Icon, Background: project.Background, Description: project.Description} +} +``` + +Resolve projects with `owner_id = ? AND identity = ?`. Return 404 for missing owned projects and 409 for duplicate identifiers. + +- [ ] **Step 4: Verify project contracts** + +Run: `go test ./internal/logic/projects -v` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add backend/internal/logic/projects +git commit -m "refactor(api): expose project identity DTOs" +``` + +### Task 3: 拆分工作区聚合查询 + +**Files:** +- Create: `backend/internal/logic/projects/workspace.go` +- Create: `backend/internal/logic/projects/workspace_test.go` +- Modify: `backend/internal/logic/projects/service.go` +- Modify: `backend/internal/logic/projects/dto.go` + +**Interfaces:** +- Produces: `Workspace(userID uint, projectIdentity string) (WorkspaceDTO, error)`. + +- [ ] **Step 1: Move existing workspace tests to identity-based expectations** + +Assert that project, tasks, tags, notes/sources, sessions and cron plans all expose string identities and RFC3339 timestamps, and that tasks return the actual project-scoped tag. + +- [ ] **Step 2: Verify tests fail against the old aggregate** + +Run: `go test ./internal/logic/projects -run Workspace -v` + +Expected: FAIL on numeric IDs and preformatted display times. + +- [ ] **Step 3: Move workspace-only code and remove presentation formatting** + +Move `workspaceCounts`, `workspaceChannels`, `workspaceInbox`, `workspaceTasks`, `workspaceAISessions`, `workspaceNotesSources` and `workspaceCronPlans` into `workspace.go`. DTO times must use `time.Time`/`*time.Time` JSON serialization; delete `displayTime`, `displayOptionalTime` and `displayDuration` from backend presentation logic. + +- [ ] **Step 4: Verify and check file focus** + +Run: `go test ./internal/logic/projects -v` + +Expected: PASS; `service.go` contains project CRUD only and is under 300 lines. + +- [ ] **Step 5: Commit** + +```powershell +git add backend/internal/logic/projects +git commit -m "refactor(backend): isolate workspace aggregation" +``` + +### Task 4: 任务、标签、资料与计划任务职责迁移 + +**Files:** +- Create: `backend/internal/logic/tasks/dto.go` +- Create: `backend/internal/logic/tasks/handlers.go` +- Create: `backend/internal/logic/tasks/handlers_test.go` +- Create: `backend/internal/logic/files/handlers.go` +- Create: `backend/internal/logic/files/handlers_test.go` +- Create: `backend/internal/logic/projects/tag_handlers.go` +- Create: `backend/internal/logic/projects/cron_handlers.go` +- Modify: `backend/internal/logic/tasks/service.go` +- Modify: `backend/internal/logic/files/service.go` +- Modify: `backend/internal/logic/projects/handlers.go` +- Modify: `backend/cmd/api/main.go` + +**Interfaces:** +- Produces: identity-based Task DTO and separate route registrars for tasks/files/tags/cron plans. + +- [ ] **Step 1: Write failing registrar contract tests** + +Cover create/update task, create/list tag, upload source and create cron plan. Assert camelCase responses, identity IDs, project ownership, tag scope and source paths that do not contain absolute storage roots. + +- [ ] **Step 2: Verify tests fail** + +Run: `go test ./internal/logic/tasks ./internal/logic/files ./internal/logic/projects -v` + +Expected: FAIL because registrars and DTOs are missing. + +- [ ] **Step 3: Move handlers without weakening rules** + +`tasks.Service` must accept a DB transaction or repository dependency and retain explicit-share checks. `files.Handler` must call `files.Service.Save` before creating the source record. Tag and cron handlers may remain in `projects` but must not be in the core project handler file. + +- [ ] **Step 4: Register every handler under `/api/v1`** + +Construct and pass auth, projects, tasks, files, inbox, search and AI registrars in `cmd/api/main.go`. Add Chinese comments to ownership, sharing, Inbox confirmation and file-path boundaries. + +- [ ] **Step 5: Verify backend** + +Run: `go test ./...` + +Expected: PASS. + +- [ ] **Step 6: Commit** + +```powershell +git add backend/internal/logic backend/cmd/api/main.go +git commit -m "refactor(backend): split project write responsibilities" +``` + diff --git a/docs/superpowers/plans/2026-07-21-forest-ai-docs-verification.md b/docs/superpowers/plans/2026-07-21-forest-ai-docs-verification.md new file mode 100644 index 0000000..a035f45 --- /dev/null +++ b/docs/superpowers/plans/2026-07-21-forest-ai-docs-verification.md @@ -0,0 +1,144 @@ +# 森林AI Documentation And Verification Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 统一开发配置、演示数据、README 和最终验证,使新开发者能够按文档启动森林AI并复现验收结果。 + +**Architecture:** Docker Compose、YAML 配置和 README 使用同一组开发默认值;本地数据通过显式 seed 命令创建。最终验证脚本只读取环境配置,不携带真实凭据。 + +**Tech Stack:** Docker Compose、PostgreSQL 16、Go、Node.js、Vite、Tauri。 + +## Global Constraints + +- 不提交真实凭据、本地数据库、文件存储、日志、审计截图或构建产物。 +- 开发配置可以包含明确标注的非生产默认值。 +- 程序启动不得自动 drop 表或清空生产数据。 +- README 必须为 UTF-8 中文,名称统一为“森林AI”。 + +--- + +### Task 1: 开发配置与演示数据一致性 + +**Files:** +- Modify: `infra/docker-compose.yml` +- Modify: `backend/etc/agent.dev.yaml` +- Modify: `backend/internal/config/config.go` +- Modify: `backend/internal/config/config_test.go` +- Modify: `backend/internal/seed/demo.go` +- Modify: `backend/internal/seed/demo_test.go` +- Modify: `.gitignore` + +**Interfaces:** +- Produces: one PostgreSQL DSN shared by Compose and development YAML; explicit `go run ./cmd/seed` reset-safe seed workflow. + +- [ ] **Step 1: Write failing configuration tests** + +Assert the loaded development config uses port 9150, `/api/v1` compatible CORS origins, a non-empty storage dir, and that seed is idempotent while preserving project-scoped tags. + +- [ ] **Step 2: Verify failures** + +Run: `go test ./internal/config ./internal/seed -v` + +Expected: FAIL where config lacks allowed origins or seed contracts. + +- [ ] **Step 3: Align Compose and YAML** + +Use the same development values in both files: user `agent`, password `agent`, database `agent`, host `localhost`, port `5432`. Keep secrets explicitly marked as development-only. Add `.superpowers/`, `backend/tmp/`, `backend/data/`, `apps/web_v1/test-results/` and build outputs to `.gitignore`. + +- [ ] **Step 4: Verify config and seed** + +Run: `go test ./internal/config ./internal/seed -v` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add infra/docker-compose.yml backend/etc/agent.dev.yaml backend/internal/config backend/internal/seed .gitignore +git commit -m "chore: align forest AI development setup" +``` + +### Task 2: 重写 README + +**Files:** +- Modify: `README.md` +- Modify: `docs/mvp-verification.md` + +**Interfaces:** +- Produces: authoritative local setup and verification guide. + +- [ ] **Step 1: Check every documented command before writing** + +Run the exact commands that README will contain: Compose startup, backend API startup, seed, Web dev server, backend tests, visual check, build and lint. Record only commands that actually succeed. + +- [ ] **Step 2: Replace README with the approved structure** + +Use these exact top-level sections: `产品定位`, `MVP 范围`, `技术栈`, `目录结构`, `快速开始`, `配置`, `API v1 概览`, `验证`, `桌面端`, `常见问题`, `安全说明`. + +Document `POST /api/v1/auth/login`, project/workspace, task/tag/source/cron, Inbox, search and AI session endpoints without embedding tokens or real secrets. + +- [ ] **Step 3: Update verification documentation** + +Include the current expected commands and artifact paths; remove stale Svelte references, old API paths, old product names and deprecated ports. + +- [ ] **Step 4: Verify text consistency** + +Run: + +```powershell +rg -n "SenlinAI Agent Workbench|森林Agent|/api/projects|apps/web/|Svelte" README.md docs/mvp-verification.md +``` + +Expected: no matches. + +- [ ] **Step 5: Commit** + +```powershell +git add README.md docs/mvp-verification.md +git commit -m "docs: update forest AI setup and verification" +``` + +### Task 3: 全量验证与前后截图对比 + +**Files:** +- Modify: `apps/web_v1/scripts/visual-check.mjs` +- Create: `docs/forest-ai-audit.md` + +**Interfaces:** +- Produces: repeatable desktop/mobile audit summary with final screenshots. + +- [ ] **Step 1: Run backend verification** + +Run: `go test ./...` + +Expected: PASS for every package. + +- [ ] **Step 2: Run frontend verification** + +Run: `node scripts/structure-check.mjs; $env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs; npm run build; npm run lint` + +Expected: PASS; build may report a size warning but no error. + +- [ ] **Step 3: Run PostgreSQL integration checks when DATABASE_URL is present** + +Run: `go test ./internal/models -run TestPostgresPing -v` + +Expected: PASS when `DATABASE_URL` is configured; otherwise the test reports its documented skip. + +- [ ] **Step 4: Capture final evidence** + +Capture and inspect 1440×1024 login, workspace, project overview and tasks, plus 390×844 login and project navigation. Compare against the five accepted audit screenshots from the design phase and document visible fixes and remaining limits in `docs/forest-ai-audit.md`. + +- [ ] **Step 5: Verify repository cleanliness** + +Run: `git status --short` + +Expected: only intended source/docs changes are present; no logs, test screenshots, database files or secrets. + +- [ ] **Step 6: Commit** + +```powershell +git add apps/web_v1/scripts/visual-check.mjs docs/forest-ai-audit.md +git commit -m "test: verify forest AI MVP unification" +``` + diff --git a/docs/superpowers/plans/2026-07-21-forest-ai-feature-alignment.md b/docs/superpowers/plans/2026-07-21-forest-ai-feature-alignment.md new file mode 100644 index 0000000..312bed1 --- /dev/null +++ b/docs/superpowers/plans/2026-07-21-forest-ai-feature-alignment.md @@ -0,0 +1,206 @@ +# 森林AI Feature Alignment Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 让前端核心工作流完整使用 `/api/v1`,补齐搜索、项目设置、Inbox 和受控 AI 会话,同时移除伪功能入口。 + +**Architecture:** 前端 API 层只认一种 camelCase DTO,页面事件由 `App` 编排后刷新聚合工作区。后端为搜索和 AI 会话提供独立 registrar;超出 MVP 的入口从页面移除。 + +**Tech Stack:** React、TypeScript、Gin、Gorm、Playwright、Go httptest。 + +## Global Constraints + +- 所有前端 ID 是 identity 字符串;不兼容 PascalCase 或数字 ID。 +- AI 未经用户确认不得创建任务、笔记或资料。 +- 核心操作必须有 loading、成功反馈和可执行的中文错误。 +- 不实现探索数据源、支付、窗口停靠、自主 Agent 或实时聊天。 + +--- + +### Task 1: 前端 API v1 客户端和错误类型 + +**Files:** +- Modify: `apps/web_v1/src/api/client.ts` +- Modify: `apps/web_v1/src/api/projects.ts` +- Modify: `apps/web_v1/src/api/mappers.tsx` +- Create: `apps/web_v1/src/api/search.ts` +- Create: `apps/web_v1/src/api/inbox.ts` +- Modify: `apps/web_v1/scripts/structure-check.mjs` + +**Interfaces:** +- Produces: `ApiError { status: number; code: string; message: string }` and camelCase DTOs only. + +- [ ] **Step 1: Add failing static checks** + +Reject `ID?`, `Name?`, `/api/projects`, and `number` project/task IDs in `src/api`. Require `/api/v1` in login and project API paths. + +- [ ] **Step 2: Verify failures** + +Run: `node scripts/structure-check.mjs` + +Expected: FAIL on legacy paths and PascalCase compatibility fields. + +- [ ] **Step 3: Implement one response contract** + +Parse the standard error envelope: + +```ts +export class ApiError extends Error { + constructor(public status: number, public code: string, message: string) { + super(message) + } +} +``` + +All DTOs use required camelCase fields and string IDs. Update date formatting to happen only in mappers. + +- [ ] **Step 4: Verify frontend types** + +Run: `node scripts/structure-check.mjs && npm run build && npm run lint` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add apps/web_v1/src/api apps/web_v1/scripts/structure-check.mjs +git commit -m "refactor(web): consume api v1 contracts" +``` + +### Task 2: 搜索与项目设置真实往返 + +**Files:** +- Create: `backend/internal/logic/search/handlers.go` +- Create: `backend/internal/logic/search/handlers_test.go` +- Modify: `backend/cmd/api/main.go` +- Modify: `apps/web_v1/src/pages/projects/project-topbar.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-sidebar.tsx` +- Modify: `apps/web_v1/src/app/App.tsx` + +**Interfaces:** +- `GET /api/v1/search?q=` returns `{items: SearchResultDTO[]}`. +- `PATCH /api/v1/projects/:projectId` persists settings and returns ProjectDTO. + +- [ ] **Step 1: Write failing search handler tests** + +Assert blank query returns 400 `invalid_query`, authenticated matching query returns project/task/note results, and another user's private objects are absent. + +- [ ] **Step 2: Verify backend failures** + +Run: `go test ./internal/logic/search -v` + +Expected: FAIL because handler is missing. + +- [ ] **Step 3: Implement search registrar and front-end search state** + +Topbar accepts `query`, `loading`, `onQueryChange`, `onSearch`. Submit on Enter or the Search button. Render results in an Arco dropdown/list and navigate to the owning project/channel when the result type is known. + +- [ ] **Step 4: Persist project settings** + +Replace the local `setWorkspaces`-only update with `updateProject(session, update)`, then call `loadWorkspaces` with the same identity. Keep the modal open on failure. + +- [ ] **Step 5: Verify** + +Run: `go test ./internal/logic/search ./internal/logic/projects -v; npm run build; npm run lint` + +Expected: PASS. + +- [ ] **Step 6: Commit** + +```powershell +git add backend/internal/logic/search backend/cmd/api/main.go apps/web_v1/src +git commit -m "feat: connect search and project settings" +``` + +### Task 3: Inbox 确认流与核心写操作 + +**Files:** +- Modify: `backend/internal/logic/inbox/handlers.go` +- Modify: `backend/internal/logic/inbox/service.go` +- Modify: `backend/internal/logic/inbox/service_test.go` +- Modify: `apps/web_v1/src/api/inbox.ts` +- Create: `apps/web_v1/src/pages/projects/project-inbox.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-channel-page.tsx` +- Modify: `apps/web_v1/src/app/App.tsx` + +**Interfaces:** +- Inbox capture/analyze/confirm uses identity strings. +- `confirm` accepts only suggestions returned for the same inbox item and current user. + +- [ ] **Step 1: Add failing identity and authorization tests** + +Test capture, analyze without writes, confirm selected task/note/source with source Inbox identity, and reject confirming another user's inbox item. + +- [ ] **Step 2: Verify failures** + +Run: `go test ./internal/logic/inbox -v` + +Expected: legacy numeric paths or authorization gaps fail new tests. + +- [ ] **Step 3: Implement v1 Inbox DTOs and page** + +The page shows item content, suggestion checkboxes and one `确认创建` action. Analysis results remain drafts until this action. On success refresh the workspace and show the created object count. + +- [ ] **Step 4: Verify core write operations** + +Run: `go test ./internal/logic/inbox ./internal/logic/tasks ./internal/logic/projects -v; npm run build; npm run lint` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add backend/internal/logic/inbox apps/web_v1/src +git commit -m "feat: connect inbox confirmation workflow" +``` + +### Task 4: 受控 AI 会话与伪功能清理 + +**Files:** +- Create: `backend/internal/logic/ai/handlers.go` +- Create: `backend/internal/logic/ai/handlers_test.go` +- Modify: `backend/internal/logic/ai/sessions.go` +- Modify: `backend/internal/logic/ai/gateway.go` +- Modify: `backend/cmd/api/main.go` +- Modify: `apps/web_v1/src/pages/projects/project-ai.tsx` +- Modify: `apps/web_v1/src/pages/workspace-explore.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-new-channel.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-statusbar.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-topbar.tsx` +- Modify: `apps/web_v1/scripts/visual-check.mjs` + +**Interfaces:** +- `GET/POST /api/v1/projects/:projectId/ai-sessions` lists/creates controlled sessions. +- No endpoint converts AI output into formal objects without a separate confirmation request. + +- [ ] **Step 1: Write failing AI handler tests** + +Assert session creation checks project ownership, rate limit runs before provider selection, call logs contain required fields, and the response contains no automatic object IDs. + +- [ ] **Step 2: Verify failures** + +Run: `go test ./internal/logic/ai -v` + +Expected: FAIL because handlers are missing. + +- [ ] **Step 3: Implement controlled session endpoints** + +Return a session DTO with identity, title, context, status and timestamps. If no provider key exists, return `ai_key_missing` without creating formal objects. + +- [ ] **Step 4: Remove unsupported controls** + +Remove active-looking sync/edit/delete actions from Explore, payment choices from the status bar, dock buttons, fake app launcher and nonfunctional channel save. Keep a concise “暂未开放” empty state only where navigation must remain visible. + +- [ ] **Step 5: Update visual checks and verify** + +Run: `go test ./...; $env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs; npm run build; npm run lint` + +Expected: all PASS, AI page has an `AI 助手` heading, and console errors are empty. + +- [ ] **Step 6: Commit** + +```powershell +git add backend/internal/logic/ai backend/cmd/api/main.go apps/web_v1/src apps/web_v1/scripts/visual-check.mjs +git commit -m "feat: align controlled AI sessions and MVP controls" +``` + diff --git a/docs/superpowers/plans/2026-07-21-forest-ai-frontend-foundation.md b/docs/superpowers/plans/2026-07-21-forest-ai-frontend-foundation.md new file mode 100644 index 0000000..c9fe922 --- /dev/null +++ b/docs/superpowers/plans/2026-07-21-forest-ai-frontend-foundation.md @@ -0,0 +1,248 @@ +# 森林AI Frontend Foundation Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 将 Web 客户端统一为“森林AI”品牌,并建立可在桌面和移动浏览器使用的基础布局与视觉系统。 + +**Architecture:** 保留 React、Arco Design 和现有工作台信息架构。品牌资产通过公共 SVG 文件引用,主题令牌集中到独立样式文件,移动导航状态由 `ProjectPage` 管理,避免组件各自实现断点逻辑。 + +**Tech Stack:** React 18、TypeScript 6、Vite 8、Arco Design、Playwright visual check、CSS custom properties。 + +## Global Constraints + +- 产品可见名称和 HTML title 必须为“森林AI”。 +- 主色固定为 `#165DFF`;ICON 使用已批准的年轮知识树方案。 +- 桌面优先,但 390×844 视口必须能够访问主内容。 +- 不增加新的前端运行时依赖。 +- 超出 MVP 的探索同步、支付、窗口停靠和自主 Agent 控件不得伪装为可用功能。 + +--- + +### Task 1: 品牌资产与静态契约 + +**Files:** +- Create: `apps/web_v1/public/senlinai-icon.svg` +- Modify: `apps/web_v1/public/favicon.svg` +- Modify: `apps/web_v1/index.html` +- Modify: `apps/web_v1/scripts/structure-check.mjs` +- Modify: `apps/web_v1/src/pages/login.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-topbar.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-rail.tsx` + +**Interfaces:** +- Produces: `/senlinai-icon.svg` as the single brand image consumed by login, topbar and project rail. + +- [ ] **Step 1: Add failing brand checks** + +Extend `structure-check.mjs` with exact assertions: + +```js +const html = readFileSync('index.html', 'utf8') +if (!html.includes('')) failures.push('index language must be zh-CN') +if (!html.includes('森林AI')) failures.push('document title must be 森林AI') +if (!existsSync('public/senlinai-icon.svg')) failures.push('missing public/senlinai-icon.svg') +for (const file of ['src/pages/login.tsx', 'src/pages/projects/project-topbar.tsx', 'src/pages/projects/project-rail.tsx']) { + const source = readFileSync(file, 'utf8') + if (!source.includes('/senlinai-icon.svg')) failures.push(`${file} must use the brand icon`) +} +``` + +- [ ] **Step 2: Verify the check fails** + +Run: `node scripts/structure-check.mjs` + +Expected: FAIL with `missing public/senlinai-icon.svg` and title/asset usage failures. + +- [ ] **Step 3: Add the approved SVG and replace all brand placeholders** + +Use one `` at decorative positions, and `aria-label="森林AI 工作台"` on the rail brand button. Set `lang="zh-CN"`, title `森林AI`, and favicon `/senlinai-icon.svg` in `index.html`. Replace visible `森林Agent` and `SenlinAI` labels with `森林AI`. + +- [ ] **Step 4: Verify brand contracts** + +Run: `node scripts/structure-check.mjs && npm run build && npm run lint` + +Expected: all commands PASS; no visible `S` placeholder remains in brand components. + +- [ ] **Step 5: Commit** + +```powershell +git add apps/web_v1/public apps/web_v1/index.html apps/web_v1/scripts/structure-check.mjs apps/web_v1/src/pages/login.tsx apps/web_v1/src/pages/projects/project-topbar.tsx apps/web_v1/src/pages/projects/project-rail.tsx +git commit -m "feat(web): apply forest AI brand identity" +``` + +### Task 2: 主题令牌、字体与基础文案 + +**Files:** +- Create: `apps/web_v1/src/styles/tokens.css` +- Modify: `apps/web_v1/src/main.tsx` +- Modify: `apps/web_v1/src/index.css` +- Modify: `apps/web_v1/src/App.css` +- Modify: `apps/web_v1/src/pages/workspace-body.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-overview.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-ai.tsx` + +**Interfaces:** +- Produces: semantic custom properties `--color-*`, `--space-*`, `--radius-*` used by all page CSS. + +- [ ] **Step 1: Add failing text and token checks** + +Add to `structure-check.mjs`: + +```js +const tokenSource = existsSync('src/styles/tokens.css') ? readFileSync('src/styles/tokens.css', 'utf8') : '' +for (const token of ['--color-primary: #165dff', '--font-sans', '--space-4: 16px']) { + if (!tokenSource.toLowerCase().includes(token)) failures.push(`missing token ${token}`) +} +for (const forbidden of ['森林Agent', 'AI智能体', '实时接口', '进度 60%']) { + for (const file of requiredFiles.filter((name) => name.endsWith('.tsx'))) { + if (readFileSync(file, 'utf8').includes(forbidden)) failures.push(`${file} contains forbidden copy ${forbidden}`) + } +} +``` + +- [ ] **Step 2: Verify failures** + +Run: `node scripts/structure-check.mjs` + +Expected: FAIL for missing tokens and old copy. + +- [ ] **Step 3: Introduce semantic tokens and Chinese system font** + +Create tokens beginning with: + +```css +:root { + --color-primary: #165dff; + --color-bg: #f7f8fa; + --color-panel: #ffffff; + --color-border: #e5e6eb; + --color-text: #1d2129; + --color-muted: #6b7785; + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; + --space-1: 4px; + --space-2: 8px; + --space-3: 12px; + --space-4: 16px; + --space-6: 24px; + --radius-control: 8px; +} +``` + +Import it before `index.css`. Replace old `--senlin-*` variables and scattered brand colors with semantic tokens. Rename visible `AI智能体` to `AI 助手`; remove `实时接口` and fixed progress copy. + +- [ ] **Step 4: Verify tokens and copy** + +Run: `node scripts/structure-check.mjs && npm run build && npm run lint` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```powershell +git add apps/web_v1/src/styles apps/web_v1/src/main.tsx apps/web_v1/src/index.css apps/web_v1/src/App.css apps/web_v1/src/pages +git commit -m "refactor(web): unify tokens and product copy" +``` + +### Task 3: 登录页响应式重构 + +**Files:** +- Modify: `apps/web_v1/src/pages/login.tsx` +- Modify: `apps/web_v1/src/App.css` +- Modify: `apps/web_v1/scripts/visual-check.mjs` + +**Interfaces:** +- Consumes: semantic tokens and `/senlinai-icon.svg`. +- Produces: two-column desktop and one-column mobile login layout. + +- [ ] **Step 1: Add desktop and mobile login assertions** + +In `visual-check.mjs`, capture login at 1440×1024 and 390×844 and assert: + +```js +const loginMetrics = await page.evaluate(() => ({ + overflowX: document.documentElement.scrollWidth > document.documentElement.clientWidth, + title: document.title, + columns: getComputedStyle(document.querySelector('.login-card')).gridTemplateColumns, +})) +if (loginMetrics.overflowX) failures.push('login must not overflow horizontally') +if (loginMetrics.title !== '森林AI') failures.push(`unexpected title ${loginMetrics.title}`) +``` + +At the mobile viewport assert `.login-card` width is at most 390 and its computed column count is one. + +- [ ] **Step 2: Verify the current layout fails** + +Run: `$env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs` + +Expected: FAIL on mobile overflow or login column assertions. + +- [ ] **Step 3: Implement the two-column login** + +Keep `.login-brand-panel` and `.login-form-panel`; remove the third marketing panel. Add `@media (max-width: 760px)` that sets `grid-template-columns: 1fr`, reduces outer padding to 16px, and keeps every input/button at full available width. + +- [ ] **Step 4: Verify at both viewports** + +Run: `$env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs` + +Expected: login checks PASS with no clipping. + +- [ ] **Step 5: Commit** + +```powershell +git add apps/web_v1/src/pages/login.tsx apps/web_v1/src/App.css apps/web_v1/scripts/visual-check.mjs +git commit -m "fix(web): make login responsive" +``` + +### Task 4: 移动工作台导航与有效 DOM + +**Files:** +- Modify: `apps/web_v1/src/pages/workspace-home.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-topbar.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-rail.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-sidebar.tsx` +- Modify: `apps/web_v1/src/pages/projects/project-statusbar.tsx` +- Modify: `apps/web_v1/src/App.css` +- Modify: `apps/web_v1/scripts/visual-check.mjs` + +**Interfaces:** +- Produces: `navOpen: 'projects' | 'channels' | null` state controlled by `ProjectPage`. +- `ProjectTopbar` emits `onOpenProjects` and `onOpenChannels`. + +- [ ] **Step 1: Add failing DOM and mobile navigation checks** + +Assert that the status user container has no descendant button, the mobile viewport has no horizontal overflow, and buttons labelled `打开项目导航` and `打开频道导航` can reveal their respective asides. + +- [ ] **Step 2: Verify failures** + +Run: `$env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs` + +Expected: FAIL for nested button console error and missing mobile navigation. + +- [ ] **Step 3: Implement controlled drawers** + +Add `const [navOpen, setNavOpen] = useState<'projects' | 'channels' | null>(null)` to `ProjectPage`. Pass an `open` class and close callback to rail/sidebar. Add topbar buttons with exact accessible names. CSS must position asides as fixed overlays below 768px, add a backdrop button, and remove `.workbench-shell { min-width: 1180px; }`. + +Replace the status user outer ` + + +``` + +- [ ] **Step 4: Run full frontend verification** + +Run: `node scripts/structure-check.mjs; $env:VISUAL_CHECK_PORT='4174'; node scripts/visual-check.mjs; npm run build; npm run lint` + +Expected: all PASS and browser console errors are empty. + +- [ ] **Step 5: Commit** + +```powershell +git add apps/web_v1/src/pages/workspace-home.tsx apps/web_v1/src/pages/projects apps/web_v1/src/App.css apps/web_v1/scripts/visual-check.mjs +git commit -m "feat(web): add responsive workbench navigation" +```