35 KiB
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
# Hive Manage v3
蜂群运维中台 — 58 个 Hermes Agent Profile 的批量管控面板。
## 技术栈
- 后端: FastAPI + SQLAlchemy async + PostgreSQL
- 前端: React 19 + TypeScript + Tailwind CSS + Vite
## 快速开始
见 deploy/ 目录下的部署文档。
- Step 3: 创建 backend/pyproject.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: 提交
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 执行命令参考:
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
"""应用配置 — 从环境变量 / .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
"""异步 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
"""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: 提交
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 模型
cd backend && alembic init alembic
- Step 2: 配置 alembic/env.py
将 target_metadata 指向 Base.metadata,配置异步引擎。关键改动:
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
"""用户 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: 生成初始迁移
cd backend && alembic revision --autogenerate -m "create users table"
alembic upgrade head
- Step 5: 创建 backend/app/models/audit.py
"""审计日志 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 迁移并提交
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
{
"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
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
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(最小骨架)
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Hive Manage v3</title></head>
<body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body>
</html>
// 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(
<React.StrictMode><App /></React.StrictMode>
)
// App.tsx
export default function App() {
return <div className="min-h-screen bg-[var(--bg-root)] text-[var(--text)]">Hive Manage v3</div>
}
- Step 5: 安装依赖 + 验证
cd frontend && npm install && npm run dev
# 访问 http://localhost:5173 应显示 "Hive Manage v3"
- Step 6: 提交
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 精确实现:
/* ===== 暗色模式(默认) ===== */
: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: 提交
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)
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(核心布局)
// 桌面: CSS Grid (sidebar 220px + header 48px + main)
// 平板 (768-1279px): sidebar 180px
// 移动 (<768px): Header + TabBar + 汉堡抽屉
// 使用 CSS 媒体查询 + data-viewport 属性切换
- Step 2: 实现路由占位
// App.tsx 中使用 react-router-dom
// / → Dashboard
// /login → LoginPage
// /gateway → GatewayPage
// ...
// 未登录重定向 /login,已登录根据 JWT 存在与否判断
- Step 3: 提交
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
# 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 中间件
# 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: 编写测试
# backend/tests/test_auth.py
# 测试用例:
# - 注册成功 → 201
# - 重复注册 → 409
# - 登录成功 → 200 + JWT
# - 错误密码 → 401
# - 登录锁定(5 次失败) → 423
# - Token 过期 → 401
# - 无 Token 访问受保护路由 → 401
# - Viewer 角色访问写操作 → 403
- Step 5: 提交
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: 实现路由
# 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 注册路由
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)
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 编写,命令格式:
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 · 开发工程