timsquad 3.3.0 → 3.5.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.ko.md +288 -0
- package/README.md +158 -151
- package/dist/commands/compile.d.ts +3 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +170 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +95 -5
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/full.js +1 -0
- package/dist/commands/full.js.map +1 -1
- package/dist/commands/git/pr.js +6 -5
- package/dist/commands/git/pr.js.map +1 -1
- package/dist/commands/git/release.js +2 -7
- package/dist/commands/git/release.js.map +1 -1
- package/dist/commands/improve.js +2 -2
- package/dist/commands/improve.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +2 -2
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/metrics.d.ts.map +1 -1
- package/dist/commands/metrics.js +6 -2
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/retro.js +8 -8
- package/dist/commands/retro.js.map +1 -1
- package/dist/commands/session.js +3 -3
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/skills.d.ts +12 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +228 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +23 -1
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/daemon/entry.js +3 -3
- package/dist/daemon/entry.js.map +1 -1
- package/dist/daemon/event-queue.d.ts.map +1 -1
- package/dist/daemon/event-queue.js +2 -2
- package/dist/daemon/event-queue.js.map +1 -1
- package/dist/daemon/index.d.ts +4 -2
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +214 -52
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/jsonl-watcher.d.ts +1 -0
- package/dist/daemon/jsonl-watcher.d.ts.map +1 -1
- package/dist/daemon/jsonl-watcher.js.map +1 -1
- package/dist/daemon/meta-cache.d.ts +1 -0
- package/dist/daemon/meta-cache.d.ts.map +1 -1
- package/dist/daemon/meta-cache.js +9 -0
- package/dist/daemon/meta-cache.js.map +1 -1
- package/dist/daemon/session-notes.d.ts +33 -0
- package/dist/daemon/session-notes.d.ts.map +1 -0
- package/dist/daemon/session-notes.js +74 -0
- package/dist/daemon/session-notes.js.map +1 -0
- package/dist/daemon/session-state.d.ts +27 -0
- package/dist/daemon/session-state.d.ts.map +1 -0
- package/dist/daemon/session-state.js +165 -0
- package/dist/daemon/session-state.js.map +1 -0
- package/dist/daemon/shutdown.d.ts.map +1 -1
- package/dist/daemon/shutdown.js +9 -1
- package/dist/daemon/shutdown.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-generator.d.ts +4 -0
- package/dist/lib/agent-generator.d.ts.map +1 -1
- package/dist/lib/agent-generator.js +52 -3
- package/dist/lib/agent-generator.js.map +1 -1
- package/dist/lib/compile-rules.d.ts +66 -0
- package/dist/lib/compile-rules.d.ts.map +1 -0
- package/dist/lib/compile-rules.js +114 -0
- package/dist/lib/compile-rules.js.map +1 -0
- package/dist/lib/compiler.d.ts +105 -0
- package/dist/lib/compiler.d.ts.map +1 -0
- package/dist/lib/compiler.js +368 -0
- package/dist/lib/compiler.js.map +1 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +8 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/project.d.ts.map +1 -1
- package/dist/lib/project.js +8 -3
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/skill-generator.d.ts.map +1 -1
- package/dist/lib/skill-generator.js +22 -1
- package/dist/lib/skill-generator.js.map +1 -1
- package/dist/lib/template.d.ts.map +1 -1
- package/dist/lib/template.js +6 -0
- package/dist/lib/template.js.map +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +12 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/project.d.ts +1 -1
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js +2 -0
- package/dist/types/project.js.map +1 -1
- package/package.json +4 -4
- package/templates/base/agents/base/tsq-architect.md +2 -2
- package/templates/base/agents/overlays/domain/mobile/_common.md +13 -0
- package/templates/base/knowledge/checklists/plan-quality.md +31 -0
- package/templates/base/knowledge/checklists/stability-verification.md +14 -0
- package/templates/base/skills/controller/SKILL.md +111 -0
- package/templates/base/skills/controller/references/README.md +35 -0
- package/templates/base/skills/controller/rules/README.md +18 -0
- package/templates/base/skills/mobile/dart/SKILL.md +69 -0
- package/templates/base/skills/mobile/dart/rules/async-patterns.md +112 -0
- package/templates/base/skills/mobile/dart/rules/code-style.md +96 -0
- package/templates/base/skills/mobile/dart/rules/null-safety.md +84 -0
- package/templates/base/skills/mobile/dart/rules/type-system.md +111 -0
- package/templates/base/skills/mobile/flutter/SKILL.md +89 -0
- package/templates/base/skills/mobile/flutter/ci-cd/SKILL.md +82 -0
- package/templates/base/skills/mobile/flutter/ci-cd/references/ci-cd-pipeline.md +314 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/code-signing.md +106 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/codemagic-setup.md +116 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/fastlane-setup.md +105 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/github-actions.md +112 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/store-deployment.md +106 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/versioning.md +107 -0
- package/templates/base/skills/mobile/flutter/i18n/SKILL.md +78 -0
- package/templates/base/skills/mobile/flutter/i18n/references/i18n-architecture.md +225 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/arb-files.md +182 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/locale-switching.md +226 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/localization-setup.md +137 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/plural-gender.md +159 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/text-direction.md +199 -0
- package/templates/base/skills/mobile/flutter/monitoring/SKILL.md +81 -0
- package/templates/base/skills/mobile/flutter/monitoring/references/monitoring-architecture.md +269 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/analytics.md +227 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/crashlytics-setup.md +195 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/logging.md +258 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/performance-monitoring.md +248 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/sentry-integration.md +249 -0
- package/templates/base/skills/mobile/flutter/networking/SKILL.md +88 -0
- package/templates/base/skills/mobile/flutter/networking/references/api-client-architecture.md +305 -0
- package/templates/base/skills/mobile/flutter/networking/rules/caching.md +212 -0
- package/templates/base/skills/mobile/flutter/networking/rules/connectivity.md +213 -0
- package/templates/base/skills/mobile/flutter/networking/rules/dio-setup.md +159 -0
- package/templates/base/skills/mobile/flutter/networking/rules/error-handling.md +209 -0
- package/templates/base/skills/mobile/flutter/networking/rules/interceptors.md +205 -0
- package/templates/base/skills/mobile/flutter/networking/rules/retrofit-patterns.md +194 -0
- package/templates/base/skills/mobile/flutter/push-notifications/SKILL.md +87 -0
- package/templates/base/skills/mobile/flutter/push-notifications/references/notification-architecture.md +340 -0
- package/templates/base/skills/mobile/flutter/push-notifications/references/platform-setup.md +286 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/background-processing.md +308 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/deep-linking.md +217 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/fcm-setup.md +164 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/local-notifications.md +262 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-handling.md +210 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-permissions.md +246 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/rich-notifications.md +320 -0
- package/templates/base/skills/mobile/flutter/references/freezed-patterns.md +162 -0
- package/templates/base/skills/mobile/flutter/references/project-structure.md +170 -0
- package/templates/base/skills/mobile/flutter/rules/animations.md +112 -0
- package/templates/base/skills/mobile/flutter/rules/architecture.md +121 -0
- package/templates/base/skills/mobile/flutter/rules/navigation-routing.md +117 -0
- package/templates/base/skills/mobile/flutter/rules/performance.md +112 -0
- package/templates/base/skills/mobile/flutter/rules/platform-adaptive.md +126 -0
- package/templates/base/skills/mobile/flutter/rules/state-management.md +110 -0
- package/templates/base/skills/mobile/flutter/rules/testing.md +131 -0
- package/templates/base/skills/mobile/flutter/rules/widget-conventions.md +122 -0
- package/templates/base/skills/mobile/flutter/security/SKILL.md +86 -0
- package/templates/base/skills/mobile/flutter/security/references/mobile-security-checklist.md +168 -0
- package/templates/base/skills/mobile/flutter/security/rules/api-key-protection.md +206 -0
- package/templates/base/skills/mobile/flutter/security/rules/authentication.md +248 -0
- package/templates/base/skills/mobile/flutter/security/rules/data-protection.md +271 -0
- package/templates/base/skills/mobile/flutter/security/rules/obfuscation.md +213 -0
- package/templates/base/skills/mobile/flutter/security/rules/secure-storage.md +171 -0
- package/templates/base/skills/mobile/flutter/security/rules/ssl-pinning.md +197 -0
- package/templates/base/skills/stability-verification/SKILL.md +64 -0
- package/templates/base/skills/stability-verification/references/release-checklist.md +34 -0
- package/templates/base/skills/stability-verification/references/security-fix-patterns.md +112 -0
- package/templates/base/skills/stability-verification/rules/verification-layers.md +67 -0
- package/templates/base/skills/stability-verification/rules/verification-workflow.md +69 -0
- package/templates/base/skills/stability-verification/scripts/verify.sh +294 -0
- package/templates/platforms/claude-code/CLAUDE.md.template +25 -0
- package/templates/platforms/claude-code/rules/build-gate.md +28 -0
- package/templates/platforms/claude-code/rules/completion-verification.md +30 -0
- package/templates/platforms/claude-code/rules/context-monitor.md +23 -0
- package/templates/platforms/claude-code/rules/plan-review.md +45 -0
- package/templates/platforms/claude-code/rules/quality-guards.md +43 -0
- package/templates/platforms/claude-code/rules/session-notes.md +18 -0
- package/templates/platforms/claude-code/rules/skill-suggest.md +27 -0
- package/templates/platforms/claude-code/scripts/build-gate.sh +73 -0
- package/templates/platforms/claude-code/scripts/completion-guard.sh +93 -0
- package/templates/platforms/claude-code/scripts/phase-guard.sh +79 -0
- package/templates/platforms/claude-code/scripts/safe-guard.sh +83 -0
- package/templates/platforms/claude-code/scripts/skill-rules.json +85 -0
- package/templates/platforms/claude-code/scripts/skill-suggest.sh +105 -0
- package/templates/platforms/claude-code/settings.json +111 -3
- package/templates/project-types/mobile-app/config.yaml +123 -0
- package/templates/project-types/mobile-app/process/workflow.xml +191 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Code Style (Effective Dart)
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: style, naming, linting, documentation
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Code Style (Effective Dart)
|
|
8
|
+
|
|
9
|
+
Effective Dart 기반 코딩 컨벤션. `dart_style` 포매터 + strict analysis_options.
|
|
10
|
+
|
|
11
|
+
### analysis_options.yaml
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
include: package:flutter_lints/flutter.yaml
|
|
15
|
+
# 또는 non-Flutter: package:lints/recommended.yaml
|
|
16
|
+
|
|
17
|
+
linter:
|
|
18
|
+
rules:
|
|
19
|
+
# 필수 추가 규칙
|
|
20
|
+
- prefer_const_constructors
|
|
21
|
+
- prefer_const_declarations
|
|
22
|
+
- avoid_dynamic_calls
|
|
23
|
+
- unawaited_futures
|
|
24
|
+
- cancel_subscriptions
|
|
25
|
+
- close_sinks
|
|
26
|
+
- prefer_final_locals
|
|
27
|
+
- avoid_print # debugPrint 사용
|
|
28
|
+
- require_trailing_commas
|
|
29
|
+
|
|
30
|
+
analyzer:
|
|
31
|
+
errors:
|
|
32
|
+
missing_return: error
|
|
33
|
+
unawaited_futures: warning
|
|
34
|
+
language:
|
|
35
|
+
strict-casts: true
|
|
36
|
+
strict-inference: true
|
|
37
|
+
strict-raw-types: true
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 네이밍
|
|
41
|
+
|
|
42
|
+
| 종류 | 규칙 | 예시 |
|
|
43
|
+
|------|------|------|
|
|
44
|
+
| 클래스, enum, typedef | UpperCamelCase | `UserProfile`, `AuthState` |
|
|
45
|
+
| 변수, 함수, 파라미터 | lowerCamelCase | `userName`, `fetchData()` |
|
|
46
|
+
| 상수 | lowerCamelCase | `defaultTimeout` (UPPER_SNAKE 금지) |
|
|
47
|
+
| 파일 | snake_case | `user_profile.dart` |
|
|
48
|
+
| 라이브러리 접두사 | snake_case | `import 'x' as my_lib` |
|
|
49
|
+
|
|
50
|
+
**Incorrect:**
|
|
51
|
+
```dart
|
|
52
|
+
const MAX_RETRY_COUNT = 3; // UPPER_SNAKE
|
|
53
|
+
class user_service { } // snake_case 클래스
|
|
54
|
+
String UserName = ''; // UpperCamel 변수
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Correct:**
|
|
58
|
+
```dart
|
|
59
|
+
const maxRetryCount = 3;
|
|
60
|
+
class UserService { }
|
|
61
|
+
String userName = '';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Import 정리
|
|
65
|
+
|
|
66
|
+
```dart
|
|
67
|
+
// 1. dart: 표준 라이브러리
|
|
68
|
+
import 'dart:async';
|
|
69
|
+
import 'dart:convert';
|
|
70
|
+
|
|
71
|
+
// 2. package: 외부 패키지
|
|
72
|
+
import 'package:flutter/material.dart';
|
|
73
|
+
import 'package:riverpod/riverpod.dart';
|
|
74
|
+
|
|
75
|
+
// 3. 프로젝트 내부 (상대 경로 금지)
|
|
76
|
+
import 'package:my_app/features/auth/domain/user.dart';
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 문서화
|
|
80
|
+
|
|
81
|
+
```dart
|
|
82
|
+
/// 사용자 프로필을 가져온다.
|
|
83
|
+
///
|
|
84
|
+
/// [userId]에 해당하는 사용자가 없으면 null 반환.
|
|
85
|
+
/// 네트워크 에러 시 [FetchException] 발생.
|
|
86
|
+
Future<UserProfile?> fetchProfile(String userId) async { ... }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 규칙
|
|
90
|
+
|
|
91
|
+
- `dart format .` 자동 포매팅 (커밋 전 필수)
|
|
92
|
+
- 상대 import 금지 → `package:` import
|
|
93
|
+
- `print()` 금지 → `debugPrint()` 또는 logger
|
|
94
|
+
- `part`/`part of` 금지 → 파일 분리
|
|
95
|
+
- trailing comma 필수 (위젯 트리 가독성)
|
|
96
|
+
- `prefer_final_locals` 활성화
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Sound Null Safety
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
tags: null-safety, dart3, patterns
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Sound Null Safety
|
|
8
|
+
|
|
9
|
+
Dart의 null safety는 컴파일 타임에 null 참조를 방지한다.
|
|
10
|
+
`!`와 `late` 남용은 런타임 크래시를 초래하므로 패턴으로 해결.
|
|
11
|
+
|
|
12
|
+
### Bang Operator (!) 금지
|
|
13
|
+
|
|
14
|
+
**Incorrect:**
|
|
15
|
+
```dart
|
|
16
|
+
final user = users.firstWhere((u) => u.id == id);
|
|
17
|
+
print(user!.name); // NoSuchElementException 위험
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct:**
|
|
21
|
+
```dart
|
|
22
|
+
final user = users.where((u) => u.id == id).firstOrNull;
|
|
23
|
+
if (user case final found?) {
|
|
24
|
+
print(found.name);
|
|
25
|
+
} else {
|
|
26
|
+
throw UserNotFoundException(id);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Nullable Collection 처리
|
|
31
|
+
|
|
32
|
+
**Incorrect:**
|
|
33
|
+
```dart
|
|
34
|
+
final List<String?> items = getData();
|
|
35
|
+
for (final item in items) {
|
|
36
|
+
print(item!.length); // null이면 크래시
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Correct:**
|
|
41
|
+
```dart
|
|
42
|
+
final List<String?> items = getData();
|
|
43
|
+
final validItems = items.whereType<String>(); // null 필터링 + 타입 내로잉
|
|
44
|
+
for (final item in validItems) {
|
|
45
|
+
print(item.length); // String 보장
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### late 사용 기준
|
|
50
|
+
|
|
51
|
+
**Incorrect:**
|
|
52
|
+
```dart
|
|
53
|
+
class MyWidget extends StatefulWidget { ... }
|
|
54
|
+
class _MyWidgetState extends State<MyWidget> {
|
|
55
|
+
late final ApiService api; // dispose 전에 접근하면 크래시
|
|
56
|
+
late String userName; // 초기화 보장 없음
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Correct:**
|
|
61
|
+
```dart
|
|
62
|
+
class _MyWidgetState extends State<MyWidget> {
|
|
63
|
+
late final TextEditingController _controller; // initState에서 반드시 초기화
|
|
64
|
+
|
|
65
|
+
@override
|
|
66
|
+
void initState() {
|
|
67
|
+
super.initState();
|
|
68
|
+
_controller = TextEditingController();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@override
|
|
72
|
+
void dispose() {
|
|
73
|
+
_controller.dispose();
|
|
74
|
+
super.dispose();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 규칙
|
|
80
|
+
|
|
81
|
+
- `late` 는 lifecycle 보장 컨텍스트에서만: `initState`, `setUp`, 생성자 body
|
|
82
|
+
- `!` 대신 `case`, `??`, `?.` 사용
|
|
83
|
+
- `firstWhere` → `firstOrNull` + null 체크
|
|
84
|
+
- 함수 파라미터에서 `required` 키워드로 null 방지
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Type System (Dart 3+)
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: sealed-class, pattern-matching, records, extension-type
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Type System (Dart 3+)
|
|
8
|
+
|
|
9
|
+
Dart 3의 sealed class, 패턴 매칭, records, extension type으로 타입 안전한 코드 작성.
|
|
10
|
+
|
|
11
|
+
### Sealed Class (상태 모델링)
|
|
12
|
+
|
|
13
|
+
**Incorrect:**
|
|
14
|
+
```dart
|
|
15
|
+
enum LoadState { loading, success, error }
|
|
16
|
+
|
|
17
|
+
class ScreenState {
|
|
18
|
+
final LoadState state;
|
|
19
|
+
final List<Item>? data; // success일 때만 유효
|
|
20
|
+
final String? error; // error일 때만 유효
|
|
21
|
+
// 불가능한 조합이 가능: state=loading + data!=null
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct:**
|
|
26
|
+
```dart
|
|
27
|
+
sealed class ScreenState {}
|
|
28
|
+
class Loading extends ScreenState {}
|
|
29
|
+
class Success extends ScreenState {
|
|
30
|
+
final List<Item> data;
|
|
31
|
+
Success(this.data);
|
|
32
|
+
}
|
|
33
|
+
class Failure extends ScreenState {
|
|
34
|
+
final String message;
|
|
35
|
+
Failure(this.message);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// exhaustive switch — 새 상태 추가 시 컴파일 에러
|
|
39
|
+
Widget build(BuildContext context) => switch (state) {
|
|
40
|
+
Loading() => const CircularProgressIndicator(),
|
|
41
|
+
Success(:final data) => ItemList(items: data),
|
|
42
|
+
Failure(:final message) => ErrorView(message: message),
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 패턴 매칭
|
|
47
|
+
|
|
48
|
+
**Incorrect:**
|
|
49
|
+
```dart
|
|
50
|
+
if (response is Map<String, dynamic>) {
|
|
51
|
+
if (response.containsKey('data')) {
|
|
52
|
+
final data = response['data'];
|
|
53
|
+
if (data is List) {
|
|
54
|
+
// 중첩 if 지옥
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Correct:**
|
|
61
|
+
```dart
|
|
62
|
+
if (response case {'data': List<Map<String, dynamic>> items}) {
|
|
63
|
+
final users = items.map(User.fromJson).toList();
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Records (경량 튜플)
|
|
68
|
+
|
|
69
|
+
**Incorrect:**
|
|
70
|
+
```dart
|
|
71
|
+
// 위치 좌표를 위한 불필요한 클래스
|
|
72
|
+
class LatLng {
|
|
73
|
+
final double lat;
|
|
74
|
+
final double lng;
|
|
75
|
+
LatLng(this.lat, this.lng);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Correct:**
|
|
80
|
+
```dart
|
|
81
|
+
// Named record로 간결하게
|
|
82
|
+
typedef LatLng = ({double lat, double lng});
|
|
83
|
+
|
|
84
|
+
LatLng getLocation() => (lat: 1.3521, lng: 103.8198);
|
|
85
|
+
|
|
86
|
+
final (:lat, :lng) = getLocation(); // 구조 분해
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Extension Type (Zero-Cost Wrapper)
|
|
90
|
+
|
|
91
|
+
```dart
|
|
92
|
+
extension type UserId(String value) {
|
|
93
|
+
factory UserId.fromInt(int id) => UserId('user_$id');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
extension type PostId(String value) {}
|
|
97
|
+
|
|
98
|
+
// 컴파일 타임에 타입 구분, 런타임 오버헤드 0
|
|
99
|
+
void fetchUser(UserId id) { ... }
|
|
100
|
+
void fetchPost(PostId id) { ... }
|
|
101
|
+
|
|
102
|
+
fetchUser(PostId('abc')); // 컴파일 에러!
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 규칙
|
|
106
|
+
|
|
107
|
+
- 상태/에러/결과는 `sealed class` + exhaustive switch
|
|
108
|
+
- Map 접근은 패턴 매칭 `case` 사용
|
|
109
|
+
- 2-3개 값 반환은 Record `(int, String)` 사용 (클래스 불필요)
|
|
110
|
+
- ID 타입은 `extension type`으로 구분
|
|
111
|
+
- `dynamic` 타입 금지 → `Object?` + 패턴 매칭
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flutter
|
|
3
|
+
description: Flutter 개발 가이드라인. Feature-first 아키텍처, Riverpod 상태관리, 위젯 합성, 성능 최적화, 크로스플랫폼 적응형 UI.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
tags: [flutter, mobile, cross-platform, riverpod]
|
|
6
|
+
user-invocable: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Flutter Development Guidelines
|
|
10
|
+
|
|
11
|
+
Flutter 3.x 기반 크로스플랫폼 앱 개발 가이드라인.
|
|
12
|
+
Flutter 공식 아키텍처 가이드 + VGV + Riverpod 커뮤니티 베스트 프랙티스 종합.
|
|
13
|
+
|
|
14
|
+
## Philosophy
|
|
15
|
+
|
|
16
|
+
- 위젯은 합성 — 상속보다 조합, 작게 분리
|
|
17
|
+
- 상태는 구조화 — Riverpod로 선언적 의존성
|
|
18
|
+
- Feature-first — 기능 단위로 코드 구성
|
|
19
|
+
- const 는 습관 — 불필요한 리빌드 원천 차단
|
|
20
|
+
|
|
21
|
+
## Resources
|
|
22
|
+
|
|
23
|
+
8개 규칙 + 2개 참조. 카테고리별 배치.
|
|
24
|
+
|
|
25
|
+
| Priority | Type | Resource | Description |
|
|
26
|
+
|----------|------|----------|-------------|
|
|
27
|
+
| CRITICAL | rule | [widget-conventions](rules/widget-conventions.md) | 위젯 합성, const, Key 사용, 크기 제한 |
|
|
28
|
+
| CRITICAL | rule | [state-management](rules/state-management.md) | Riverpod Provider/Notifier 패턴 |
|
|
29
|
+
| CRITICAL | rule | [architecture](rules/architecture.md) | Feature-first + MVVM + Data/Domain/UI 레이어 |
|
|
30
|
+
| HIGH | rule | [navigation-routing](rules/navigation-routing.md) | go_router 선언적 라우팅, 딥링크 |
|
|
31
|
+
| HIGH | rule | [performance](rules/performance.md) | 리빌드 최적화, ListView.builder, Impeller |
|
|
32
|
+
| HIGH | rule | [testing](rules/testing.md) | Widget/Golden/Integration 테스트, mocktail |
|
|
33
|
+
| MEDIUM | rule | [platform-adaptive](rules/platform-adaptive.md) | 적응형 UI, 반응형 레이아웃, 플랫폼 분기 |
|
|
34
|
+
| MEDIUM | rule | [animations](rules/animations.md) | 암시적/명시적 애니메이션, Hero, 모션 가이드라인 |
|
|
35
|
+
| — | ref | [project-structure](references/project-structure.md) | Feature-first + melos 모노레포 구조 |
|
|
36
|
+
| — | ref | [freezed-patterns](references/freezed-patterns.md) | freezed + json_serializable 불변 모델 |
|
|
37
|
+
|
|
38
|
+
## Quick Rules
|
|
39
|
+
|
|
40
|
+
### 위젯
|
|
41
|
+
- `const` 생성자 적극 사용 (리빌드 스킵)
|
|
42
|
+
- 위젯 200줄 이하 — 초과 시 추출
|
|
43
|
+
- build() 안에서 로직 금지 — ViewModel/Notifier로 분리
|
|
44
|
+
- `GlobalKey` 남용 금지 — `ValueKey`/`ObjectKey` 사용
|
|
45
|
+
|
|
46
|
+
### 상태 관리 (Riverpod)
|
|
47
|
+
- UI 상태: `NotifierProvider` + `Notifier`
|
|
48
|
+
- 서버 데이터: `FutureProvider` / `StreamProvider`
|
|
49
|
+
- 파생 상태: `Provider` (computed)
|
|
50
|
+
- `ref.watch` (build), `ref.listen` (side effect), `ref.read` (이벤트 핸들러)
|
|
51
|
+
|
|
52
|
+
### 아키텍처
|
|
53
|
+
- Feature-first 구조 (`lib/features/{name}/`)
|
|
54
|
+
- 각 feature: `data/` + `domain/` + `presentation/`
|
|
55
|
+
- Repository 패턴으로 데이터 소스 추상화
|
|
56
|
+
- DTO ↔ Domain Model 변환 레이어
|
|
57
|
+
|
|
58
|
+
### 네비게이션
|
|
59
|
+
- go_router 선언적 라우팅
|
|
60
|
+
- 딥링크/유니버설 링크 지원
|
|
61
|
+
- 중첩 네비게이션 (ShellRoute)
|
|
62
|
+
|
|
63
|
+
### 성능
|
|
64
|
+
- `const` 위젯 우선
|
|
65
|
+
- 리스트는 `ListView.builder` (lazy)
|
|
66
|
+
- `RepaintBoundary`로 리빌드 범위 격리
|
|
67
|
+
- 이미지: `cached_network_image` + 적절한 크기
|
|
68
|
+
|
|
69
|
+
### 테스트
|
|
70
|
+
- Widget test: `testWidgets` + `pumpWidget`
|
|
71
|
+
- Unit test: Notifier/Repository 독립 테스트
|
|
72
|
+
- Integration test: `patrol` (네이티브 상호작용)
|
|
73
|
+
- Mock: `mocktail` (코드 생성 불필요)
|
|
74
|
+
|
|
75
|
+
## Checklist
|
|
76
|
+
|
|
77
|
+
| Priority | Item |
|
|
78
|
+
|----------|------|
|
|
79
|
+
| CRITICAL | const 생성자 사용 (lint: prefer_const_constructors) |
|
|
80
|
+
| CRITICAL | Riverpod Provider 타입 올바르게 선택 |
|
|
81
|
+
| CRITICAL | Feature-first 디렉토리 구조 |
|
|
82
|
+
| CRITICAL | build() 안에 비즈니스 로직 없음 |
|
|
83
|
+
| HIGH | ListView.builder 사용 (10+ 아이템) |
|
|
84
|
+
| HIGH | Repository 패턴 (데이터 소스 추상화) |
|
|
85
|
+
| HIGH | go_router 선언적 라우팅 |
|
|
86
|
+
| HIGH | Widget test 작성 |
|
|
87
|
+
| MEDIUM | RepaintBoundary 적용 (복잡한 서브트리) |
|
|
88
|
+
| MEDIUM | 적응형 UI (Material + Cupertino) |
|
|
89
|
+
| MEDIUM | 이미지 캐싱 + 적절한 리사이징 |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ci-cd
|
|
3
|
+
description: |
|
|
4
|
+
Flutter CI/CD 파이프라인 가이드라인.
|
|
5
|
+
코드 서명, Fastlane, Codemagic, GitHub Actions,
|
|
6
|
+
스토어 배포, 버전 관리 자동화.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
tags: [flutter, ci-cd, fastlane, codemagic, github-actions, code-signing, deployment]
|
|
9
|
+
user-invocable: false
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# CI/CD Pipeline
|
|
13
|
+
|
|
14
|
+
Flutter 앱의 빌드, 테스트, 서명, 배포 자동화 가이드.
|
|
15
|
+
iOS/Android 코드 서명, Fastlane/Codemagic/GitHub Actions 파이프라인, 스토어 배포, 버전 관리.
|
|
16
|
+
|
|
17
|
+
## Philosophy
|
|
18
|
+
|
|
19
|
+
- 배포는 자동 — 수동 빌드/업로드 금지, CI가 전부 처리
|
|
20
|
+
- 서명은 분리 — 코드 서명 키를 CI 환경에 안전하게 주입, 레포에 절대 포함 금지
|
|
21
|
+
- 버전은 규칙 — 시맨틱 버저닝 + 빌드 넘버 자동 증가
|
|
22
|
+
- 환경은 격리 — dev/staging/prod 설정 분리, 환경별 독립 파이프라인
|
|
23
|
+
|
|
24
|
+
## Resources
|
|
25
|
+
|
|
26
|
+
6개 규칙 + 1개 참조. CI/CD 파이프라인 전체를 커버.
|
|
27
|
+
|
|
28
|
+
| Priority | Type | Resource | Description |
|
|
29
|
+
|----------|------|----------|-------------|
|
|
30
|
+
| CRITICAL | rule | [code-signing](rules/code-signing.md) | iOS provisioning profile, Android keystore, 인증서 관리 |
|
|
31
|
+
| HIGH | rule | [fastlane-setup](rules/fastlane-setup.md) | Fastfile 구성, match, supply, deliver, .env 관리 |
|
|
32
|
+
| HIGH | rule | [codemagic-setup](rules/codemagic-setup.md) | codemagic.yaml 워크플로우, 환경변수, 빌드 트리거 |
|
|
33
|
+
| HIGH | rule | [github-actions](rules/github-actions.md) | Flutter 빌드 워크플로우, 테스트-빌드-업로드 파이프라인 |
|
|
34
|
+
| HIGH | rule | [store-deployment](rules/store-deployment.md) | TestFlight, Play Store tracks, 메타데이터, 단계적 출시 |
|
|
35
|
+
| MEDIUM | rule | [versioning](rules/versioning.md) | 시맨틱 버저닝, 빌드 넘버 자동 증가, CHANGELOG, git 태그 |
|
|
36
|
+
| — | ref | [ci-cd-pipeline](references/ci-cd-pipeline.md) | 파이프라인 아키텍처, 환경 설정, 시크릿 관리, 롤백 |
|
|
37
|
+
|
|
38
|
+
## Quick Rules
|
|
39
|
+
|
|
40
|
+
### 코드 서명
|
|
41
|
+
- iOS: `match` 로 인증서/프로필 Git 저장소 관리 (팀 공유)
|
|
42
|
+
- Android: keystore 파일을 CI 환경변수로 base64 주입
|
|
43
|
+
- 개발용/배포용 인증서 분리 — 동일 인증서 사용 금지
|
|
44
|
+
- 서명 키를 레포에 커밋 금지 — `.gitignore` 에 `*.keystore`, `*.jks`, `*.p12` 추가
|
|
45
|
+
|
|
46
|
+
### Fastlane
|
|
47
|
+
- `Fastfile` 에 `ios`/`android` 레인 분리
|
|
48
|
+
- `match` → iOS 인증서 자동 관리 (Git 저장소 or Google Cloud Storage)
|
|
49
|
+
- `supply` → Google Play 업로드, `deliver` → App Store 업로드
|
|
50
|
+
- `.env` 로 환경별 설정 분리 (`.env.production`, `.env.staging`)
|
|
51
|
+
|
|
52
|
+
### CI/CD 플랫폼
|
|
53
|
+
- Codemagic: Flutter 네이티브 지원, `codemagic.yaml` 로 워크플로우 정의
|
|
54
|
+
- GitHub Actions: `subosito/flutter-action` 으로 Flutter 설치, pub cache 캐시 필수
|
|
55
|
+
- 빌드 트리거: 태그 푸시 (`v*`) → 릴리스, PR → 테스트만
|
|
56
|
+
|
|
57
|
+
### 스토어 배포
|
|
58
|
+
- TestFlight: `deliver` 또는 `app-store-connect` API로 업로드
|
|
59
|
+
- Play Store: internal → closed → open → production 트랙 순서
|
|
60
|
+
- 단계적 출시 (staged rollout): 1% → 5% → 20% → 50% → 100%
|
|
61
|
+
- 메타데이터 (스크린샷, 설명) 코드로 관리 (`fastlane/metadata/`)
|
|
62
|
+
|
|
63
|
+
### 버전 관리
|
|
64
|
+
- `pubspec.yaml`: `version: major.minor.patch+buildNumber`
|
|
65
|
+
- 빌드 넘버: CI에서 자동 증가 (`--build-number=$CI_BUILD_NUMBER`)
|
|
66
|
+
- git 태그: `v1.2.3` 형식, 릴리스 빌드와 1:1 매핑
|
|
67
|
+
|
|
68
|
+
## Checklist
|
|
69
|
+
|
|
70
|
+
| Priority | Item |
|
|
71
|
+
|----------|------|
|
|
72
|
+
| CRITICAL | iOS 코드 서명 (provisioning profile + 인증서) CI에 구성 |
|
|
73
|
+
| CRITICAL | Android keystore CI 환경변수로 안전하게 주입 |
|
|
74
|
+
| CRITICAL | 서명 키/인증서 `.gitignore` 에 추가 확인 |
|
|
75
|
+
| CRITICAL | CI 파이프라인: test → build → deploy 순서 보장 |
|
|
76
|
+
| HIGH | Fastlane match 설정 (iOS 인증서 팀 공유) |
|
|
77
|
+
| HIGH | 환경별 (dev/staging/prod) 빌드 설정 분리 |
|
|
78
|
+
| HIGH | 스토어 업로드 자동화 (TestFlight + Play Store) |
|
|
79
|
+
| HIGH | 빌드 넘버 자동 증가 전략 구현 |
|
|
80
|
+
| MEDIUM | CHANGELOG 자동 생성 (conventional commits 기반) |
|
|
81
|
+
| MEDIUM | 슬랙/디스코드 배포 알림 설정 |
|
|
82
|
+
| MEDIUM | 롤백 절차 문서화 및 테스트 |
|