Files
ai-proj-helper/plugins/dev-coding-plugin/skills/SKILL.md

17 KiB
Raw Blame History

name, description
name description
dev-coding 软件编码开发技能。用于代码编写、功能实现、代码审查、重构优化。集成 ai-proj CLI 进行任务管理和进度跟踪。支持 Go、Vue、React、iOS、Android、小程序等全栈开发。

软件编码开发 Skill (dev-coding)

⚠️ REQ 任务自动工作流

当收到 REQ 任务(包含 REQ-YYYYMMDD-XXXX需要开发时必须严格按以下顺序执行

  1. 读取 ticket — 从 ai-proj 获取需求详情和关联文档

    mcp__ai-proj-dev__get_detailed_task_info (通过 REQ 号查找)
    mcp__ai-proj-dev__get_task_document (如果有 PRD 文档)
    
  2. 进入 Plan Mode — 调用 EnterPlanMode 工具

    • 分析需求,探索代码库,设计实现方案
    • 输出实现计划(涉及的文件、改动范围、测试策略)
    • 等待用户审批后再开始编码
  3. 执行计划 — 用户批准后按计划编码 + 写测试

禁止跳过 plan mode 直接编码。


概述

本技能用于软件编码开发工作,支持多种项目类型:

  • Go 后端 (Gin + GORM)
  • Vue 3 / React 前端
  • iOS (Swift/SwiftUI)
  • Android (Kotlin/Jetpack Compose)
  • PDA 应用
  • MCP 桥接服务
  • 微服务架构

核心集成 ai-proj CLI 进行任务管理。


ai-proj 任务管理

开发任务工作流

1. 查看/创建任务 → 2. 启动任务 → 3. 编码实现 → 4. 完成任务 → 5. 记录文档

任务操作速查

操作 CLI 命令 说明
查看任务列表 ai-proj task list 查看项目所有任务
创建任务 ai-proj task create 创建新任务
创建子任务 ai-proj task create --parent-id 分解任务
启动任务 ai-proj task start --id 开始执行
完成任务 ai-proj task complete --id 标记完成
更新任务 ai-proj task update --id 更新状态/描述
查看详情 ai-proj task get --id 完整任务信息
记录文档 ai-proj task append-doc --id 附加文档

开始新任务

# 1. 查看任务列表
ai-proj task list --status todo,in_progress

# 2. 启动任务
ai-proj task start --id <taskId>

# 3. 完成后
ai-proj task complete --id <taskId>

# 4. 记录文档
ai-proj task append-doc --id <taskId> --content "实现说明"

项目类型速查

当前项目生态

项目 类型 后端 前端 移动端
TWMS 仓储物流 Go+Gin+MySQL Vue 3 -
AI-Proj 项目管理 Go+Gin+PostgreSQL React 18 iOS+Android
DICIAI 进销存SaaS Go+Gin+MySQL Vue 3 Android PDA

Go 后端开发

分层架构

backend/
├── cmd/main.go                 # 入口点
├── internal/
│   ├── controller/handlers/    # HTTP 处理层
│   ├── biz/services/           # 业务逻辑层
│   ├── store/database/         # 数据访问层
│   └── middleware/             # 中间件
├── pkg/
│   ├── model/                  # 数据模型
│   ├── errno/                  # 错误定义
│   ├── api/                    # API 类型
│   └── util/                   # 工具函数
└── configs/migrations/         # 配置和迁移

代码规范

// 包声明和导入组织
package main

import (
    // 标准库
    "context"
    "fmt"

    // 第三方
    "github.com/gin-gonic/gin"

    // 项目内部
    "project/internal/pkg/errno"
)

// 错误处理 (Errno 模式)
if err != nil {
    core.WriteResponse(c, errno.ErrBind, nil)
    return
}

// 接口定义
type IStore interface {
    Users() UserStore
}

// 服务注入
type userBiz struct {
    ds store.IStore
}

func NewUserBiz(ds store.IStore) *userBiz {
    return &userBiz{ds: ds}
}

常用命令

# 构建
make build
go build -o ./_output/main ./cmd/main.go

# 运行
./_output/main --config ./configs/config.yaml

# 测试
make test
go test -v ./...

# 代码检查
make lint
golangci-lint run

# Swagger 文档
make swagger
swag init -g cmd/main.go

数据库模型

type UserM struct {
    Id         int64  `gorm:"column:id;primary_key"`
    Username   string `gorm:"column:username;not null"`
    CreateTime int64  `gorm:"column:create_time"`
    UpdateTime int64  `gorm:"column:update_time"`
    DeletedAt  soft_delete.DeletedAt `gorm:"column:deleted_at"`
}

func (m *UserM) TableName() string { return "users" }

func (m *UserM) BeforeCreate(tx *gorm.DB) error {
    m.CreateTime = time.Now().Unix()
    m.UpdateTime = m.CreateTime
    return nil
}

前端 data-testid 规范

编写或修改前端组件时,所有可交互元素必须加 data-testid

命名格式: <模块>-<元素类型>[-<标识>]

<!--  正确 -->
<a-input data-testid="product-input-name" v-model:value="form.name" placeholder="商品名称" />
<a-button data-testid="product-btn-submit" type="primary">创建商品</a-button>
<a-select data-testid="product-select-brand" v-model:value="form.brandId" />
<a-table data-testid="product-table" :dataSource="list" />

<!--  错误  交互元素无 data-testid -->
<a-input v-model:value="form.name" placeholder="商品名称" />
<a-button type="primary">创建商品</a-button>

必须加: 输入框、选择器、开关、按钮(提交/取消/删除)、表格、模态框确认按钮、导航菜单项 不需要加: 纯展示文本、图标、布局容器Row/Col/Space


Vue 3 前端开发

项目结构

frontend/src/
├── api/                  # API 服务 (按模块分组)
│   ├── wms/             # 仓储管理
│   ├── oms/             # 订单管理
│   └── system/          # 系统管理
├── views/               # 页面组件
├── components/          # 可复用组件
├── store/modules/       # Pinia 状态
├── router/              # 路由配置
├── utils/
│   ├── request.ts       # Axios 拦截器
│   └── permission.ts    # 权限检查
└── i18n/                # 国际化

代码规范

// API 服务层
// api/user/model/index.ts
export interface User {
    id: number;
    username: string;
}

// api/user/index.ts
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { User } from './model';

export async function getUsers(params: UserParams) {
    const res = await request.get<ApiResult<PageResult<User>>>(
        '/v1/users',
        { params }
    );
    if (res.status === 200) {
        return res.data;
    }
    return Promise.reject(new Error(res.data.message));
}

常用命令

# 安装依赖
npm install
pnpm install  # DICIAI 使用 pnpm

# 开发
npm run dev

# 构建
npm run build:prod
npm run build:test

# 代码检查
npm run lint:eslint

React 前端开发

项目结构

frontend/src/
├── pages/               # 页面组件
├── components/          # 可复用组件
├── services/            # API 服务
├── hooks/               # 自定义 Hooks
├── contexts/            # Context Providers
├── types/               # TypeScript 类型
├── utils/               # 工具函数
└── config/              # 配置

代码规范

// Context 集成
<QueryProvider>
    <AuthProvider>
        <TimerProvider>
            <ConfigProvider locale={zhCN}>
                <Router>
                    <Routes />
                </Router>
            </ConfigProvider>
        </TimerProvider>
    </AuthProvider>
</QueryProvider>

// API 服务
const api = axios.create({
    baseURL: API_BASE_URL,
    timeout: 120000,
});

api.interceptors.request.use((config) => {
    const token = TokenManager.getToken();
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
});

常用命令

# 开发
npm start

# 构建
npm run build

# 测试
npm test
npm run test:e2e

iOS 开发 (Swift/SwiftUI)

项目结构

AI-Proj-iOS/
├── Core/                # 核心服务
│   ├── Network/        # 网络层
│   ├── Storage/        # 本地存储
│   └── Auth/           # 认证
├── Features/           # 功能模块
│   ├── Dashboard/
│   ├── Tasks/
│   └── Settings/
├── Models/             # 数据模型
└── UI/                 # UI 组件

代码规范

// MVVM 架构
class TaskViewModel: ObservableObject {
    @Published var tasks: [Task] = []
    @Published var isLoading = false

    private let taskService: TaskServiceProtocol

    init(taskService: TaskServiceProtocol = TaskService()) {
        self.taskService = taskService
    }

    func fetchTasks() async {
        isLoading = true
        defer { isLoading = false }

        do {
            tasks = try await taskService.getTasks()
        } catch {
            // 错误处理
        }
    }
}

// SwiftUI 视图
struct TaskListView: View {
    @StateObject private var viewModel = TaskViewModel()

    var body: some View {
        List(viewModel.tasks) { task in
            TaskRow(task: task)
        }
        .task {
            await viewModel.fetchTasks()
        }
    }
}

构建命令

# Xcode 构建
xcodebuild -scheme AI-Proj-iOS -configuration Debug

# 测试
xcodebuild test -scheme AI-Proj-iOS

常见问题排查

SwiftLint 沙盒错误

问题描述 构建时出现错误:

Sandbox: swiftlint(xxxx) deny(1) file-read-data /path/to/.swiftlint.yml

原因 Xcode 15+ 默认启用 User Script Sandboxing限制脚本访问文件系统。

解决方案

方案 1 - 修改项目配置(推荐):

  1. 打开 Xcode → 选择项目 → Build Settings
  2. 搜索 "User Script Sandboxing"
  3. ENABLE_USER_SCRIPT_SANDBOXING 设置为 NO

方案 2 - 命令行构建时禁用:

xcodebuild -scheme AI-Proj-iOS -configuration Debug \
    ENABLE_USER_SCRIPT_SANDBOXING=NO

方案 3 - 直接修改 project.pbxproj

sed -i '' 's/ENABLE_USER_SCRIPT_SANDBOXING = YES/ENABLE_USER_SCRIPT_SANDBOXING = NO/g' \
    AI-Proj-iOS.xcodeproj/project.pbxproj

Personal Development Team 功能限制

问题描述 使用免费 Personal Team 签名时报错:

Cannot create iOS App Development provisioning profile...
Personal development teams do not support the Associated Domains,
Push Notifications and App Groups capabilities.

原因 Personal Team免费账户不支持以下 Entitlements

  • Associated Domains (com.apple.developer.associated-domains)
  • Push Notifications (aps-environment)
  • App Groups (com.apple.security.application-groups)

解决方案

  1. 从 Entitlements 文件中移除不支持的功能:
<!-- AI-Proj-iOS.entitlements -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- 仅保留 Personal Team 支持的功能 -->
    <key>keychain-access-groups</key>
    <array>
        <string>$(AppIdentifierPrefix)com.yourcompany.app</string>
    </array>
</dict>
</plist>
  1. Personal Team 支持的功能:

    • Keychain Access Groups ✓
    • In-App Purchase ✓
    • Game Center ✓
  2. 需要付费 Apple Developer Program 的功能:

    • Push Notifications ✗
    • Associated Domains ✗
    • App Groups ✗
    • CloudKit ✗
    • Sign in with Apple ✗

Android 开发 (Kotlin)

项目结构

android-app/app/src/main/
├── java/com/project/
│   ├── ui/              # UI 层
│   │   ├── screens/    # Compose 屏幕
│   │   └── components/ # 可复用组件
│   ├── data/           # 数据层
│   │   ├── api/        # 网络接口
│   │   ├── repository/ # 仓库模式
│   │   └── local/      # 本地存储
│   ├── domain/         # 业务逻辑
│   └── di/             # 依赖注入
└── res/                # 资源文件

代码规范

// Hilt 依赖注入
@HiltViewModel
class TaskViewModel @Inject constructor(
    private val taskRepository: TaskRepository
) : ViewModel() {

    private val _tasks = MutableStateFlow<List<Task>>(emptyList())
    val tasks: StateFlow<List<Task>> = _tasks.asStateFlow()

    fun fetchTasks() {
        viewModelScope.launch {
            taskRepository.getTasks()
                .collect { _tasks.value = it }
        }
    }
}

// Jetpack Compose
@Composable
fun TaskListScreen(
    viewModel: TaskViewModel = hiltViewModel()
) {
    val tasks by viewModel.tasks.collectAsState()

    LazyColumn {
        items(tasks) { task ->
            TaskItem(task = task)
        }
    }
}

构建命令

# 构建 Debug
./gradlew assembleDebug

# 构建 Release
./gradlew assembleRelease

# 测试
./gradlew test

PDA 应用开发

特点

  • Android 原生开发
  • 扫码枪集成
  • 离线优先
  • 简洁 UI

常见功能

// 扫码处理
class ScanReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val barcode = intent.getStringExtra("SCAN_BARCODE")
        // 处理扫码结果
    }
}

// 离线存储
@Entity(tableName = "inventory")
data class Inventory(
    @PrimaryKey val id: Long,
    val barcode: String,
    val quantity: Int,
    @ColumnInfo(name = "sync_status")
    val syncStatus: SyncStatus = SyncStatus.PENDING
)

MCP 桥接开发

项目结构

mcp-task-bridge/
├── index.ts             # 入口
├── task-service.ts      # 任务服务
├── document-service.ts  # 文档服务
├── base-client.ts       # HTTP 基类
├── types.ts             # 类型定义
└── token-storage.ts     # Token 管理

代码规范

// 服务类模式
export class TaskService extends BaseClient {
    async createTask(
        title: string,
        projectId: number = 1,
        options: CreateTaskOptions = {}
    ): Promise<ApiResponse<Task>> {
        try {
            const response = await this.makeRequest<Task>(
                'POST',
                `/projects/${projectId}/tasks`,
                { title, project_id: projectId, ...options }
            );

            if (response.success) {
                return {
                    success: true,
                    data: response.data,
                    message: `✅ 任务 "${title}" 创建成功`
                };
            }
            return response;
        } catch (error: any) {
            return {
                success: false,
                error: `创建任务失败: ${error.message}`
            };
        }
    }
}

通用开发规范

API 响应格式

{
  "code": 0,
  "message": "success",
  "data": {}
}

分页参数

{
  "page": 1,
  "limit": 20,
  "sort": "created_at",
  "order": "desc"
}

认证方式

  • JWT Token
  • Header: Authorization: Bearer <token>

错误处理

// Go
if err != nil {
    core.WriteResponse(c, errno.ErrXxx, nil)
    return
}

// TypeScript
try {
    const result = await api.call();
} catch (error) {
    message.error(error.message);
}

// Swift
do {
    let result = try await service.fetch()
} catch {
    // 处理错误
}

Git 工作流

提交规范

类型 说明
feat 新功能
fix Bug 修复
docs 文档
refactor 重构
test 测试
chore 杂项

双电脑同步 (au-dev / cn-dev)

# 离开时
git add -A
git commit -m "WIP: sync from $(hostname)"
git push origin $(git branch --show-current)

# 到达时
git fetch origin
git pull origin $(git branch --show-current)

Docker 部署

标准配置

# docker-compose.yml
services:
  backend:
    build: ./backend
    ports:
      - "8080:8080"
    depends_on:
      - db
      - redis

  frontend:
    build: ./frontend
    ports:
      - "80:80"

  db:
    image: mysql:8.0
    # 或 postgres:15

  redis:
    image: redis:alpine

常用端口

服务 端口
Backend 8080 / 9099
Frontend 80 / 3000
MySQL 3306
PostgreSQL 5432
Redis 6379

Push 前必须通过:变更包单元测试

git push/pr create 之前,必须跑所有变更文件对应包的单元测试。

# 找出变更的 Go 文件所在包,跑对应测试
PKGS=$(git diff --name-only origin/main...HEAD | grep '\.go$' | grep -v '_test\.go' | sed 's|/[^/]*$||' | sort -u | sed 's|^|./|' | tr '\n' ' ')

if [ -n "$PKGS" ]; then
    echo "Running tests for changed packages: $PKGS"
    go test -v -count=1 $PKGS
else
    echo "No Go files changed, skipping tests"
fi

规则:

  • 测试通过 → 继续 push + /pr create
  • 测试失败 → 尝试自动修复,修复后重跑
    • 修复成功 → 继续 push
    • 修复失败 → 禁止 push向用户报告失败原因等待指示
  • 仅改了 _test.go → 同样需要跑(验证测试本身通过)
  • 无 Go 文件变更(纯前端/文档) → 跳过

最佳实践

  1. 任务驱动 - 使用 ai-proj 管理所有开发任务
  2. 分层清晰 - Controller → Service → Repository
  3. 接口先行 - 先定义接口再实现
  4. 小步提交 - 频繁提交,每次做一件事
  5. 测试覆盖 - 核心逻辑必须有测试
  6. 文档同步 - 代码变更同步更新文档