From 2e1aa251d22b5c21e80dcb7b7565f4c4dee5efec Mon Sep 17 00:00:00 2001 From: enzo Date: Wed, 22 Jul 2026 16:20:01 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20initial=20commit=20=E2=80=94=20project?= =?UTF-8?q?=20scaffold=20(FastAPI=20+=20React=20+=20PostgreSQL)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- .gitignore | 9 + README.md | 12 + backend/.env.example | 8 + backend/pyproject.toml | 22 + .../plans/2026-07-22-hive-manage-v3-p0.md | 1040 +++++++++++++++++ docs/superpowers/plans/task-0.1-spec.md | 70 ++ 6 files changed, 1161 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 backend/.env.example create mode 100644 backend/pyproject.toml create mode 100644 docs/superpowers/plans/2026-07-22-hive-manage-v3-p0.md create mode 100644 docs/superpowers/plans/task-0.1-spec.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2de6e47 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +__pycache__/ +*.pyc +.env +node_modules/ +dist/ +.pytest_cache/ +*.egg-info/ +venv/ +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..07e59a8 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Hive Manage v3 + +蜂群运维中台 — 58 个 Hermes Agent Profile 的批量管控面板。 + +## 技术栈 + +- 后端: FastAPI + SQLAlchemy async + PostgreSQL +- 前端: React 19 + TypeScript + Tailwind CSS + Vite + +## 快速开始 + +见 deploy/ 目录下的部署文档。 diff --git a/backend/.env.example b/backend/.env.example new file mode 100644 index 0000000..495bef1 --- /dev/null +++ b/backend/.env.example @@ -0,0 +1,8 @@ +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 diff --git a/backend/pyproject.toml b/backend/pyproject.toml new file mode 100644 index 0000000..0f4680d --- /dev/null +++ b/backend/pyproject.toml @@ -0,0 +1,22 @@ +[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", +] diff --git a/docs/superpowers/plans/2026-07-22-hive-manage-v3-p0.md b/docs/superpowers/plans/2026-07-22-hive-manage-v3-p0.md new file mode 100644 index 0000000..0a0a86b --- /dev/null +++ b/docs/superpowers/plans/2026-07-22-hive-manage-v3-p0.md @@ -0,0 +1,1040 @@ +# 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 · 开发工程* diff --git a/docs/superpowers/plans/task-0.1-spec.md b/docs/superpowers/plans/task-0.1-spec.md new file mode 100644 index 0000000..eae9ab3 --- /dev/null +++ b/docs/superpowers/plans/task-0.1-spec.md @@ -0,0 +1,70 @@ +请在 /home/enzo/projects/hive-manage-v3/ 下创建以下 4 个文件,内容必须完全一致。 + +## 文件 1: .gitignore +``` +__pycache__/ +*.pyc +.env +node_modules/ +dist/ +.pytest_cache/ +*.egg-info/ +venv/ +.DS_Store +``` + +## 文件 2: README.md +``` +# Hive Manage v3 + +蜂群运维中台 — 58 个 Hermes Agent Profile 的批量管控面板。 + +## 技术栈 + +- 后端: FastAPI + SQLAlchemy async + PostgreSQL +- 前端: React 19 + TypeScript + Tailwind CSS + Vite + +## 快速开始 + +见 deploy/ 目录下的部署文档。 +``` + +## 文件 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", +] +``` + +## 文件 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 +``` + +backend 目录如不存在请先创建。创建完成后用 `cat` 验证每个文件内容是否正确。