@walwal-harness/cli 2.4.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -22
- package/assets/templates/AGENTS.md.template +31 -0
- package/assets/templates/HARNESS.md +180 -6
- package/assets/templates/config.json +205 -14
- package/assets/templates/evaluation-functional.md.template +119 -0
- package/assets/templates/evaluation-visual.md.template +151 -0
- package/assets/templates/memory.md +20 -0
- package/assets/templates/progress.json.template +6 -0
- package/package.json +5 -2
- package/scripts/harness-next.sh +266 -6
- package/scripts/harness-session-start.sh +15 -12
- package/scripts/harness-statusline.sh +93 -0
- package/scripts/harness-user-prompt-submit.sh +31 -72
- package/scripts/lib/harness-guardrail.sh +143 -0
- package/scripts/lib/harness-render-progress.sh +8 -3
- package/scripts/scan-project.sh +33 -3
- package/skills/dispatcher/references/pipeline-definitions.md +20 -9
- package/skills/evaluator-functional-flutter/SKILL.md +10 -3
- package/skills/generator-frontend-flutter/SKILL.md +36 -2
- package/skills/generator-frontend-flutter/references/anti-patterns.md +44 -12
- package/skills/generator-frontend-flutter/references/flutter-web-pattern.md +273 -0
- package/skills/planner/references/fe-stack-detection.md +62 -15
|
@@ -33,26 +33,49 @@ docmeta:
|
|
|
33
33
|
|
|
34
34
|
각 항목은 **패턴 → 이유 → 대체 방법** 형태.
|
|
35
35
|
|
|
36
|
-
## 1. 웹 전용 API 직접 참조
|
|
36
|
+
## 1. 웹 전용 API 직접 참조 (fe_target 별 차이)
|
|
37
37
|
|
|
38
|
-
### 금지
|
|
38
|
+
### `fe_target = mobile` 또는 `desktop` — 금지
|
|
39
39
|
```dart
|
|
40
|
-
import 'dart:html';
|
|
41
|
-
import 'package:universal_html/html.dart';
|
|
40
|
+
import 'dart:html'; // ✗
|
|
41
|
+
import 'package:universal_html/html.dart'; // ✗
|
|
42
|
+
import 'package:web/web.dart'; // ✗ (가드 없으면)
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
### 이유
|
|
45
|
-
Flutter
|
|
46
|
-
|
|
46
|
+
Flutter 모바일/데스크톱 빌드에서 `dart:html` 참조는 즉시 빌드 실패한다.
|
|
47
|
+
가드 없이 import 하면 cross-platform 코드가 깨진다.
|
|
47
48
|
|
|
48
49
|
### 대체
|
|
49
|
-
|
|
50
|
+
- `kIsWeb` 분기로 플랫폼 체크 후 조건부 import
|
|
51
|
+
- `if (kIsWeb) { ... }` 가드 안에서만 web API 사용
|
|
52
|
+
- 또는 conditional import (`stub.dart` / `web.dart` / `io.dart`)
|
|
53
|
+
|
|
54
|
+
### `fe_target = web` — 허용 (단, 권장 패턴 준수)
|
|
55
|
+
```dart
|
|
56
|
+
import 'package:web/web.dart' as web; // ✓ 권장 (modern)
|
|
57
|
+
import 'dart:js_interop'; // ✓ JS interop
|
|
58
|
+
import 'dart:html'; // ✓ (legacy, 신규 코드는 package:web 권장)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Web 권장 패턴
|
|
62
|
+
- 새 코드는 `package:web` + `dart:js_interop` 사용 (Flutter 3.7+ 에서 stable)
|
|
63
|
+
- `dart:html` 은 legacy — 마이그레이션 대상이지만 즉시 금지는 아님
|
|
64
|
+
- 가능하면 web 전용 코드를 별도 파일로 분리하고 conditional import:
|
|
65
|
+
```dart
|
|
66
|
+
// _web_helper.dart 또는 conditional import
|
|
67
|
+
import 'platform_helper.dart'
|
|
68
|
+
if (dart.library.html) 'platform_helper_web.dart'
|
|
69
|
+
if (dart.library.io) 'platform_helper_io.dart';
|
|
70
|
+
```
|
|
50
71
|
|
|
51
72
|
### 검증
|
|
52
73
|
```bash
|
|
53
|
-
|
|
74
|
+
# fe_target = mobile/desktop: 0개여야 함
|
|
75
|
+
grep -rn "dart:html\|universal_html\|package:web" lib/ integrated_data_layer/lib/
|
|
76
|
+
|
|
77
|
+
# fe_target = web: 매치 OK, 단 'kIsWeb' 가드 또는 conditional import 와 함께 쓰는지 인접 라인 확인
|
|
54
78
|
```
|
|
55
|
-
결과 0개여야 함.
|
|
56
79
|
|
|
57
80
|
---
|
|
58
81
|
|
|
@@ -263,11 +286,20 @@ grep -rEn "(api[_-]?key|secret|token)\s*=\s*['\"][A-Za-z0-9]{16,}['\"]" lib/ int
|
|
|
263
286
|
|
|
264
287
|
## 셀프 체크 스크립트
|
|
265
288
|
|
|
266
|
-
Generator는 handoff 전 다음 명령을 모두 실행하고 결과를 sprint-contract.md에
|
|
289
|
+
Generator는 handoff 전 다음 명령을 모두 실행하고 결과를 sprint-contract.md에 기록한다.
|
|
290
|
+
**`fe_target` 에 따라 1번 룰의 적용 여부가 달라진다.**
|
|
267
291
|
|
|
268
292
|
```bash
|
|
269
|
-
#
|
|
270
|
-
|
|
293
|
+
# fe_target 읽기
|
|
294
|
+
FE_TARGET=$(jq -r '.fe_target // "web"' .harness/actions/pipeline.json 2>/dev/null || echo "web")
|
|
295
|
+
|
|
296
|
+
# 1. 웹 API 직접 참조 — fe_target=web 이 아닐 때만 검사
|
|
297
|
+
if [ "$FE_TARGET" != "web" ]; then
|
|
298
|
+
grep -rn "dart:html\|universal_html\|package:web" lib/ integrated_data_layer/lib/ || echo "OK (FL-01 mobile/desktop)"
|
|
299
|
+
else
|
|
300
|
+
# web 타겟: 가드 없는 사용만 경고 (수동 검토)
|
|
301
|
+
grep -rn "dart:html\|package:web" lib/ | grep -v "kIsWeb\|conditional import" || echo "OK (FL-01 web — manual review)"
|
|
302
|
+
fi
|
|
271
303
|
|
|
272
304
|
# 2. print 남발
|
|
273
305
|
grep -rn "^\s*print(" lib/ integrated_data_layer/lib/ || echo "OK"
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
---
|
|
2
|
+
docmeta:
|
|
3
|
+
id: flutter-web-pattern
|
|
4
|
+
title: Flutter Web 패턴 — fe_target=web 전용
|
|
5
|
+
type: output
|
|
6
|
+
createdAt: 2026-04-09T00:00:00Z
|
|
7
|
+
updatedAt: 2026-04-09T00:00:00Z
|
|
8
|
+
source:
|
|
9
|
+
producer: agent
|
|
10
|
+
skillId: harness-generator-frontend-flutter
|
|
11
|
+
inputs:
|
|
12
|
+
- documentId: harness-generator-frontend-flutter-skill
|
|
13
|
+
uri: ../SKILL.md
|
|
14
|
+
relation: output-from
|
|
15
|
+
sections:
|
|
16
|
+
- sourceRange:
|
|
17
|
+
startLine: 56
|
|
18
|
+
endLine: 90
|
|
19
|
+
targetRange:
|
|
20
|
+
startLine: 21
|
|
21
|
+
endLine: 240
|
|
22
|
+
- documentId: flutter-anti-patterns
|
|
23
|
+
uri: ./anti-patterns.md
|
|
24
|
+
relation: output-from
|
|
25
|
+
sections:
|
|
26
|
+
- sourceRange:
|
|
27
|
+
startLine: 22
|
|
28
|
+
endLine: 75
|
|
29
|
+
targetRange:
|
|
30
|
+
startLine: 90
|
|
31
|
+
endLine: 165
|
|
32
|
+
tags:
|
|
33
|
+
- flutter
|
|
34
|
+
- flutter-web
|
|
35
|
+
- dart-web
|
|
36
|
+
- go-router
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
# Flutter Web 패턴 (`fe_target = web` 전용)
|
|
40
|
+
|
|
41
|
+
`pipeline.json.fe_target == "web"` 일 때만 적용. Mobile/Desktop 타겟에서는 이 문서의 규칙을 무시한다.
|
|
42
|
+
|
|
43
|
+
## 1. 프로젝트 활성화
|
|
44
|
+
|
|
45
|
+
기존 Flutter 프로젝트에 Web 타겟이 없으면:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
flutter config --enable-web
|
|
49
|
+
flutter create --platforms=web .
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`web/index.html`, `web/manifest.json`, `web/favicon.png`, `web/icons/` 가 생성된다.
|
|
53
|
+
|
|
54
|
+
## 2. 빌드 및 개발 서버
|
|
55
|
+
|
|
56
|
+
| 명령 | 용도 |
|
|
57
|
+
|------|------|
|
|
58
|
+
| `flutter run -d chrome` | 개발 서버 (HMR 포함) |
|
|
59
|
+
| `flutter run -d chrome --web-port 8080` | 포트 고정 |
|
|
60
|
+
| `flutter build web --release` | 프로덕션 빌드 (`build/web/`) |
|
|
61
|
+
| `flutter build web --release --web-renderer canvaskit` | CanvasKit 렌더러 (성능 우선) |
|
|
62
|
+
| `flutter build web --release --web-renderer html` | HTML 렌더러 (호환성 우선, 작은 번들) |
|
|
63
|
+
|
|
64
|
+
> **렌더러 선택**: 모바일 사파리 호환성이 중요하면 `html`, 데스크톱/Chrome 중심이면 `canvaskit` (또는 auto).
|
|
65
|
+
|
|
66
|
+
## 3. 라우팅 — `go_router` 권장
|
|
67
|
+
|
|
68
|
+
URL 동기화 + 브라우저 history 지원을 위해 `go_router` 사용.
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
# pubspec.yaml
|
|
72
|
+
dependencies:
|
|
73
|
+
go_router: ^14.0.0
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```dart
|
|
77
|
+
// lib/router/app_router.dart
|
|
78
|
+
import 'package:go_router/go_router.dart';
|
|
79
|
+
|
|
80
|
+
final pAppRouterProvider = Provider<GoRouter>((ref) {
|
|
81
|
+
return GoRouter(
|
|
82
|
+
initialLocation: '/',
|
|
83
|
+
routes: [
|
|
84
|
+
GoRoute(path: '/', builder: (ctx, state) => const HomePage()),
|
|
85
|
+
GoRoute(path: '/login', builder: (ctx, state) => const LoginPage()),
|
|
86
|
+
GoRoute(
|
|
87
|
+
path: '/items/:id',
|
|
88
|
+
builder: (ctx, state) => ItemPage(id: state.pathParameters['id']!),
|
|
89
|
+
),
|
|
90
|
+
],
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```dart
|
|
96
|
+
// main.dart
|
|
97
|
+
class App extends ConsumerWidget {
|
|
98
|
+
@override
|
|
99
|
+
Widget build(BuildContext context, WidgetRef ref) {
|
|
100
|
+
final router = ref.watch(pAppRouterProvider);
|
|
101
|
+
return MaterialApp.router(
|
|
102
|
+
routerConfig: router,
|
|
103
|
+
// ...
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Hash routing vs Path routing**:
|
|
110
|
+
- 기본은 hash routing (`/#/login`)
|
|
111
|
+
- Path routing 으로 바꾸려면 `web/index.html` 의 `<base href="/">` 설정 + 서버 fallback (모든 경로 → `index.html`)
|
|
112
|
+
|
|
113
|
+
## 4. JS Interop (필요할 때만)
|
|
114
|
+
|
|
115
|
+
크로스플랫폼 코드를 우선하되, Web 전용 API 가 필요하면 `package:web` + `dart:js_interop` 사용.
|
|
116
|
+
|
|
117
|
+
```dart
|
|
118
|
+
import 'package:web/web.dart' as web;
|
|
119
|
+
import 'dart:js_interop';
|
|
120
|
+
|
|
121
|
+
void copyToClipboard(String text) {
|
|
122
|
+
web.window.navigator.clipboard.writeText(text.toJS);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
String getUserAgent() => web.window.navigator.userAgent;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Conditional import 패턴** (cross-platform 코드를 web/io 로 분기):
|
|
129
|
+
|
|
130
|
+
```dart
|
|
131
|
+
// platform_helper.dart (interface)
|
|
132
|
+
abstract class PlatformHelper {
|
|
133
|
+
String get platformName;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
PlatformHelper getPlatformHelper() => throw UnimplementedError();
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```dart
|
|
140
|
+
// platform_helper_web.dart
|
|
141
|
+
import 'package:web/web.dart' as web;
|
|
142
|
+
import 'platform_helper.dart';
|
|
143
|
+
|
|
144
|
+
class WebPlatformHelper implements PlatformHelper {
|
|
145
|
+
@override
|
|
146
|
+
String get platformName => 'web (${web.window.navigator.userAgent})';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
PlatformHelper getPlatformHelper() => WebPlatformHelper();
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```dart
|
|
153
|
+
// platform_helper_io.dart
|
|
154
|
+
import 'dart:io';
|
|
155
|
+
import 'platform_helper.dart';
|
|
156
|
+
|
|
157
|
+
class IoPlatformHelper implements PlatformHelper {
|
|
158
|
+
@override
|
|
159
|
+
String get platformName => 'io (${Platform.operatingSystem})';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
PlatformHelper getPlatformHelper() => IoPlatformHelper();
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```dart
|
|
166
|
+
// 사용처
|
|
167
|
+
import 'platform_helper.dart'
|
|
168
|
+
if (dart.library.html) 'platform_helper_web.dart'
|
|
169
|
+
if (dart.library.io) 'platform_helper_io.dart';
|
|
170
|
+
|
|
171
|
+
final helper = getPlatformHelper();
|
|
172
|
+
print(helper.platformName);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## 5. CORS 와 백엔드 연동
|
|
176
|
+
|
|
177
|
+
Flutter Web 은 브라우저에서 실행되므로 백엔드 API 호출 시 **CORS** 가 적용된다.
|
|
178
|
+
|
|
179
|
+
- 개발 단계: 백엔드 Gateway 의 `Access-Control-Allow-Origin` 에 `http://localhost:8080` (또는 `*`) 추가
|
|
180
|
+
- 프로덕션: 동일 origin 또는 명시적 CORS 화이트리스트
|
|
181
|
+
- API 키/인증 토큰은 **HttpOnly cookie** 또는 메모리 보관 (localStorage 는 XSS 위험)
|
|
182
|
+
|
|
183
|
+
`Dio` 인터셉터로 CSRF 토큰 등을 헤더에 추가:
|
|
184
|
+
|
|
185
|
+
```dart
|
|
186
|
+
final dio = Dio(BaseOptions(
|
|
187
|
+
baseUrl: 'https://api.example.com',
|
|
188
|
+
headers: {'Content-Type': 'application/json'},
|
|
189
|
+
));
|
|
190
|
+
|
|
191
|
+
dio.interceptors.add(InterceptorsWrapper(
|
|
192
|
+
onRequest: (options, handler) {
|
|
193
|
+
final token = ref.read(pAuthProvider).accessToken;
|
|
194
|
+
if (token != null) {
|
|
195
|
+
options.headers['Authorization'] = 'Bearer $token';
|
|
196
|
+
}
|
|
197
|
+
return handler.next(options);
|
|
198
|
+
},
|
|
199
|
+
));
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 6. SEO / Meta Tags
|
|
203
|
+
|
|
204
|
+
`web/index.html` 의 `<head>` 에 SEO 메타 태그 추가:
|
|
205
|
+
|
|
206
|
+
```html
|
|
207
|
+
<meta name="description" content="Suprema CLUe — Smart Access Control">
|
|
208
|
+
<meta property="og:title" content="CLUe">
|
|
209
|
+
<meta property="og:description" content="...">
|
|
210
|
+
<meta property="og:image" content="/icons/og-image.png">
|
|
211
|
+
<link rel="canonical" href="https://app.example.com">
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
> SPA 의 SEO 한계: Flutter Web 은 client-side rendering 이므로 검색엔진이 동적 콘텐츠를 인덱싱하지 못할 수 있다. SSR 이 필요하면 Next.js + REST API 패턴을 고려.
|
|
215
|
+
|
|
216
|
+
## 7. 자산 최적화
|
|
217
|
+
|
|
218
|
+
- 이미지: `assets/images/` 에 두고 `pubspec.yaml` 의 `flutter.assets` 에 등록
|
|
219
|
+
- 폰트: `web/fonts/` 또는 `assets/fonts/` + `pubspec.yaml` 의 `flutter.fonts`
|
|
220
|
+
- 큰 이미지: webp 사용 권장 (`flutter_image_compress` 또는 사전 변환)
|
|
221
|
+
- Tree-shaking: `flutter build web --tree-shake-icons` 로 사용하지 않는 Material 아이콘 제거
|
|
222
|
+
|
|
223
|
+
## 8. PWA (Progressive Web App)
|
|
224
|
+
|
|
225
|
+
`flutter create --platforms=web` 시 자동 생성되는 `web/manifest.json` 을 채워서 PWA 로 동작:
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"name": "CLUe",
|
|
230
|
+
"short_name": "CLUe",
|
|
231
|
+
"start_url": "/",
|
|
232
|
+
"display": "standalone",
|
|
233
|
+
"background_color": "#FFFFFF",
|
|
234
|
+
"theme_color": "#6682FF",
|
|
235
|
+
"icons": [
|
|
236
|
+
{ "src": "icons/Icon-192.png", "sizes": "192x192", "type": "image/png" },
|
|
237
|
+
{ "src": "icons/Icon-512.png", "sizes": "512x512", "type": "image/png" }
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Service worker 는 `flutter build web` 시 자동 생성된다 (`flutter_service_worker.js`).
|
|
243
|
+
|
|
244
|
+
## 9. 디버깅 — Chrome DevTools
|
|
245
|
+
|
|
246
|
+
- `flutter run -d chrome` 후 Chrome 자체 DevTools 열기 (F12)
|
|
247
|
+
- Console 에서 `print()` 출력 확인 가능 (단, 프로덕션 빌드에서는 `print` 금지)
|
|
248
|
+
- Source map 활성화: `--web-renderer html --source-maps` (디버그 빌드 기본)
|
|
249
|
+
- Network 탭에서 API 호출 직접 검사 가능 → Playwright 기반 `evaluator-functional` 도 동일하게 동작
|
|
250
|
+
|
|
251
|
+
## 10. Eval 인터페이스
|
|
252
|
+
|
|
253
|
+
`fe_target = web` 인 경우 `harness-next.sh` 가 다음과 같이 자동 라우팅:
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
generator-frontend-flutter (Self-Verification: flutter analyze + flutter test)
|
|
257
|
+
→ evaluator-functional (Playwright MCP — http://localhost:포트 E2E)
|
|
258
|
+
→ evaluator-visual (Playwright MCP — 스크린샷 + 반응형 + 접근성)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Generator 의 Self-Verification 단계에서 `flutter build web --release` 가 성공하는지 확인** 후 handoff.
|
|
262
|
+
|
|
263
|
+
## 11. 호스팅 (참고)
|
|
264
|
+
|
|
265
|
+
| 호스팅 | 빌드 산출물 |
|
|
266
|
+
|--------|------------|
|
|
267
|
+
| Vercel | `build/web/` 디렉토리를 정적 호스팅 |
|
|
268
|
+
| Netlify | 동일 |
|
|
269
|
+
| Firebase Hosting | `firebase deploy --only hosting` (firebase.json 의 public 을 `build/web` 으로) |
|
|
270
|
+
| GitHub Pages | `build/web/` 을 gh-pages 브랜치에 푸시 |
|
|
271
|
+
| 자체 서버 | nginx 로 정적 파일 서빙 + SPA fallback (`try_files $uri /index.html`) |
|
|
272
|
+
|
|
273
|
+
호스팅 결정은 Planner / 사용자가 함. Generator 는 빌드 산출물만 보장.
|
|
@@ -76,40 +76,87 @@ Planner는 Sprint 1 착수 전 반드시 `fe_stack`을 확정하고 `pipeline.js
|
|
|
76
76
|
|
|
77
77
|
혼재 프로젝트(Web + Flutter mobile)라면 사용자에게 **현 스프린트의 타깃**을 묻는다 — 파이프라인은 한 번에 하나의 `fe_stack`만 취급한다.
|
|
78
78
|
|
|
79
|
+
## 2.5 fe_target 확정 (Flutter 전용)
|
|
80
|
+
|
|
81
|
+
`fe_stack == "flutter"` 인 경우, **반드시** `fe_target` 도 함께 확정해야 한다 (`web` | `mobile` | `desktop`).
|
|
82
|
+
이는 Flutter Web vs Mobile/Desktop 에서 사용 가능한 API, 빌드 명령, evaluator 가 달라지기 때문이다.
|
|
83
|
+
|
|
84
|
+
### 자동 감지 (scan-result.json 의 `tech_stack.fe_target`)
|
|
85
|
+
|
|
86
|
+
| 시그널 | fe_target |
|
|
87
|
+
|--------|-----------|
|
|
88
|
+
| `<flutter_root>/web/index.html` 존재 | `web` |
|
|
89
|
+
| `<flutter_root>/android/` 또는 `ios/` 존재, web/ 없음 | `mobile` |
|
|
90
|
+
| `<flutter_root>/macos/`, `windows/`, `linux/` 존재 (mobile/web 없음) | `desktop` |
|
|
91
|
+
| 없음 | `unknown` |
|
|
92
|
+
|
|
93
|
+
### 사용자 질문 (불명확하거나 multi-target)
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Flutter 프로젝트의 타깃을 확인합니다:
|
|
97
|
+
|
|
98
|
+
(A) Web — 브라우저 (Chrome/Safari/Firefox), 컴파일 결과는 HTML+JS+CSS
|
|
99
|
+
(B) Mobile — Android / iOS 네이티브 빌드
|
|
100
|
+
(C) Desktop — macOS / Windows / Linux 네이티브 빌드
|
|
101
|
+
|
|
102
|
+
감지된 시그널:
|
|
103
|
+
- web/index.html: [있음/없음]
|
|
104
|
+
- android|ios/: [있음/없음]
|
|
105
|
+
- macos|windows|linux/: [있음/없음]
|
|
106
|
+
|
|
107
|
+
이번 스프린트의 타깃은? (A/B/C)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### fe_target → Eval 흐름
|
|
111
|
+
|
|
112
|
+
| fe_target | Generator | Eval-Functional | Eval-Visual |
|
|
113
|
+
|-----------|-----------|----------------|-------------|
|
|
114
|
+
| `web` | `generator-frontend-flutter` | `evaluator-functional` (Playwright!) | `evaluator-visual` (Playwright!) |
|
|
115
|
+
| `mobile` | `generator-frontend-flutter` | `evaluator-functional-flutter` (정적 분석) | SKIP |
|
|
116
|
+
| `desktop` | `generator-frontend-flutter` | `evaluator-functional-flutter` (정적 분석) | SKIP |
|
|
117
|
+
|
|
118
|
+
**핵심**: Flutter Web 의 빌드 결과물(HTML/JS/CSS)은 일반 웹앱과 동일하므로 Playwright 기반
|
|
119
|
+
React 경로의 evaluator 를 그대로 재사용한다. Generator-Frontend-Flutter 의 Self-Verification
|
|
120
|
+
단계에서 `flutter analyze`/`flutter test`/`flutter build web` 정적 검증이 이미 통과한 상태로 handoff 된다.
|
|
121
|
+
|
|
79
122
|
## 3. pipeline.json 갱신
|
|
80
123
|
|
|
81
|
-
`fe_stack` 확정 후 `pipeline.json`에 반드시 추가:
|
|
124
|
+
`fe_stack` + `fe_target` 확정 후 `pipeline.json`에 반드시 추가:
|
|
82
125
|
|
|
83
126
|
```json
|
|
84
127
|
{
|
|
85
128
|
"pipeline": "FULLSTACK",
|
|
86
129
|
"planner_mode": "full",
|
|
87
130
|
"fe_stack": "flutter",
|
|
131
|
+
"fe_target": "web",
|
|
88
132
|
"agents_active": [
|
|
89
133
|
"planner",
|
|
90
134
|
"generator-backend",
|
|
91
135
|
"generator-frontend-flutter",
|
|
92
|
-
"evaluator-functional
|
|
136
|
+
"evaluator-functional",
|
|
137
|
+
"evaluator-visual"
|
|
93
138
|
],
|
|
94
139
|
"agents_skipped": [
|
|
95
140
|
"generator-frontend",
|
|
96
|
-
"evaluator-functional"
|
|
97
|
-
"evaluator-visual"
|
|
141
|
+
"evaluator-functional-flutter"
|
|
98
142
|
],
|
|
99
|
-
"evaluator_mode": "
|
|
100
|
-
"notes": "Flutter
|
|
143
|
+
"evaluator_mode": "playwright-web",
|
|
144
|
+
"notes": "Flutter Web — 컴파일 결과가 HTML+JS+CSS 이므로 React 경로의 Playwright evaluator 사용. Generator 의 Self-Verification 에서 flutter analyze/test 통과 전제."
|
|
101
145
|
}
|
|
102
146
|
```
|
|
103
147
|
|
|
104
|
-
### fe_stack → 파이프라인 매핑
|
|
105
|
-
|
|
106
|
-
| pipeline | fe_stack | agents_active 예시 |
|
|
107
|
-
|
|
108
|
-
| FULLSTACK | react | planner, generator-backend, generator-frontend, evaluator-functional, evaluator-visual |
|
|
109
|
-
| FULLSTACK | flutter | planner, generator-backend, generator-frontend-flutter, evaluator-functional-
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
148
|
+
### fe_stack + fe_target → 파이프라인 매핑
|
|
149
|
+
|
|
150
|
+
| pipeline | fe_stack | fe_target | agents_active 예시 |
|
|
151
|
+
|----------|----------|-----------|-------------------|
|
|
152
|
+
| FULLSTACK | react | (n/a) | planner, generator-backend, generator-frontend, evaluator-functional, evaluator-visual |
|
|
153
|
+
| FULLSTACK | flutter | **web** | planner, generator-backend, generator-frontend-flutter, evaluator-functional, evaluator-visual |
|
|
154
|
+
| FULLSTACK | flutter | mobile | planner, generator-backend, generator-frontend-flutter, evaluator-functional-flutter |
|
|
155
|
+
| FULLSTACK | flutter | desktop | planner, generator-backend, generator-frontend-flutter, evaluator-functional-flutter |
|
|
156
|
+
| FE-ONLY | react | (n/a) | planner, generator-frontend, evaluator-functional, evaluator-visual |
|
|
157
|
+
| FE-ONLY | flutter | **web** | planner, generator-frontend-flutter, evaluator-functional, evaluator-visual |
|
|
158
|
+
| FE-ONLY | flutter | mobile | planner, generator-frontend-flutter, evaluator-functional-flutter |
|
|
159
|
+
| BE-ONLY | (무관) | (n/a) | planner, generator-backend, evaluator-functional |
|
|
113
160
|
|
|
114
161
|
## 4. Flutter 선택 시 추가 작업
|
|
115
162
|
|