feat(monisuo-dev): 重构开发流程为五阶段并优化Agent协作机制

- 更新开发流程描述,细化为需求定义→架构设计→模块化开发→精简测试→功能验证→构建六个环节
- 重构Phase 3为精简+测试,移除构建步骤,新增独立的Phase 5构建阶段
- 优化Agent协作流程:Phase 3输出审查报告供Phase 4使用,避免重复读取代码
- 明确各阶段职责分工,增加Spec同步要求确保Agent间信息一致性
- 添加Phase 5构建阶段,专门处理后端和Flutter构建任务
- 完善Bug修复循环,明确各Agent失败时的修复流程
This commit is contained in:
2026-03-29 20:34:52 +08:00
parent 41c1288616
commit e26031ad17
2 changed files with 68 additions and 643 deletions

View File

@@ -1,6 +1,6 @@
---
name: monisuo-dev
description: Monisuo 项目结构化开发流程。需求分析 → 架构设计 → 开发 → 测试构建。
description: Monisuo 项目结构化开发流程。需求分析 → 架构设计 → 模块化开发 → 精简测试 → 功能验证 → 构建。
---
# Monisuo 开发工作流
@@ -8,18 +8,25 @@ description: Monisuo 项目结构化开发流程。需求分析 → 架构设计
## 流程概览
```
Phase 1: 需求定义 → Phase 1.5: 架构设计 → Phase 2: 模块化开发
Phase 1: 需求定义 → Phase 1.5: 架构设计 → Phase 2: 模块化开发(子任务逐步推进)
↑ │
│ ↓
[Agent A] Phase 3: 精简 + 测试 + 构建
主对话:同步更新 Spec
│ │
│ ↓
│ [Agent A] Phase 3: 精简 + 测试 → 输出审查报告
│ │
│ ↓ (通过)
│ [Agent B] Phase 4: 功能验证(用例驱动
│ [Agent B] Phase 4: 功能验证(接收审查报告
│ │
│ ↓ (通过)
│ [Agent C] Phase 5: 构建
│ │
└──────────────── Bug 修复 ←──────────────────┘
```
**Phase 1-1.5-2 在主对话完成Phase 3 和 Phase 4 分别启动独立 Agent。**
**Phase 1/1.5/2 在主对话完成Phase 3/4/5 分别启动独立 Agent。**
**所有 Agent prompt 中的 `[feature-name]` 由主对话替换为实际值后再传入。**
---
@@ -86,28 +93,38 @@ Phase 1: 需求定义 → Phase 1.5: 架构设计 → Phase 2: 模块化开发
## Phase 2: 模块化开发
依据 Spec 中的 API 契约和数据模型,自底向上开发:
依据 Spec 中的 API 契约和数据模型,**按子模块逐步推进**自底向上开发:
```
1. 数据层 → 2. 后端 API → 3. 前端实现
DDL/Entity Controller/Service Model/Provider/UI
2a. 数据层 → 2b. 后端 API → 2c. Flutter 前端 → 2d. Admin 前端(如有)
DDL/Entity Controller/Service Model/Provider/UI Vue Pages
```
### 子模块执行方式
- 每个子模块独立完成,不与其他子模块混在一起
- 每完成一个子模块,确认无编译错误再进入下一个
- 后端子模块完成后可先验证 API前端再对接
### 代码规范
- Flutter: `flutter analyze` 无错,用 AppSpacing/AppRadius/AppColorScheme禁止硬编码颜色
- Java: Lombok 简化,资金变动方法加 `@Transactional(rollbackFor = Exception.class)`RESTful 设计
### Spec 同步
Phase 2 全部完成后、启动 Agent 前,**主对话必须更新 Spec**
- 实际实现与设计有差异时,以实现为准更新 Spec
- 确保 Phase 3/4 的 Agent 读到的是最新状态
---
## Phase 3: 精简 + 测试 + 构建Agent A
## Phase 3: 精简 + 测试Agent A
Phase 2 完成后,启动独立 Agent 执行代码精简自动化测试和构建
Phase 2 完成且 Spec 已同步后,启动独立 Agent 执行代码精简自动化测试。
### 启动 Agent A
```
Agent(
description: "精简+测试验证与构建",
description: "精简+测试验证",
prompt: |
你是 Monisuo 项目质量 Agent独立完成以下任务不要询问用户。
@@ -129,19 +146,19 @@ Agent(
- Flutter: cd flutter_monisuo && flutter test
- API: ./tests/api/test-[feature].sh如存在
## 5. 构建
- 后端: mvn clean package -DskipTests → target/monisuo-*.jar
- Flutter: cd flutter_monisuo && flutter build web --release --dart-define=ENV=prod → build/web/
## 5. 输出审查报告(供 Agent B 使用)
### 代码审查摘要
- 变更文件列表及每个文件的核心改动
- 代码规范检查结果
- 精简改动摘要(改了什么、为什么改)
## 6. 输出报告
### 测试结果
| 项目 | 状态 | 备注 |
|------|------|------|
| 代码审查 | ✅/❌ | |
| 代码精简 | ✅/❌ | 改动摘要 |
| 后端测试 | ✅/❌ | |
| Flutter 测试 | ✅/❌ | |
| 后端构建 | ✅/❌ | |
| Flutter 构建 | ✅/❌ | |
如有 Bug列出文件、原因、修复建议。返回主对话修复后重新验证。
)
@@ -151,7 +168,7 @@ Agent(
## Phase 4: 功能验证Agent B
**Agent A 全部通过后**,启动第二个独立 Agent,基于 Spec 中的测试用例验证功能正确性
**Agent A 全部通过后**,启动独立 Agent。Agent B 接收 Agent A 的审查报告,避免重复读代码
### 启动 Agent B
@@ -165,9 +182,9 @@ Agent(
- 路径: docs/features/[feature-name].md
- 提取「测试用例」和「验收标准」
## 2. 读取变更代码
- git diff 查看本次变更文件列表
- 阅读变更的 Controller、Service、Provider、UI 代码
## 2. 利用审查报告
- Agent A 已完成代码审查,变更文件列表和核心改动见报告
- 仅对报告未覆盖的逻辑路径做补充阅读
- 对照 Spec 中的 API 设计,确认实现与契约一致
## 3. 逐条验证测试用例
@@ -199,8 +216,37 @@ Agent(
---
## Phase 5: 构建Agent C
**Agent A 和 Agent B 全部通过后**,启动独立 Agent 执行构建。
### 启动 Agent C
```
Agent(
description: "项目构建",
prompt: |
你是 Monisuo 项目构建 Agent独立完成构建任务不要询问用户。
## 1. 构建
- 后端: mvn clean package -DskipTests → target/monisuo-*.jar
- Flutter: cd flutter_monisuo && flutter build web --release --dart-define=ENV=prod → build/web/
## 2. 输出报告
| 项目 | 状态 | 备注 |
|------|------|------|
| 后端构建 | ✅/❌ | 产物路径 |
| Flutter 构建 | ✅/❌ | 产物路径 |
如有构建失败,列出:模块、错误信息、修复建议。返回主对话修复后重新构建。
)
```
---
## Bug 修复循环
- **Agent A 失败**(测试/构建不通过)→ 主对话修复 Bug → 重新启动 Agent A
- **Agent A 失败**(测试不通过)→ 主对话修复 Bug → 重新启动 Agent A
- **Agent B 失败**(功能验证不通过)→ 主对话修复逻辑 → 重新启动 Agent B
- **Agent C 失败**(构建不通过)→ 主对话修复构建问题 → 重新启动 Agent C
- **全部通过** → 开发完成

View File

@@ -1,621 +0,0 @@
---
name: superdesign-flutter
description: Flutter Design Skill - SuperDesign adapted for Flutter/Dart development. Optimized for Material Design 3 and Flutter widgets.
---
# Flutter Design Skill
Use this skill when creating Flutter UI components, screens, or any Flutter UI design work.
This is an adapted version of SuperDesign for Flutter, converting web/CSS patterns to Flutter/Dart equivalents.
## Design Workflow
Follow this structured approach for Flutter UI design:
- **Layout Design** — Think through widget structure, create ASCII wireframes
- **Theme Design** — Define colors, text styles, spacing, shadows
- **Animation Design** — Plan micro-interactions and transitions
- **Implementation** — Generate Flutter/Dart code
### 1. Layout Design
Before coding, sketch the widget tree in ASCII format:
```
┌─────────────────────────────────────┐
│ Scaffold / AppBar │
├─────────────────────────────────────┤
│ │
│ Hero Section (Column) │
│ - Title Text │
│ - CTA ElevatedButton │
│ │
├─────────────────────────────────────┤
│ Row (3x Feature Cards) │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Card │ │Card │ │Card │ │
│ └─────┘ └─────┘ └─────┘ │
├─────────────────────────────────────┤
│ BottomNavigationBar │
└─────────────────────────────────────┘
```
### 2. Theme Guidelines
#### Color Rules:
- NEVER use generic blue (Colors.blue) — it looks dated
- Prefer Material Design 3 color system (ColorScheme)
- Use Theme.of(context).colorScheme for semantic colors
- Support both light and dark mode with ColorScheme
#### OKLCH to Flutter Color Conversion:
Convert OKLCH values to Flutter Color using this helper:
```dart
import 'package:flutter/material.dart';
/// Convert OKLCH to Flutter Color
/// Example: oklch(0.205 0 0) → Color
Color oklchToColor(double l, double c, double h) {
// Simplified conversion - for accurate conversion use a color library
// This is a placeholder implementation
final hue = h;
final chroma = c;
final lightness = l;
// Convert to HSL then to RGB
// For production, use package:flutter_color or similar
return HSLColor.fromAHSL(1.0, hue, chroma, lightness).toColor();
}
// Modern Dark Mode Colors (Vercel/Linear style)
class ModernDarkColors {
static const background = Color(0xFFFFFFFF); // oklch(1 0 0)
static const foreground = Color(0xFF252525); // oklch(0.145 0 0)
static const primary = Color(0xFF343434); // oklch(0.205 0 0)
static const secondary = Color(0xFFF7F7F7); // oklch(0.970 0 0)
static const muted = Color(0xFFF7F7F7); // oklch(0.970 0 0)
static const border = Color(0xFFEBEBEB); // oklch(0.922 0 0)
}
```
#### Flutter Theme Setup:
```dart
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Color(0xFF343434), // Modern neutral
brightness: Brightness.light,
),
fontFamily: 'Inter',
),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Color(0xFF343434),
brightness: Brightness.dark,
),
fontFamily: 'Inter',
),
);
```
#### Font Selection (Google Fonts):
Use `google_fonts` package:
```yaml
# pubspec.yaml
dependencies:
google_fonts: ^6.1.0
```
```dart
import 'package:google_fonts/google_fonts.dart';
// Sans-serif fonts
final inter = GoogleFonts.inter();
final roboto = GoogleFonts.roboto();
final poppins = GoogleFonts.poppins();
final montserrat = GoogleFonts.montserrat();
final outfit = GoogleFonts.outfit();
final dmSans = GoogleFonts.dmSans();
// Monospace fonts
final jetBrainsMono = GoogleFonts.jetBrainsMono();
final firaCode = GoogleFonts.firaCode();
final sourceCodePro = GoogleFonts.sourceCodePro();
```
#### Spacing System:
```dart
/// Spacing scale based on 4.0 (instead of 0.25rem)
class Spacing {
static const double xs = 4.0;
static const double sm = 8.0;
static const double md = 16.0;
static const double lg = 24.0;
static const double xl = 32.0;
static const double xxl = 48.0;
}
// Usage
Padding(
padding: EdgeInsets.all(Spacing.md), // 16.0
child: Text('Content'),
)
```
### 3. Theme Patterns
#### Modern Dark Mode (Vercel/Linear style):
```dart
ThemeData(
useMaterial3: true,
colorScheme: ColorScheme(
brightness: Brightness.light,
background: Color(0xFFFFFFFF),
onBackground: Color(0xFF252525),
primary: Color(0xFF343434),
onPrimary: Color(0xFFFBFBFB),
secondary: Color(0xFFF7F7F7),
onSecondary: Color(0xFF252525),
surface: Color(0xFFFFFFFF),
onSurface: Color(0xFF252525),
outline: Color(0xFFEBEBEB),
),
cardTheme: CardTheme(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0), // 0.625rem
),
),
);
```
#### Neo-Brutalism (90s revival):
```dart
ThemeData(
useMaterial3: true,
colorScheme: ColorScheme(
brightness: Brightness.light,
background: Color(0xFFFFFFFF),
onBackground: Color(0xFF000000),
primary: Color(0xFFFF6B35), // Vibrant orange
secondary: Color(0xFF4ECDC4), // Teal
tertiary: Color(0xFF5B5F97), // Purple
outline: Color(0xFF000000),
),
cardTheme: CardTheme(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0), // No radius
side: BorderSide(color: Colors.black, width: 2),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
elevation: 0,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
),
),
);
```
#### Glassmorphism:
```dart
class GlassCard extends StatelessWidget {
final Widget child;
const GlassCard({required this.child});
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(16.0),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
border: Border.all(
color: Colors.white.withOpacity(0.2),
width: 1,
),
borderRadius: BorderRadius.circular(16.0),
),
child: child,
),
),
);
}
}
```
### 4. Animation Guidelines
#### Flutter Animation Equivalents:
```dart
// Button press animation (150ms)
class AnimatedButton extends StatefulWidget {
@override
_AnimatedButtonState createState() => _AnimatedButtonState();
}
class _AnimatedButtonState extends State<AnimatedButton>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _scaleAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 150),
vsync: this,
);
_scaleAnimation = Tween<double>(begin: 1.0, end: 0.95).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (_) => _controller.forward(),
onTapUp: (_) => _controller.reverse(),
onTapCancel: () => _controller.reverse(),
child: ScaleTransition(
scale: _scaleAnimation,
child: ElevatedButton(...),
),
);
}
}
// Fade in animation (400ms)
class FadeInWidget extends StatefulWidget {
final Widget child;
const FadeInWidget({required this.child});
@override
_FadeInWidgetState createState() => _FadeInWidgetState();
}
class _FadeInWidgetState extends State<FadeInWidget>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _opacity;
late Animation<Offset> _slide;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 400),
vsync: this,
);
_opacity = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
_slide = Tween<Offset>(begin: Offset(0, 0.05), end: Offset.zero)
.animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));
_controller.forward();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: _slide,
child: FadeTransition(opacity: _opacity, child: widget.child),
);
}
}
```
#### Common Animation Durations:
```dart
class AnimationDurations {
static const Duration buttonPress = Duration(milliseconds: 150);
static const Duration hover = Duration(milliseconds: 200);
static const Duration fadeIn = Duration(milliseconds: 400);
static const Duration slideIn = Duration(milliseconds: 350);
static const Duration bounce = Duration(milliseconds: 600);
static const Duration pageTransition = Duration(milliseconds: 300);
}
```
### 5. Widget Patterns
#### Responsive Layout:
```dart
class ResponsiveLayout extends StatelessWidget {
final Widget mobile;
final Widget? tablet;
final Widget? desktop;
const ResponsiveLayout({
required this.mobile,
this.tablet,
this.desktop,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= 1024) {
return desktop ?? tablet ?? mobile;
} else if (constraints.maxWidth >= 768) {
return tablet ?? mobile;
} else {
return mobile;
}
},
);
}
}
// Usage
ResponsiveLayout(
mobile: MobileLayout(),
tablet: TabletLayout(),
desktop: DesktopLayout(),
)
```
#### Icons:
```dart
// Use Material Icons (built-in)
Icon(Icons.home)
Icon(Icons.settings)
// Or use Cupertino Icons
Icon(CupertinoIcons.house)
Icon(CupertinoIcons.settings)
// For custom icons, use flutter_svg
import 'package:flutter_svg/flutter_svg.dart';
SvgPicture.asset('assets/icons/custom_icon.svg')
```
#### Images:
```dart
// Network images with error handling
Image.network(
'https://images.unsplash.com/photo-xxx?w=800&h=600',
errorBuilder: (context, error, stackTrace) {
return Icon(Icons.error);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return CircularProgressIndicator();
},
)
// Asset images
Image.asset('assets/images/placeholder.png')
// Use cached_network_image for better performance
CachedNetworkImage(
imageUrl: 'https://images.unsplash.com/photo-xxx?w=800&h=600',
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
)
```
### 6. Accessibility
```dart
// Semantic labels for screen readers
Semantics(
label: 'Submit button',
button: true,
enabled: true,
child: ElevatedButton(...),
)
// Minimum touch target (44x44)
MaterialButton(
minWidth: 44,
height: 44,
child: Text('Button'),
onPressed: () {},
)
// Sufficient color contrast (4.5:1 minimum)
// Use tools like https://webaim.org/resources/contrastchecker/
```
### 7. Component Design Tips
#### Cards:
```dart
Card(
elevation: 2, // Subtle shadow
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
child: Padding(
padding: EdgeInsets.all(16.0), // p-4
child: Column(...),
),
)
// Hover effect (web only)
InkWell(
onTap: () {},
hoverColor: Colors.transparent,
splashColor: Colors.transparent,
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: AnimatedContainer(
duration: Duration(milliseconds: 200),
transform: Matrix4.identity()..translate(0.0, _isHovered ? -2.0 : 0.0),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(_isHovered ? 0.15 : 0.1),
blurRadius: _isHovered ? 12 : 8,
offset: Offset(0, _isHovered ? 4 : 2),
),
],
),
child: Card(...),
),
),
)
```
#### Buttons:
```dart
// Primary button
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size(44, 44), // Touch target
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
onPressed: () {},
child: Text('Primary'),
)
// Secondary button
OutlinedButton(
style: OutlinedButton.styleFrom(
minimumSize: Size(44, 44),
),
onPressed: () {},
child: Text('Secondary'),
)
// Ghost button
TextButton(
style: TextButton.styleFrom(
minimumSize: Size(44, 44),
),
onPressed: () {},
child: Text('Ghost'),
)
```
#### Forms:
```dart
TextFormField(
decoration: InputDecoration(
labelText: 'Email', // Clear label above input
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Theme.of(context).colorScheme.primary, width: 2),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Theme.of(context).colorScheme.error),
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter email';
}
return null;
},
)
// Spacing between fields
SizedBox(height: 16.0)
```
#### Navigation:
```dart
// Bottom navigation bar
BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
],
)
// Navigation Rail (for tablets)
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (index) => setState(() => _selectedIndex = index),
destinations: [
NavigationRailDestination(icon: Icon(Icons.home), label: Text('Home')),
NavigationRailDestination(icon: Icon(Icons.settings), label: Text('Settings')),
],
)
```
### 8. Flutter-Specific Best Practices
#### Performance:
```dart
// Use const constructors when possible
const Text('Static text')
const SizedBox(height: 16)
// Use ListView.builder for long lists
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(title: Text(items[index]));
},
)
// Avoid rebuilding widgets with const
const MyStaticWidget()
```
#### State Management:
```dart
// Simple state with StatefulWidget
setState(() {
_counter++;
});
// For complex state, use provider, riverpod, or bloc
// Example with provider:
Consumer<MyModel>(
builder: (context, model, child) {
return Text('${model.value}');
},
)
```
## Quick Reference
| Element | Flutter Recommendation |
|---------|------------------------|
| Primary font | Inter, Outfit, DM Sans (google_fonts) |
| Code font | JetBrains Mono, Fira Code (google_fonts) |
| Border radius | 8.0 - 16.0 (modern), 0 (brutalist) |
| Shadow | BoxShadow with elevation 2-4 |
| Spacing | 4.0 base unit (Spacing class) |
| Animation | 150-400ms, Curves.easeOut |
| Colors | ColorScheme.fromSeed (Material 3) |
| Touch targets | Minimum 44x44 |
---
Based on SuperDesign patterns — https://superdesign.dev
Adapted for Flutter/Dart — Material Design 3