Skip to content

Latest commit

 

History

History
520 lines (411 loc) · 14.8 KB

File metadata and controls

520 lines (411 loc) · 14.8 KB

SchedSim AGENTS.md

This file provides guidelines for AI agents working on the SchedSim project (Kubernetes Scheduler Simulation Platform).


1. Build, Lint, and Test Commands

Full Project Commands (from project root)

# Setup & Environment
make setup              # Install all dev dependencies (idempotent)
make check-env          # Verify dev environment; auto-fix if possible

# Build
make build              # Full build: check-env + frontend + backend (CGO_ENABLED=1)
make build-backend      # Build Go binary to bin/schedsim
make build-frontend     # Build React assets to web/dist

# Test
make test               # Run Go unit tests with coverage
make test-frontend      # Run frontend tests with Vitest
make verify-scenarios   # Verify built-in scenario templates against running backend

# Lint
make lint               # Run golangci-lint + eslint

# Development
make start / make dev   # Full dev env: check-env + ensure-frontend + sqlite-web + backend + frontend
make dev-backend        # Backend with hot reload (air if installed, fallback go run)
make dev-frontend       # Frontend Vite dev server (port 5173)

# Database
make sqlite-web         # Launch sqlite_web in foreground (port 8081)
make sqlite-web-bg      # Launch sqlite_web in background (auto-started by dev)

# Docker & Helm
make docker             # Build Docker image
make docker-push        # Push Docker image
make helm-lint          # Validate Helm chart
make helm-package       # Package Helm chart to dist/

# Production
make prod               # Build + run binary

# Misc
make clean              # Remove bin/, web/dist/, data/
make migrate            # Run DB migration

Frontend Commands (cd web)

npm run dev            # Start Vite dev server (port 5173)
npm run build          # tsc -b && vite build
npm run lint           # ESLint check
npm test               # vitest run (single pass)
npm run test:watch     # vitest (watch mode)
npm run preview        # Preview production build

Running a Single Test

Go Backend:

# Run specific test function
go test ./internal/api/... -run TestClusterCreate -v

# Run tests in a specific file
go test ./internal/service/scenario_test.go -v

# Run with coverage
go test ./internal/... -cover

Frontend (Vitest):

# Run specific test file
cd web && npx vitest run scenarioEditor.test.tsx

# Run tests matching a pattern
cd web && npx vitest run -t "ScenarioEditor"

# Run with coverage
cd web && npx vitest run --coverage

2. Code Style Guidelines

2.1 Go Backend

Naming Conventions

Element Convention Example
Files lowercase_underscores cluster_manager.go
Packages lowercase single word package cluster
Interfaces PascalCase, describes capability ClusterProvisioner
Structs PascalCase KindProvisioner
Constants PascalCase or UPPER_SNAKE MaxRetries or MAX_RETRIES
Test files *_test.go cluster_test.go
Test functions TestXxx TestClusterCreate

Error Handling

  • Wrap errors with context: fmt.Errorf("creating cluster: %w", err)
  • Never suppress errors with empty catch blocks
  • API layer returns structured errors:
type APIError struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
    Detail  string `json:"detail,omitempty"`
}

Logging

  • Use zap structured logger
  • Log levels: Debug < Info < Warn < Error
  • Include context fields: requestID, userID, clusterID
  • NEVER log secrets (passwords, tokens, kubeconfigs)

Project Structure

cmd/schedsim/       # Main entry point only
internal/           # Private application code
  ├── analysis/     # Analysis & reporting module
  ├── api/          # HTTP layer (handler, middleware, router)
  ├── auth/         # Authentication (JWT, local auth)
  ├── cluster/      # Cluster lifecycle management
  │   ├── deployer/ # Component deployers (scheduler, metrics, etc.)
  │   └── mirror/   # Cluster snapshot & transform
  ├── config/       # Configuration loading (Viper)
  ├── engine/       # Scenario execution engine (DAG)
  ├── model/        # Data models (GORM)
  ├── plugin/       # Plugin system
  ├── service/      # Business logic layer
  └── store/        # Database access layer (SQLite/PostgreSQL)
pkg/                # Public reusable libraries (utils, types)
web/                # Frontend React application
deploy/             # Deployment files (Docker, Helm, K8s manifests)
configs/            # Runtime configuration (schedsim.yaml)
scripts/            # Build & utility scripts
test/               # E2E and integration tests

Testing

  • Use testify for assertions
  • Prefer table-driven tests
  • Mock external dependencies (K8s client, database)
  • Target >70% coverage for new code

2.2 TypeScript Frontend

Naming Conventions

Element Convention Example
Components PascalCase ScenarioEditor.tsx
Utils camelCase formatDate.ts
Types PascalCase Scenario.ts
Hooks camelCase + use prefix useWebSocket.ts
Stores camelCase useScenarioStore.ts
Constants UPPER_SNAKE MAX_NODES

TypeScript Strict Mode

The project uses strict TypeScript with these settings:

  • strict: true
  • noUnusedLocals: true
  • noUnusedParameters: true
  • erasableSyntaxOnly: true
  • verbatimModuleSyntax: true
  • noFallthroughCasesInSwitch: true
  • noUncheckedSideEffectImports: true
  • Target: ES2022, Module: ESNext, moduleResolution: bundler

Always:

  • Define explicit types for props, function returns
  • Use interface for object shapes
  • Use type for unions, primitives
  • Avoid any - use unknown if necessary

Component Rules

  • Use functional components + Hooks only (no class components)
  • Define Props with TypeScript interface
  • Keep components small (< 300 lines)
  • Use Ant Design components for consistency
  • Extract reusable logic into custom hooks

State Management

  • Global state: Zustand (useXxxStore.ts)
  • Local component state: useState
  • Avoid prop drilling > 2 levels

Imports (ESLint enforced)

// Order: 1. React hooks 2. Libraries 3. Internal modules (@/) 4. Relative paths 5. Types
import { useState, useEffect } from 'react'
import { Button, Card } from 'antd'
import { useScenarioStore } from '@/stores'
import { formatDate } from '@/utils'
import type { Scenario } from '@/types'

Note: React 19 does not require import React from 'react' for JSX. Use import type for type-only imports (enforced by verbatimModuleSyntax).


2.3 API Design

RESTful Conventions

  • Resource names: plural /api/v1/scenarios
  • Version in URL: /api/v1/
  • Pagination: ?page=1&pageSize=20
  • Sorting: ?sort=createdAt&order=desc
  • Filtering: ?status=running

Response Format

// Success (single)
{ data: { ... } }

// Success (list)
{ data: [...], total: 100, page: 1, pageSize: 20 }

// Error
{ error: { code: 400, message: "Invalid input", detail: "..." } }

2.4 Git Conventions

Branch Strategy

  • main - Stable release branch
  • develop - Development branch
  • feat/* - New features
  • fix/* - Bug fixes

Commit Messages

<type>(<scope>): <subject>

type: feat, fix, docs, style, refactor, test, chore, perf
scope: api, web, cluster, engine, auth, report, plugin

Example:

feat(cluster): add KWOK node batch creation support
fix(engine): resolve DAG execution order issue
test(api): add scenario CRUD unit tests

3. Key Technologies

Layer Technology
Frontend React 19, TypeScript 5.9, Vite 7, Ant Design 6
State Zustand 5
Charts @ant-design/charts
Diagram React Flow
Code Editor Monaco Editor (@monaco-editor/react)
Terminal xterm.js (@xterm/xterm)
Routing React Router 7
Backend Go 1.26+, Gin, GORM
Database SQLite (dev), PostgreSQL (prod)
K8s Client client-go, k8s.io/api v0.36
K8s Sim Kind, KWOK
Cluster Runtime Local Docker / Remote VM (SSH) / K8s-in-K8s
Auth JWT (golang-jwt/jwt/v5)
Config Viper
Logging Zap
Testing Vitest, Go testing, Playwright (E2E)
Deploy Docker, Helm Chart

4. Common Patterns

Frontend Component Structure

// src/components/ScenarioEditor/ScenarioEditor.tsx
import { useState } from 'react'
import { Card } from 'antd'
import type { ScenarioEditorProps } from './types'
import { useScenarioStore } from '@/stores'
import { validateScenario } from '@/utils'

export const ScenarioEditor: React.FC<ScenarioEditorProps> = ({ 
  scenarioId, 
  onSave 
}) => {
  const [loading, setLoading] = useState(false)
  const scenario = useScenarioStore(s => s.current)

  const handleSubmit = async () => {
    setLoading(true)
    try {
      await onSave(scenario)
    } finally {
      setLoading(false)
    }
  }

  return (
    <Card>
      {/* ... */}
    </Card>
  )
}

Zustand Store Pattern

// src/stores/scenarioStore.ts
import { create } from 'zustand'

interface ScenarioState {
  current: Scenario | null
  list: Scenario[]
  setCurrent: (s: Scenario) => void
  fetchList: () => Promise<void>
}

export const useScenarioStore = create<ScenarioState>((set) => ({
  current: null,
  list: [],
  setCurrent: (scenario) => set({ current: scenario }),
  fetchList: async () => {
    const data = await api.getScenarios()
    set({ list: data })
  }
}))

5. Development Environment

  • Backend runs on port 8080
  • Frontend runs on port 5173, proxies /api and /db to 8080
  • WebSocket endpoint: /api/v1/ws for real-time logs
  • SQLite Web browser on port 8081 (auto-started by make dev)
  • Database auto-migrates on startup (GORM)
  • Use air for Go hot reload (make setup installs it)
  • CGO_ENABLED=1 required (mattn/go-sqlite3)
  • Path alias: @web/src/ (configured in vite.config.ts + tsconfig)

Cluster Runtime Backends

The platform supports 3 cluster runtime backends (configured in configs/schedsim.yamlclusterRuntime.backend):

Backend Description
local Creates Kind clusters on the local Docker daemon (default)
remote-vm Creates Kind clusters on a remote VM via SSH
k8s-cluster Runs Kind-in-Pod on a target Kubernetes cluster

6. AI Agent Workflow

6.1 Git Commit Requirements

CRITICAL: Every task completion MUST include a git commit.

When any development task is completed (bug fix, feature implementation, refactoring, etc.), the AI agent MUST:

  1. Stage relevant files

    git add <relevant-files>
  2. Commit with descriptive message

    git commit -m "<type>(<scope>): <subject>
    
    <detailed description of changes>
    - item 1
    - item 2
    "
  3. Push to remote

    git push origin main

Commit Message Format

<type>(<scope>): <subject>

<body>

Types:

  • feat: New feature
  • fix: Bug fix
  • refactor: Code refactoring
  • test: Adding tests
  • docs: Documentation
  • chore: Maintenance tasks

Scopes:

  • api: Backend API changes
  • web: Frontend changes
  • cluster: Cluster management (Kind, KWOK, runtime)
  • engine: Execution engine
  • auth: Authentication & authorization
  • report: Report functionality
  • plugin: Plugin system
  • mirror: Cluster snapshot & mirror
  • deploy: Deployment configuration (Helm, Docker, K8s manifests)
  • config: Configuration changes
  • store: Database & data layer

Example Commit

fix(web): resolve sidebar menu highlighting issue

- Changed from defaultOpenKeys to controlled openKeys state
- Added useEffect to respond to route changes
- Fixed dynamic route matching for detail pages

Files changed:
- web/src/components/Layout/Sidebar.tsx

6.2 Pre-commit Checklist

Before committing, ensure:

  • Code builds successfully (make build)
  • Tests pass (make test)
  • No TypeScript errors (cd web && npm run build)
  • Lint passes (make lint)
  • Commit message follows convention

6.3 When to Commit

Always commit after:

  • Completing a bug fix
  • Implementing a new feature
  • Refactoring code
  • Adding tests
  • Updating documentation
  • Fixing a broken build

Do NOT commit:

  • Work in progress (unless creating a draft)
  • Broken tests
  • Sensitive files (.env, credentials, etc.)
  • Generated files (node_modules, dist, etc.)

6.4 Deploy Configuration Sync (MANDATORY)

CRITICAL: Any change affecting runtime behavior MUST be reflected in the Helm Chart configuration under deploy/helm/schedsim/.

Sync Rules

When modifying any of the following, you MUST also update the corresponding Helm deployment files:

If you change... You MUST update...
configs/schedsim.yaml 新增/修改/删除配置项 deploy/helm/schedsim/values.yamlconfig
Server 监听端口 (server.port) values.yamlconfig.server.port + service.port + probe ports
新增环境变量依赖 deploy/helm/schedsim/templates/deployment.yamlenv
健康检查端点路径 (/health, /ready) values.yamllivenessProbe / readinessProbe 路径
新增 Volume/存储需求 deployment.yaml 模板 + values.yaml persistence 段
资源消耗显著变化(如启用新特性导致内存增长) values.yamlresources.limits / resources.requests
应用版本发布 Chart.yamlappVersion + values.yamlimage.tag
新增命令行参数 / 启动 flag deployment.yaml 模板 → args

Key Files Mapping

configs/schedsim.yaml          ←→  deploy/helm/schedsim/values.yaml (config 段)
internal/api/router.go         ←→  values.yaml (端口、健康检查路径)
cmd/schedsim/main.go           ←→  deployment.yaml (args、env)
deploy/helm/schedsim/Chart.yaml  → appVersion 需与发布版本一致

Verification Command

After making changes, MUST run the following to verify Helm template renders correctly:

helm template schedsim-dev deploy/helm/schedsim/ --debug 2>&1 | head -100

Failure to Comply

If the AI agent modifies runtime configuration without updating Helm files:

  • The commit MUST NOT proceed until sync is completed
  • Add a [DEPLOY-SYNC] tag in the commit message body when deployment files are updated alongside application code

Example

feat(api): add prometheus metrics endpoint on /metrics

- Added /metrics endpoint with Go runtime metrics
- [DEPLOY-SYNC] Updated values.yaml: added metrics port 9090
- [DEPLOY-SYNC] Updated deployment.yaml: added metrics container port
- [DEPLOY-SYNC] Updated service.yaml: exposed metrics port

Files changed:
- internal/api/router.go
- deploy/helm/schedsim/values.yaml
- deploy/helm/schedsim/templates/deployment.yaml
- deploy/helm/schedsim/templates/service.yaml