| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| Invoke | /app:route |
| Aliases | /route:create, /nav:setup |
| Tools | Read, Edit, Write, Glob, Grep |
| Model | sonnet |
| Skills | flutter-ui |
/app:route โ ํ๋ฉด ๊ธธ ์๋ด(๋ผ์ฐํธ) ์๋ ์์ฑ๊ธฐ#
ํ๋ง๋๋ก#
์ฑ์ ํ๋ฉด๊ณผ ํ๋ฉด์ ์๋ "๊ธธ ์๋ด ์ง๋"๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด ์ฃผ๋ ๋๊ตฌ์ ๋๋ค. ๊ฑด๋ฌผ์ ์ ๋ฐฉ์ ๋ง๋ค๋ฉด "์ด ๋ฐฉ์ผ๋ก ๊ฐ๋ ค๋ฉด ๋ช ์ธต ๋ช ํธ" ํ๋ ์ฃผ์์ ์ด๋ ํต๋ก๊ฐ ํ์ํ๋ฏ, ์ ํ๋ฉด์ ์ถ๊ฐํ ๋ ๊ทธ ํ๋ฉด์ผ๋ก ๊ฐ๋ ์ฃผ์(๊ฒฝ๋ก)์ ์ด๋ ๋ฐฉ์(์ ํ ํจ๊ณผ)์ ์ฝ๋๋ก ๋ง๋ค์ด ์ค๋๋ค.
๋๊ฐยท์ธ์ ์ฐ๋์#
- ์ฑ์ ์ ํ๋ฉด์ ์ถ๊ฐํ๊ณ ๊ทธ ํ๋ฉด์ผ๋ก ์ด๋ํ๋ ๊ธธ์ ์ฐ๊ฒฐํด์ผ ํ๋ ๊ฐ๋ฐ์
/app:route๋ช ๋ น์ ์ง์ ์คํํ ๋- ํฐ ๊ธฐ๋ฅ์ ํ ๋ฒ์ ๋ง๋๋
/feature:create์์ ์ด ์งํ๋๋ ์ค, ํ๋ฉด(Presentation) ๋จ๊ณ์์ ์๋์ผ๋ก ํธ์ถ๋ ๋
๋ฌด์์ ํด์ฃผ๋์#
feature/{์ฑ์ข
๋ฅ}/{๊ธฐ๋ฅ์ด๋ฆ}/lib/src/route/ ํด๋ ์๋์ ํ๋ฉด ๊ธธ ์๋ด ํ์ผ 3๊ฐ๋ฅผ ๋ง๋ค์ด ์ค๋๋ค.
route.dartโ ๋ฌถ์(๋ด๋ณด๋ด๊ธฐ) ํ์ผ{๊ธฐ๋ฅ์ด๋ฆ}_route.dartโ ์ค์ ๊ธธ(๊ฒฝ๋ก) ์ ์{๊ธฐ๋ฅ์ด๋ฆ}_route.g.dartโ ์๋ ์์ฑ๋๋ ํ์ผ(build_runner๊ฐ ๋ง๋ฆ)
์ฌ๊ธฐ์๋ ํ๋ฉด ์ฃผ์(์: /store), ์์ธ ํ๋ฉด ์ฃผ์(์: /store/3), ํ๋ฉด์ด ๋ฐ๋ ๋์ ์ ํ ํจ๊ณผ(์์ํ๊ฒ ๋ฐ๋ยท์์์ ๋ฐ๋ ค์ดยทํจ๊ณผ ์์) ๋ฑ์ด ๋ด๊น๋๋ค.
์ด๋ป๊ฒ ์ฐ๋์#
# ๊ธฐ๋ณธ ์ฌ์ฉ (๊ธฐ๋ฅ ์ด๋ฆ๋ง ์ง์ )
/app:route # feature_name ์ง์ (snake_case, ์: store)
# ๋ณ์นญ(๊ฐ์ ๊ธฐ๋ฅ)
/route:create
/nav:setup
์ง์ ํ ์ ์๋ ๊ฐ(ํ๋ผ๋ฏธํฐ):
feature_name(ํ์) โ ๊ธฐ๋ฅ ๋ชจ๋ ์ด๋ฆ(snake_case)route_type(์ ํ) โapp๋๋console(๊ธฐ๋ณธ๊ฐapp)-
transition(์ ํ) โ ํ๋ฉด ์ ํ ํจ๊ณผfade(์์ํ๊ฒ) /slide(๋ฐ๋ ค์ด) /none(ํจ๊ณผ ์์) (๊ธฐ๋ณธ๊ฐfade) nested_routes(์ ํ) โ ํ๋ฉด ์์ ํ์ ํ๋ฉด ๋ชฉ๋ก
์์์ ๋ฌด์จ ์ผ์ด ๋ฒ์ด์ง๋์#
- ํ๋ฉด ์ฃผ์ํ(
TypedGoRoute)๋ฅผ ๋ถ์ฌ ๊ฐ ํ๋ฉด์ด ์ด๋ค ์ฃผ์๋ก ์ด๋ฆฌ๋์ง ์ ์ํฉ๋๋ค. - ์ผ๋ฐ ์ฑ ํ๋ฉด, ์ด๋๋ฏผ ์ฝ์ ํ๋ฉด, ์์ธ(ํ์) ํ๋ฉด ๋ฑ ์ํฉ์ ๋ง๋ ๊ธธ ์ ์ ์ฝ๋๋ฅผ ๊ณจ๋ผ ๋ง๋ค์ด ์ค๋๋ค.
- ํ๋ฉด ์ ํ ํจ๊ณผ(์์ํ๊ฒ/๋ฐ๋ ค์ด/ํจ๊ณผ ์์)๋ฅผ ์ํฉ์ ๋ง๊ฒ ์ ํํฉ๋๋ค.
- ๊ฐ์ ํ๋ฉด์ด ์ค๋ณต๋์ง ์๊ณ ์ฌ๋ฐ๋ฅด๊ฒ ๋ค์ ๊ทธ๋ ค์ง๋๋ก ํ๋ฉด๋ง๋ค ๊ณ ์ ํ ์๋ณ ํค๋ฅผ ์์ฑํฉ๋๋ค.
- ์ฃผ์์ ๋ธ๋ ค ์ค๋ ์ถ๊ฐ ์ ๋ณด(์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ, ์: ๊ฒ์์ดยทํํฐ)๋ฅผ ์ฝ์ด ์ฒ๋ฆฌํฉ๋๋ค.
- ๋ง์ง๋ง์ผ๋ก ์๋ ์์ฑ ํ์ผ์ ์ฐ๊ฒฐํ๊ณ ,
melos run build(build_runner)๋ฅผ ์คํํด ๋๋จธ์ง ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
โ๏ธ ์์ธ ์ต์ ยท์คํ ๋ช ์ธ (๊ฐ๋ฐ์ / AI ์์ด์ ํธ์ฉ)
Role#
Generates GoRouter-based TypedRoute configuration.
- TypedGoRoute annotation definition
- GoRouteData class implementation
- RouteName abstract class pattern
- Transition page configuration
- Nested route structure
Activation Conditions#
/app:routeActivated when command is invoked- Called after
/feature:createorchestration Presentation Phase
Parameters#
| Parameter | Required | Description |
|---|---|---|
feature_name | โ | Feature module name (snake_case) |
route_type | โ | app, console (default: app) |
transition | โ | fade, slide, none (default: fade) |
nested_routes | โ | Nested Route List |
Generated Files#
feature/{app_type}/{feature_name}/lib/src/route/
โโโ route.dart # Export ํ์ผ
โโโ {feature_name}_route.dart # ๋ผ์ฐํธ ์ ์
โโโ {feature_name}_route.g.dart # ์๋ ์์ฑ (build_runner)Import Order (Required)#
// 1. Feature package (page import)
import 'package:{feature_name}/{feature_name}.dart';
// 2. Dependency packages
import 'package:dependencies/dependencies.dart';
// 3. Core (transition pages)
import 'package:core/core.dart';
// 4. Generated files
part '{feature_name}_route.g.dart';
Core Patterns#
1. App Route Definition (FadeTransitionPage)#
part '{feature_name}_route.g.dart';
/// {Feature} ํ๋ฉด ๋ผ์ฐํธ ์ ์
///
/// ์ฑ์ {feature} ํ๋ฉด์ผ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
/// ์ ๋๋ฉ์ด์
ํจ๊ณผ๋ก [FadeTransitionPage]๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@TypedGoRoute<{Feature}Route>(
path: {Feature}RouteName.path,
routes: [
// in progress์ฒฉ ๋ผ์ฐํธ ์ ์
TypedGoRoute<{Feature}DetailRoute>(
path: {Feature}DetailRoute.path,
),
],
)
class {Feature}Route extends GoRouteData with ${Feature}Route {
/// {Feature} ํ๋ฉด ๋ผ์ฐํธ ์์ฑ์
const {Feature}Route({this.initialId});
/// ์ด๊ธฐ ID (์ ํ์ฌํญ)
final int? initialId;
/// {Feature} ํ๋ฉด ๋ผ์ฐํธ ๊ฒฝ๋ก
static const String path = {Feature}RouteName.path;
static const LocalKey _key = ValueKey(path);
@override
FadeTransitionPage buildPage(BuildContext context, GoRouterState state) {
return FadeTransitionPage(
key: _key,
child: {Feature}Page(initialId: initialId),
);
}
}
2. Console Route Definition (NoTransitionPage)#
/// Console {Feature} ํ๋ฉด ๋ผ์ฐํธ ์ ์
///
/// ์ด๋๋ฏผ ์ฝ์์ {feature} ํ๋ฉด์ผ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
/// ํธ๋์ง์
์์ด [NoTransitionPage]๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@TypedGoRoute<Console{Feature}Route>(
path: Console{Feature}RouteName.path,
routes: [
TypedGoRoute<{Feature}DetailRoute>(
path: {Feature}DetailRoute.path,
),
],
)
class Console{Feature}Route extends GoRouteData with $Console{Feature}Route {
/// Console{Feature} ํ๋ฉด ๋ผ์ฐํธ ์์ฑ์
const Console{Feature}Route();
/// Console{Feature} default ๊ฒฝ๋ก
static RouteBase get base => Console{Feature}RouteName.base;
@override
Page<void> buildPage(BuildContext context, GoRouterState state) {
// ๐ ๋์ key ์์ฑ (์ฟผ๋ฆฌ ๋ณํ์ ๋ฐ๋ผ ํ์ด์ง ์ฌ์์ฑ)
final query = state.uri.query;
final pageKey = ValueKey(
'console_{feature}_list-${query.isNotEmpty ? query : 'noq'}',
);
return NoTransitionPage<void>(
key: pageKey,
child: const Console{Feature}Page(),
);
}
}
3. RouteName Abstract Class Pattern#
/// {Feature} ๋ผ์ฐํธ ๊ฒฝ๋ก ์ด๋ฆ์ ์ ์ํ๋ ์ถ์ ํด๋์ค
///
/// [path]๋ '/{feature}'๋ก ์ค์ ๋์ด {feature} ํ๋ฉด์ ๊ฒฝ๋ก๋ก ์ฌ์ฉ๋ฉ๋๋ค.
abstract class {Feature}RouteName {
/// {Feature} ํ๋ฉด ๋ผ์ฐํธ ๋ฒ ์ด์ค
static RouteBase get base => ${featureCamel}Route;
/// {Feature} ํ๋ฉด ๋ผ์ฐํธ ๊ฒฝ๋ก
static const String path = '/{feature}';
/// {Feature} ํ๋ฉด ๋ผ์ฐํธ ์ด๋ฆ
static const String name = '{feature}';
}
4. Nested Route Definition#
/// {Feature} ์์ธ ํ๋ฉด ๋ผ์ฐํธ ์ ์
///
/// ์ค์ ๊ฒฝ๋ก๋ '/{feature}/{id}'๊ฐ ๋ฉ๋๋ค.
@immutable
class {Feature}DetailRoute extends GoRouteData with ${Feature}DetailRoute {
/// {Feature} ์์ธ ํ๋ฉด ๋ผ์ฐํธ ์์ฑ์
const {Feature}DetailRoute({required this.id});
/// ์กฐํํ {feature}์ ID
final int id;
/// {Feature} ์์ธ ํ๋ฉด ๋ผ์ฐํธ ๊ฒฝ๋ก
static const String path = ':id';
@override
FadeTransitionPage buildPage(BuildContext context, GoRouterState state) {
// id์ ์ ์ฒด ์ฟผ๋ฆฌ ๋ฌธ์์ด์ ํฌํจํ์ฌ ๊ณ ์ ํ ํค ์์ฑ
final fullPath = state.uri.toString();
final pageKey = ValueKey('{feature}Detail/$fullPath');
return FadeTransitionPage(
key: pageKey,
child: {Feature}DetailPage(id: id),
);
}
}
5. Query Parameter Parsing Helpers#
/// ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ์์ ์ ์ ๊ฐ์ ํ์ฑํ๋ ํฌํผ ํจ์
int? _parseIntQueryParam(String? value) {
return value != null ? int.tryParse(value) : null;
}
/// ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ์์ ๋ถ๋ฆฌ์ธ ๊ฐ์ ํ์ฑํ๋ ํฌํผ ํจ์
bool _parseBoolQueryParam(String? value) {
return value?.toLowerCase() == 'true';
}
6. Route Constants Definition#
/// ๋ผ์ฐํธ ์์ ์ ์ (private)
abstract class _RouteConstants {
/// Detail ๋ผ์ฐํธ ์๋ณ์
static const String detail = 'detail';
/// ํธ์ง ๋ผ์ฐํธ ์๋ณ์
static const String edit = 'edit';
/// ์ถ๊ฐ ๋ผ์ฐํธ ์๋ณ์
static const String add = 'add';
}
Transition Page Types#
| Type | Class | Where Used |
|---|---|---|
| Fade | FadeTransitionPage | App general screens |
| Slide | SlideTransitionPage | Modal, detail screens |
| None | NoTransitionPage | Console, tab switching |
Reference Files#
feature/application/store/lib/src/route/store_route.dart
feature/console/console_member_list/lib/src/route/console_member_list_route.dart
feature/application/app_router/lib/src/route/app_routes.dart
package/core/lib/src/transition/Checklist#
- TypedGoRoute Annotation Definition
- GoRouteData extends + mixin Apply
- Define RouteName abstract Class
- Select appropriate transition Page
- Generate unique ValueKey
- Handle query parameters
- Write KDoc comments
- Connect .g.dart via part directive
- build_runner Execution (
melos run build)