# Hive Manage v3 — P0 核心闭环实施计划 > **对于 agentic workers:** 使用 superpowers:executing-plans 或直接逐 task 执行。所有代码由 Claude Code CLI (`--output-format stream-json --include-partial-messages --verbose`) 编写,工头负责 QC。Steps 使用 checkbox (`- [ ]`) 语法追踪进度。 **目标:** 从零构建蜂群运维中台 v3 的 P0 核心闭环——7 个模块覆盖 58 个 Hermes Agent Profile 的批量管控、健康监控、密钥管理、Kanban 任务追踪、Cron 定时任务管理、事件档案、用户鉴权。 **架构:** FastAPI async 后端 + React 19 TypeScript 前端,PostgreSQL 持久层,Hermes CLI 作为蜂群数据源(低侵入只读),JWT 鉴权,CSS 变量双模(暗/浅)。 **技术栈:** Python 3.12, FastAPI, SQLAlchemy 2.0 (async), PostgreSQL, Alembic, Pydantic v2, React 19, TypeScript 5, Tailwind CSS 3, Vite 5, Lucide Icons, JWT (python-jose), bcrypt, pytest, Vitest. ## 全局约束 - 不复用 v1 任何代码,全部从零重写 - 所有 API 路径前缀 `/api/v1/` - 所有 API 请求/响应用 Pydantic 模型校验 - 四态覆盖:Loading (Skeleton) / Empty (引导文案) / Error (重试按钮) / Normal - 暗色模式为默认主题,跟随系统并可手动切换(localStorage `hive-theme`) - 移动端响应式:768px 断点,按钮触控 ≥ 44×44px - 鉴权:所有 `/api/v1/` 除 `/api/v1/auth/*` 外需 JWT Bearer Token - 审计:所有写操作(POST/PUT/PATCH/DELETE)自动记录到 `audit_logs` 表 - Hermes CLI 调用只读,不修改蜂巢核心代码 - 密钥值始终脱敏显示(前 3 + 后 4 字符)+ 不写入审计日志原文 - 模型退役 warning 可忽略(底层走 DeepSeek v4 Pro 映射) - Nginx 反代:`/api/` → FastAPI:8000,其余 → Vite dist --- ## 目录结构 ``` /home/enzo/projects/hive-manage-v3/ ├── backend/ │ ├── app/ │ │ ├── main.py # FastAPI 应用工厂 + 中间件注册 │ │ ├── config.py # Settings (pydantic-settings),读 .env │ │ ├── database.py # async engine + session + Base │ │ ├── models/ │ │ │ ├── __init__.py │ │ │ ├── user.py # User ORM │ │ │ └── audit.py # AuditLog ORM │ │ ├── schemas/ │ │ │ ├── __init__.py │ │ │ ├── auth.py # Login/Register/Token 请求响应 │ │ │ ├── user.py # User CRUD │ │ │ ├── gateway.py # Gateway 状态/事件 │ │ │ ├── health.py # 健康分 │ │ │ ├── cron.py # Cron Job │ │ │ ├── kanban.py # Kanban 任务 │ │ │ ├── keys.py # 密钥 │ │ │ ├── dashboard.py # Dashboard 聚合 │ │ │ ├── event.py # 事件档案 │ │ │ └── audit.py # 审计日志 │ │ ├── api/ │ │ │ ├── __init__.py │ │ │ ├── auth.py # /api/v1/auth/* │ │ │ ├── users.py # /api/v1/users/* │ │ │ ├── gateway.py # /api/v1/gateway/* │ │ │ ├── health.py # /api/v1/health/* │ │ │ ├── cron.py # /api/v1/cron/* │ │ │ ├── kanban.py # /api/v1/kanban/* │ │ │ ├── keys.py # /api/v1/keys/* │ │ │ ├── dashboard.py # /api/v1/dashboard/* │ │ │ ├── events.py # /api/v1/events/* │ │ │ └── audit.py # /api/v1/audit/* │ │ ├── services/ │ │ │ ├── __init__.py │ │ │ ├── hermes_cli.py # hermes gateway/cron/kanban CLI 封装 │ │ │ ├── health_scorer.py # 健康分计算引擎 │ │ │ ├── key_manager.py # .env 读写 + 脱敏 │ │ │ └── event_crawler.py # hm.zhiweidata.ai/events 爬取 │ │ └── middleware/ │ │ ├── __init__.py │ │ ├── auth.py # JWT 鉴权依赖 │ │ └── audit.py # 审计日志中间件 │ ├── alembic/ │ │ ├── env.py │ │ └── versions/ │ ├── tests/ │ │ ├── conftest.py # async test fixtures │ │ ├── test_auth.py │ │ ├── test_gateway.py │ │ ├── test_health.py │ │ ├── test_cron.py │ │ ├── test_kanban.py │ │ ├── test_keys.py │ │ ├── test_dashboard.py │ │ └── test_events.py │ ├── requirements.txt │ ├── .env.example │ └── pyproject.toml ├── frontend/ │ ├── src/ │ │ ├── main.tsx # React 入口 │ │ ├── App.tsx # 路由 + 布局 │ │ ├── types/ │ │ │ └── index.ts # 全局 TS 类型 │ │ ├── styles/ │ │ │ └── tokens.css # CSS 变量 (暗/浅双模) │ │ ├── components/ │ │ │ ├── ui/ │ │ │ │ ├── Button.tsx │ │ │ │ ├── Card.tsx │ │ │ │ ├── Table.tsx │ │ │ │ ├── Badge.tsx │ │ │ │ ├── Modal.tsx │ │ │ │ ├── Drawer.tsx │ │ │ │ ├── Toast.tsx │ │ │ │ ├── Skeleton.tsx │ │ │ │ ├── Toggle.tsx │ │ │ │ ├── Timeline.tsx │ │ │ │ └── SearchBox.tsx │ │ │ └── layout/ │ │ │ ├── Sidebar.tsx │ │ │ ├── Header.tsx │ │ │ ├── MobileNav.tsx │ │ │ ├── TabBar.tsx │ │ │ └── AppLayout.tsx │ │ ├── pages/ │ │ │ ├── LoginPage.tsx │ │ │ ├── DashboardPage.tsx │ │ │ ├── GatewayPage.tsx │ │ │ ├── HealthPage.tsx │ │ │ ├── CronPage.tsx │ │ │ ├── KanbanPage.tsx │ │ │ ├── KeysPage.tsx │ │ │ ├── EventArchivePage.tsx │ │ │ ├── UserManagementPage.tsx │ │ │ └── AuditLogPage.tsx │ │ ├── hooks/ │ │ │ ├── usePolling.ts │ │ │ ├── useAuth.ts │ │ │ └── useTheme.ts │ │ └── api/ │ │ ├── client.ts # axios 实例 + JWT 拦截器 │ │ ├── auth.ts │ │ ├── gateway.ts │ │ ├── health.ts │ │ ├── cron.ts │ │ ├── kanban.ts │ │ ├── keys.ts │ │ ├── dashboard.ts │ │ ├── events.ts │ │ ├── users.ts │ │ └── audit.ts │ ├── index.html │ ├── package.json │ ├── tsconfig.json │ ├── vite.config.ts │ ├── tailwind.config.ts │ └── postcss.config.js ├── deploy/ │ └── nginx-hive-manage-v3.conf ├── docs/ │ └── superpowers/ │ └── plans/ ├── .gitignore └── README.md ``` --- ## Phase 0:基础设施 > 所有后续 Phase 的前置依赖。无业务逻辑,纯骨架。 ### Task 0.1:项目目录 + 基础文件 **文件:** - Create: `.gitignore`, `README.md`, `backend/.env.example`, `backend/pyproject.toml` - [ ] **Step 1: 创建 .gitignore** ``` __pycache__/ *.pyc .env node_modules/ dist/ .pytest_cache/ *.egg-info/ venv/ .DS_Store ``` - [ ] **Step 2: 创建 README.md** ```markdown # Hive Manage v3 蜂群运维中台 — 58 个 Hermes Agent Profile 的批量管控面板。 ## 技术栈 - 后端: FastAPI + SQLAlchemy async + PostgreSQL - 前端: React 19 + TypeScript + Tailwind CSS + Vite ## 快速开始 见 deploy/ 目录下的部署文档。 ``` - [ ] **Step 3: 创建 backend/pyproject.toml** ```toml [project] name = "hive-manage-v3" version = "0.1.0" requires-python = ">=3.12" dependencies = [ "fastapi[standard]>=0.115", "sqlalchemy[asyncio]>=2.0", "asyncpg>=0.30", "alembic>=1.14", "pydantic>=2.10", "pydantic-settings>=2.7", "python-jose[cryptography]>=3.3", "passlib[bcrypt]>=1.7", "httpx>=0.28", "uvicorn[standard]>=0.34", ] [project.optional-dependencies] dev = [ "pytest>=8.3", "pytest-asyncio>=0.25", "httpx>=0.28", ] ``` - [ ] **Step 4: 创建 backend/.env.example** ``` DATABASE_URL=postgresql+asyncpg://hive_admin:changeme@localhost:5432/hive_manage_v3 JWT_SECRET=change-me-to-random-string JWT_ALGORITHM=HS256 JWT_EXPIRE_MINUTES=1440 HERMES_CLI_PATH=/home/enzo/.local/bin/hermes HERMES_PROFILES_ROOT=/home/enzo/.hermes/profiles ADMIN_EMAIL=admin@zhiwei.local ADMIN_PASSWORD=admin123 ``` - [ ] **Step 5: 提交** ```bash git add -A && git commit -m "chore: project scaffold with .gitignore, README, pyproject.toml" ``` --- ### Task 0.2:Git 初始化 + Gitea 建库 + Mirror > 此 Task 委托 ops-engineer(工蜂)执行。以下为指令规格,由 ops 自行完成。 **要求:** - 在 `/home/enzo/projects/hive-manage-v3/` 执行 `git init` - 在主 Gitea (`192.168.50.97:3002`, 用户 `enzo`) 创建仓库 `hive-manage-v3` - 设置 remote origin 指向主 Gitea - 首次 commit + push - 备份 Gitea (`192.168.50.92:3030`) 的 mirror 由现有 cron 自动发现(每小时),无需手动操作 - 验证:`git remote -v` 指向正确地址,Gitea Web UI 可见仓库 **ops 执行命令参考:** ```bash cd /home/enzo/projects/hive-manage-v3 git init git remote add origin http://enzo:zhiwei2026!@192.168.50.97:3002/enzo/hive-manage-v3.git git add -A && git commit -m "chore: initial commit" git push -u origin main ``` --- ### Task 0.3:FastAPI 骨架 **文件:** - Create: `backend/app/__init__.py` - Create: `backend/app/main.py` - Create: `backend/app/config.py` - Create: `backend/app/database.py` - [ ] **Step 1: 创建 config.py** ```python """应用配置 — 从环境变量 / .env 读取。""" from pydantic_settings import BaseSettings class Settings(BaseSettings): database_url: str = "postgresql+asyncpg://hive_admin:changeme@localhost:5432/hive_manage_v3" jwt_secret: str = "change-me" jwt_algorithm: str = "HS256" jwt_expire_minutes: int = 1440 hermes_cli_path: str = "/home/enzo/.local/bin/hermes" hermes_profiles_root: str = "/home/enzo/.hermes/profiles" admin_email: str = "admin@zhiwei.local" admin_password: str = "admin123" model_config = {"env_file": ".env"} settings = Settings() ``` - [ ] **Step 2: 创建 database.py** ```python """异步 SQLAlchemy 引擎 + session 工厂。""" from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession from sqlalchemy.orm import DeclarativeBase from app.config import settings engine = create_async_engine(settings.database_url, echo=False) async_session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) class Base(DeclarativeBase): pass async def get_db() -> AsyncSession: async with async_session() as session: yield session ``` - [ ] **Step 3: 创建 main.py** ```python """FastAPI 应用入口。""" from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.database import engine, Base @asynccontextmanager async def lifespan(app: FastAPI): # 启动时创建表(开发阶段;生产用 Alembic) async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) yield await engine.dispose() app = FastAPI( title="Hive Manage v3", version="0.1.0", lifespan=lifespan, ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/api/v1/health") async def health_check(): return {"status": "ok"} ``` - [ ] **Step 4: 提交** ```bash git add backend/app/ && git commit -m "feat: FastAPI skeleton with config, database, health endpoint" ``` --- ### Task 0.4:Alembic 初始化 + User 基础 Schema **文件:** - Create: `backend/alembic/` (通过 `alembic init`) - Modify: `backend/alembic/env.py` - Create: `backend/app/models/__init__.py` - Create: `backend/app/models/user.py` - [ ] **Step 1: 初始化 Alembic + 创建 User 模型** ```bash cd backend && alembic init alembic ``` - [ ] **Step 2: 配置 alembic/env.py** 将 `target_metadata` 指向 `Base.metadata`,配置异步引擎。关键改动: ```python from app.database import Base, engine from app.models import * # noqa: F401,F403 — 确保所有模型被导入 target_metadata = Base.metadata def run_migrations_offline(): ... context.configure(url=settings.database_url, target_metadata=target_metadata) def do_run_migrations(connection): context.configure(connection=connection, target_metadata=target_metadata) async def run_async_migrations(): async with engine.begin() as conn: await conn.run_sync(do_run_migrations) def run_migrations_online(): import asyncio asyncio.run(run_async_migrations()) ``` - [ ] **Step 3: 创建 User 模型 backend/app/models/user.py** ```python """用户 ORM 模型。""" import uuid from datetime import datetime from sqlalchemy import String, Boolean, DateTime, Enum as SAEnum from sqlalchemy.orm import Mapped, mapped_column import enum from app.database import Base class UserRole(str, enum.Enum): OWNER = "owner" OPERATOR = "operator" VIEWER = "viewer" class User(Base): __tablename__ = "users" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True) email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False) hashed_password: Mapped[str] = mapped_column(String(255), nullable=False) role: Mapped[UserRole] = mapped_column(SAEnum(UserRole), default=UserRole.VIEWER, nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True) is_approved: Mapped[bool] = mapped_column(Boolean, default=False) login_attempts: Mapped[int] = mapped_column(default=0) locked_until: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) ``` - [ ] **Step 4: 生成初始迁移** ```bash cd backend && alembic revision --autogenerate -m "create users table" alembic upgrade head ``` - [ ] **Step 5: 创建 backend/app/models/audit.py** ```python """审计日志 ORM 模型。""" import uuid from datetime import datetime from sqlalchemy import String, DateTime, Text from sqlalchemy.orm import Mapped, mapped_column from app.database import Base class AuditLog(Base): __tablename__ = "audit_logs" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid.uuid4())) user_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) username: Mapped[str] = mapped_column(String(50), nullable=False) action: Mapped[str] = mapped_column(String(100), nullable=False, index=True) target: Mapped[str] = mapped_column(String(255), nullable=False) detail: Mapped[str | None] = mapped_column(Text, nullable=True) ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) ``` - [ ] **Step 6: 生成 AuditLog 迁移并提交** ```bash cd backend && alembic revision --autogenerate -m "create audit_logs table" alembic upgrade head git add backend/alembic/ backend/app/models/ && git commit -m "feat: Alembic setup, User and AuditLog models" ``` --- ### Task 0.5:前端 Vite + React + Tailwind 脚手架 **文件:** - Create: `frontend/package.json`, `frontend/tsconfig.json`, `frontend/vite.config.ts`, `frontend/tailwind.config.ts`, `frontend/postcss.config.js`, `frontend/index.html`, `frontend/src/main.tsx`, `frontend/src/App.tsx` - [ ] **Step 1: 创建 package.json** ```json { "name": "hive-manage-v3-frontend", "private": true, "version": "0.1.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc && vite build", "preview": "vite preview" }, "dependencies": { "react": "^19.0", "react-dom": "^19.0", "react-router-dom": "^7.0", "axios": "^1.7", "lucide-react": "^0.460" }, "devDependencies": { "@types/react": "^19.0", "@types/react-dom": "^19.0", "@vitejs/plugin-react": "^4.3", "autoprefixer": "^10.4", "postcss": "^8.4", "tailwindcss": "^3.4", "typescript": "^5.6", "vite": "^6.0" } } ``` - [ ] **Step 2: 创建 vite.config.ts** ```typescript import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], server: { port: 5173, proxy: { '/api': 'http://127.0.0.1:8000', }, }, }) ``` - [ ] **Step 3: 创建 tailwind.config.ts** ```typescript import type { Config } from 'tailwindcss' export default { content: ['./index.html', './src/**/*.{ts,tsx}'], darkMode: 'class', theme: { extend: { colors: { honey: { DEFAULT: '#f0b90b', dim: '#b8970e' }, }, }, }, plugins: [], } satisfies Config ``` - [ ] **Step 4: 创建 index.html + main.tsx + App.tsx(最小骨架)** ```html Hive Manage v3
``` ```tsx // main.tsx import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import './styles/tokens.css' ReactDOM.createRoot(document.getElementById('root')!).render( ) ``` ```tsx // App.tsx export default function App() { return
Hive Manage v3
} ``` - [ ] **Step 5: 安装依赖 + 验证** ```bash cd frontend && npm install && npm run dev # 访问 http://localhost:5173 应显示 "Hive Manage v3" ``` - [ ] **Step 6: 提交** ```bash git add frontend/ && git commit -m "feat: Vite + React 19 + Tailwind + TypeScript scaffold" ``` --- ### Task 0.6:CSS 变量双模体系 **文件:** - Create: `frontend/src/styles/tokens.css` **根据 UI 设计规范 §2.1 精确实现:** ```css /* ===== 暗色模式(默认) ===== */ :root { --bg-root: #0f1117; --bg-nav: #161822; --bg-card: #1a1d2e; --bg-hover: #1e2134; --bg-elevated: #222639; --border: #2a2d3e; --border-light: rgba(42,45,62,.5); --honey: #f0b90b; --honey-dim: #b8970e; --honey-glow: rgba(240,185,11,.12); --green: #00c853; --red: #ff3d3d; --yellow: #ffab00; --blue: #448aff; --orange: #ff6d00; --text: #e0e0e0; --text-dim: #8b8d9a; --text-muted: #5a5d6a; --bg-success: #0d2818; --bg-error: #2d0f0f; --bg-warn: #2d2000; --bg-info: #0d1b2d; --radius: 8px; --radius-sm: 4px; --radius-lg: 12px; --radius-full: 9999px; --shadow: 0 2px 8px rgba(0,0,0,.35); --shadow-lg: 0 12px 32px rgba(0,0,0,.55); --shadow-modal: 0 24px 64px rgba(0,0,0,.65); --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; --font-mono: "SF Mono", "Fira Code", Consolas, monospace; --header-h: 48px; --sidebar-w: 220px; } /* ===== 浅色模式 ===== */ [data-theme="light"] { --bg-root: #f5f6fa; --bg-nav: #ffffff; --bg-card: #ffffff; --bg-hover: #edf0f5; --bg-elevated: #ffffff; --border: #e2e5ee; --border-light: rgba(0,0,0,.06); --honey: #e5a800; --honey-dim: #c48f00; --honey-glow: rgba(229,168,0,.08); --green: #008c3a; --red: #d32f2f; --yellow: #e65100; --blue: #1565c0; --orange: #d84315; --text: #1a1d2e; --text-dim: #555a6e; --text-muted: #8b8f9e; --bg-success: #e8f5e9; --bg-error: #fdecea; --bg-warn: #fff3e0; --bg-info: #e3f2fd; --shadow: 0 1px 4px rgba(0,0,0,.08); --shadow-lg: 0 8px 24px rgba(0,0,0,.10); --shadow-modal: 0 16px 48px rgba(0,0,0,.14); } /* ===== 全局基础 ===== */ * { box-sizing: border-box; } body { margin: 0; font-family: var(--font); font-size: 13px; background: var(--bg-root); color: var(--text); } /* 主题切换过渡 */ * { transition: background-color .15s, border-color .15s, color .15s; } ``` - [ ] **Step: 提交** ```bash git add frontend/src/styles/tokens.css && git commit -m "feat: CSS variable dual-theme system (dark default + light)" ``` --- ### Task 0.7:共享 UI 组件库 **文件:** 全部在 `frontend/src/components/ui/` 下创建。 > 每个组件遵循 UI 设计规范 §4 规格。以下列出关键组件及核心实现要点,完整代码由 Claude Code 根据原型 HTML 和设计规范实现。 | 组件 | 文件 | 规范参考 | 关键要点 | |------|------|----------|----------| | Button | `Button.tsx` | §4.4 | 4 变体 (primary/danger/outline/ghost) + 2 尺寸 + loading/disabled 态 | | Card | `Card.tsx` | §4.1 | header(label+action) + value(彩色) + change(↑↓) | | Table | `Table.tsx` | §4.3 | sticky 表头 + hover 高亮 + row-danger 样式 + 移动端卡片化 | | Badge | `Badge.tsx` | §4.5 | 6 变体 (success/danger/warning/info/honey/outline) + 胶囊形 | | Modal | `Modal.tsx` | §4.8 | 居中弹窗 + 遮罩 + Esc 关闭 + 确认短语输入 | | Drawer | `Drawer.tsx` | §4.9 | 右侧滑入 480px + 遮罩 + Esc 关闭 | | Toast | `Toast.tsx` | §4.10 | 4 类型 (success/error/warn/info) + 顶部居中 + 自动消失 | | Skeleton | `Skeleton.tsx` | §4.14 | shimmer 动画 + 形状匹配 (card/table/text) | | Toggle | `Toggle.tsx` | §4.7 | 44×24px + 滑块动画 + 标签 | | Timeline | `Timeline.tsx` | §4.13 | 横向时间线 + 点 hover tooltip | | SearchBox | `SearchBox.tsx` | §4.11 | 输入框 + 下拉面板 + 分组结果 + debounce 300ms | **测试要求:** 每个组件提供基础渲染测试(Vitest + React Testing Library),验证所有变体和状态。 - [ ] **Step: 逐个组件实现(Claude Code 编写 + 工头 QC)** ```bash git add frontend/src/components/ui/ && git commit -m "feat: shared UI component library (11 components)" ``` --- ### Task 0.8:布局组件 **文件:** `frontend/src/components/layout/` | 组件 | 文件 | 规范参考 | 关键要点 | |------|------|----------|----------| | Sidebar | `Sidebar.tsx` | §3.5 | 220px 固定 + 5 Section + NavItem active/hover + Badge | | Header | `Header.tsx` | §3.4 | 48px + 面包屑 + 搜索框 + 主题切换 + 更新指示 | | MobileNav | `MobileNav.tsx` | §3.2 | 汉堡菜单 → 左侧抽屉 280px + 遮罩 | | TabBar | `TabBar.tsx` | §3.6 | 底部固定 56px + 4 核心入口 (总览/Gateway/Kanban/Cron) | | AppLayout | `AppLayout.tsx` | §3.1 | CSS Grid: Sidebar + Header + Main,响应式 768px 断点切换移动布局 | - [ ] **Step 1: 实现 AppLayout.tsx(核心布局)** ```tsx // 桌面: CSS Grid (sidebar 220px + header 48px + main) // 平板 (768-1279px): sidebar 180px // 移动 (<768px): Header + TabBar + 汉堡抽屉 // 使用 CSS 媒体查询 + data-viewport 属性切换 ``` - [ ] **Step 2: 实现路由占位** ```tsx // App.tsx 中使用 react-router-dom // / → Dashboard // /login → LoginPage // /gateway → GatewayPage // ... // 未登录重定向 /login,已登录根据 JWT 存在与否判断 ``` - [ ] **Step 3: 提交** ```bash git add frontend/src/components/layout/ frontend/src/App.tsx && git commit -m "feat: layout components (Sidebar, Header, MobileNav, TabBar, AppLayout)" ``` --- ## Phase 1:用户中心 + 鉴权(P0-6) ### Task 1.1:JWT 鉴权服务 + 中间件 **文件:** - Create: `backend/app/services/auth_service.py` - Create: `backend/app/middleware/auth.py` - Create: `backend/app/schemas/auth.py` - [ ] **Step 1: 创建 auth schema** ```python # backend/app/schemas/auth.py from pydantic import BaseModel, EmailStr class LoginRequest(BaseModel): username: str password: str class RegisterRequest(BaseModel): username: str email: EmailStr password: str class TokenResponse(BaseModel): access_token: str token_type: str = "bearer" expires_in: int user: "UserResponse" # 引用 user schema class ChangePasswordRequest(BaseModel): old_password: str new_password: str ``` - [ ] **Step 2: 创建 auth_service.py** 核心功能: - `hash_password(password: str) -> str` — bcrypt - `verify_password(plain: str, hashed: str) -> bool` - `create_access_token(user_id: str, role: str) -> str` — JWT 编码 - `decode_access_token(token: str) -> dict` — JWT 解码 + 过期检查 - `get_current_user(token: str, db: AsyncSession) -> User` — FastAPI Depends - [ ] **Step 3: 创建 auth 中间件** ```python # backend/app/middleware/auth.py from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.services.auth_service import decode_access_token, get_user_by_id security = HTTPBearer() async def require_auth( credentials: HTTPAuthorizationCredentials = Depends(security), db: AsyncSession = Depends(get_db), ): """解析 JWT → 查询 User → 返回 User ORM 对象。失败抛 401。""" payload = decode_access_token(credentials.credentials) user = await get_user_by_id(db, payload["sub"]) if not user or not user.is_active: raise HTTPException(status_code=401, detail="Invalid or inactive user") return user def require_role(*roles: str): """角色守卫工厂。用法: Depends(require_role("owner", "operator"))""" async def role_check(user = Depends(require_auth)): if user.role.value not in roles: raise HTTPException(status_code=403, detail="Insufficient permissions") return user return role_check ``` - [ ] **Step 4: 编写测试** ```python # backend/tests/test_auth.py # 测试用例: # - 注册成功 → 201 # - 重复注册 → 409 # - 登录成功 → 200 + JWT # - 错误密码 → 401 # - 登录锁定(5 次失败) → 423 # - Token 过期 → 401 # - 无 Token 访问受保护路由 → 401 # - Viewer 角色访问写操作 → 403 ``` - [ ] **Step 5: 提交** ```bash git add backend/app/services/auth_service.py backend/app/middleware/ backend/app/schemas/auth.py backend/tests/test_auth.py && git commit -m "feat: JWT auth service, middleware, and role guards" ``` --- ### Task 1.2:Auth API 路由 **文件:** - Create: `backend/app/api/auth.py` - [ ] **Step 1: 实现路由** ```python # backend/app/api/auth.py from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.schemas.auth import LoginRequest, RegisterRequest, TokenResponse from app.services.auth_service import * from app.models.user import User, UserRole router = APIRouter(prefix="/api/v1/auth", tags=["auth"]) @router.post("/register", status_code=201) async def register(body: RegisterRequest, db: AsyncSession = Depends(get_db)): """新用户注册。默认 Viewer 角色 + 待审批。首个用户自动设为 Owner + 已审批。""" ... @router.post("/login", response_model=TokenResponse) async def login(body: LoginRequest, db: AsyncSession = Depends(get_db)): """用户名 + 密码登录。失败 5 次锁定 15 分钟。成功返回 JWT。""" ... @router.post("/refresh") async def refresh_token(user = Depends(require_auth)): """刷新 Token(重置过期时间)。""" ... @router.post("/change-password") async def change_password(body: ChangePasswordRequest, user = Depends(require_auth), db = Depends(get_db)): """修改当前用户密码。""" ... ``` - [ ] **Step 2: 在 main.py 注册路由** ```python from app.api import auth app.include_router(auth.router) ``` - [ ] **Step 3: 编写集成测试并提交** --- ### Task 1.3:用户管理 API **文件:** - Create: `backend/app/api/users.py` - Create: `backend/app/schemas/user.py` 路由:`GET /api/v1/users`(列表) / `GET /api/v1/users/{id}`(详情) / `PATCH /api/v1/users/{id}`(改角色) / `POST /api/v1/users/{id}/approve`(审批) / `DELETE /api/v1/users/{id}`(停用)。 - [ ] **Step 1: 实现 + 测试 + 提交** --- ### Task 1.4:审计日志中间件 + API **文件:** - Modify: `backend/app/middleware/audit.py`(自动记录写操作) - Create: `backend/app/api/audit.py` 核心逻辑:中间件监听所有 POST/PUT/PATCH/DELETE 请求,提取 `user_id`、`action`、`target`、`ip_address`,写入 `audit_logs`。审计日志不可删除(API 只提供 GET 查询)。 - [ ] **Step: 实现 + 测试 + 提交** --- ### Task 1.5-1.9:前端鉴权页面 **文件:** - `frontend/src/pages/LoginPage.tsx` - `frontend/src/pages/UserManagementPage.tsx` - `frontend/src/pages/AuditLogPage.tsx` - `frontend/src/hooks/useAuth.ts` - `frontend/src/api/auth.ts`, `users.ts`, `audit.ts` - `frontend/src/api/client.ts`(axios 实例 + JWT 拦截器 + 401 自动跳转登录) - [ ] **Step: 逐页面实现(Claude Code 编写 + 工头 QC)** ```bash git add frontend/src/pages/LoginPage.tsx frontend/src/pages/UserManagementPage.tsx frontend/src/pages/AuditLogPage.tsx frontend/src/hooks/useAuth.ts frontend/src/api/ && git commit -m "feat: login, user management, audit log pages with JWT auth flow" ``` --- ## Phase 2-8:业务模块 > 每个模块遵循相同模式:**Hermes CLI 封装服务 → Pydantic Schema → API 路由 → 前端页面**。以下为模块规格摘要,完整实现由 Claude Code 按此模式执行。 ### 通用实现模式(以 Gateway 为例) ``` 1. backend/app/services/hermes_cli.py — 添加 gateway_status(), gateway_start(), gateway_stop() 2. backend/app/schemas/gateway.py — GatewayStatus, GatewayEvent, ToggleRequest 3. backend/app/api/gateway.py — router + require_auth + 角色守卫 4. backend/tests/test_gateway.py — pytest + httpx AsyncClient 5. frontend/src/api/gateway.ts — axios 调用封装 6. frontend/src/pages/GatewayPage.tsx — 完整页面(四态 + 轮询 + 操作) ``` ### Phase 2:Dashboard 增强(P0-3) | Task | 后端 API | 前端页面 | 估时 | |------|----------|----------|:--:| | 2.1 | `GET /api/v1/dashboard/summary` — 在线/离线/任务/Cron 计数 | DashboardPage 统计卡片 | 2h | | 2.2 | `GET /api/v1/dashboard/health-distribution` — A/B/C/D 四级计数 | 健康分布柱状图 | 1.5h | | 2.3 | `GET /api/v1/dashboard/gateway-trend` — 24h 异常事件按小时 | Gateway 异常趋势折线图 | 1.5h | | 2.4 | `GET /api/v1/dashboard/kanban-summary` — 活跃看板概览 | Kanban 概览卡片 | 1h | | 2.5 | `GET /api/v1/dashboard/cron-recent` — 最近 Cron 执行 | Cron 最近执行卡片 | 1h | | 2.6 | `GET /api/v1/search?q=` — 全局搜索 | SearchBox 组件集成 | 1.5h | ### Phase 3:Gateway 健康监控(P0-1) | Task | 后端 API | 前端页面 | 估时 | |------|----------|----------|:--:| | 3.1 | `GET /api/v1/gateway/status` — 全部 Profile 状态列表 | GatewayPage 状态表(10s 轮询) | 3h | | 3.2 | `GET /api/v1/gateway/events` — 24h 异常事件时间线 | 异常时间线组件 | 2h | | 3.3 | `POST /api/v1/gateway/{profile}/start\|stop\|restart` | 启停按钮 + 二次确认弹窗 | 2.5h | | 3.4 | 筛选 + 蜂型分类 | 前端筛选器(即时生效) | 1.5h | ### Phase 4:Profile 健康分(P0-2) | Task | 后端 API | 前端页面 | 估时 | |------|----------|----------|:--:| | 4.1 | `GET /api/v1/health/scores` — 排行列表 | HealthPage 列表 + 展开详情 | 3h | | 4.2 | `GET /api/v1/health/scores/{profile}` — 单 Profile 详情 | 四维度扣分明细面板 | 2h | | 4.3 | `POST /api/v1/health/compare` — 批量对比 | 批量对比视图 | 2h | | 4.4 | `POST /api/v1/health/calculate` — 手动触发计算 | 凌晨定时 + 手动触发按钮 | 2h | ### Phase 5:Cron 管理(P0-4b) | Task | 后端 API | 前端页面 | 估时 | |------|----------|----------|:--:| | 5.1 | `GET /api/v1/cron/jobs` — 跨 Profile Cron 列表(含系统 Cron) | CronPage 列表 + 筛选 | 3h | | 5.2 | `GET /api/v1/cron/jobs/{id}/logs` — 最近 8 条日志 | 日志面板(遮罩 + 居中弹窗) | 2h | | 5.3 | `POST /api/v1/cron/jobs/{id}/run\|pause\|resume` | 操作按钮 + Toast | 2h | | 5.4 | 失败告警联动 | Dashboard Badge + 导航栏红色标记 | 1.5h | ### Phase 6:密钥批量管理(P0-5) | Task | 后端 API | 前端页面 | 估时 | |------|----------|----------|:--:| | 6.1 | `GET /api/v1/keys` — 密钥字段列表 | KeysPage 列表 | 2h | | 6.2 | `POST /api/v1/keys/batch-overwrite` — 批量覆盖 | 批量覆盖弹窗(确认短语) | 2h | | 6.3 | `POST /api/v1/keys/batch-scan` — 批量检查 | 缺失扫描结果 + CSV 导出 | 1.5h | | 6.4 | `GET /api/v1/keys/diff` — 差异视图 | 字段对比表 | 1.5h | ### Phase 7:Kanban 增强(P0-4) | Task | 后端 API | 前端页面 | 估时 | |------|----------|----------|:--:| | 7.1 | `GET /api/v1/kanban/tasks` — 跨 Profile 五列聚合 | KanbanPage 五列看板 | 4h | | 7.2 | `GET /api/v1/kanban/tasks/{id}` — 任务详情 | 详情抽屉 | 2h | | 7.3 | `PATCH /api/v1/kanban/tasks/{id}/move` — 拖拽移动 | 拖拽 + 异常标记 | 3h | | 7.4 | 异常检测(阻塞超时/长期无主/失败重试) | 卡片标红/警告 | 2h | | 7.5 | Worker 筛选 + 看板筛选 + 异常筛选 | 筛选器 | 2h | ### Phase 8:事件档案管理(P0-7) | Task | 后端 API | 前端页面 | 估时 | |------|----------|----------|:--:| | 8.1 | `GET /api/v1/events` — 事件卡片列表(三维筛选) | EventArchivePage 卡片网格 | 2h | | 8.2 | 数据爬取 → PG(`hm.zhiweidata.ai/events`) | — | 2h | | 8.3 | 超期标记 + Toast 详情 | 超期红色标记 + 点击 Toast | 1.5h | --- ## Phase 9:集成测试 + 上线 | Task | 内容 | 估时 | |------|------|:--:| | 9.1 | 全量 API 集成测试(httpx + pytest-asyncio) | 3h | | 9.2 | 前端冒烟测试(Vitest + Testing Library) | 2h | | 9.3 | Nginx 部署配置 + 静态文件服务 | 1h | | 9.4 | 部署文档 + API 文档(FastAPI 自动生成) | 0.5h | --- ## 执行说明 - **所有代码由 Claude Code 编写**,命令格式: ```bash cd /home/enzo/projects/hive-manage-v3 && \ ANTHROPIC_API_KEY="sk-4eem6h6DfcPIT7EbY3tLhtd7oepyw9GaqgbSUHmkv3shmNym" \ ANTHROPIC_BASE_URL="http://127.0.0.1:3000" \ ANTHROPIC_MODEL="claude-3-opus-20240229" \ claude --model claude-3-opus-20240229 \ --dangerously-skip-permissions \ --output-format stream-json --include-partial-messages --verbose \ -p "<完整任务描述 + 上下文 + 验收标准>" ``` - **每个 Task 完成后**:工头审查产出(代码质量 + 测试覆盖 + 是否符合设计规范),通过则提交,不通过则反馈 Claude Code 修改。 - **提交粒度**:一个 Task 一个 commit,commit message 格式 `feat:` / `fix:` / `test:` / `chore:` + 简短描述。 --- *计划版本: v1.0 · 2026-07-22 · 开发工程*