LogoSkills

presentation-layer-agent

Clean Architecture 프레젠테이션 레이어 전문가입니다. BLoC, Page, Widget, Route 작업에 사용합니다.

/cc-flutter:feature:presentation — 화면(UI) 만들어주는 일꾼#

항목내용
실행 명령/cc-flutter:feature:presentation
별칭/presentation:create, /layer:presentation
모델sonnet
사용 도구 Read, Edit, Write, Glob, Grep
연계 스킬feature

한마디로#

앱에서 사용자 눈에 보이는 화면 부분을 정해진 규칙대로 자동으로 만들어주는 전담 일꾼입니다. 집으로 치면 골조·배관(데이터)이 아니라 눈에 보이는 인테리어와 스위치(화면·버튼) 를 표준 자재로 똑같이 시공해 주는 역할이에요.

누가·언제 쓰나요#

  • 새 기능의 화면(페이지)과 버튼·카드 같은 위젯을 만들어야 할 때
  • 화면 상태 관리(BLoC)와 화면 전환(Route)을 일관된 방식으로 깔고 싶을 때
  • 전체 기능 자동 생성(/cc-flutter:feature:create)의 마지막 5단계로 자동 호출될 때

무엇을 해주나요#

기능 이름 하나만 주면, 화면 관련 파일 묶음을 한 번에 만들어 줍니다. 실제로 생기는 것:

  • 상태 관리 코드(BLoC){feature}_list_bloc.dart, ..._event.dart, ..._state.dart
  • 화면(Page){feature}_page.dart
  • 위젯(부품){entity}_card.dart
  • 화면 전환(Route){feature}_route.dart
  • 테스트 + Widgetbook — 화면이 제대로 동작하는지 확인하는 자동 검사 파일

이 모든 것이 회사 표준 패턴(BLoC, Clean Architecture 규칙)에 맞춰 일관되게 생성됩니다.

어떻게 쓰나요#

# 기본: 기능 이름과 엔티티 이름을 넘깁니다
/cc-flutter:feature:presentation

# 별칭으로도 호출 가능
/presentation:create
/layer:presentation

넘길 수 있는 값:

  • feature_name (필수) — 기능 모듈 이름 (snake_case 예: user_list)
  • entity_name (필수) — 엔티티 이름 (PascalCase 예: User)
  • location (선택) — application(기본) / common / console 중 어디에 만들지
  • pages (선택) — 만들 페이지 목록

안에서 무슨 일이 벌어지나요#

  1. 상태 관리(BLoC) 생성 — 화면이 가질 수 있는 사건(Event)과 상태(State)를 표준 형태로 만들고, 비동기 처리 후 안전 점검(isClosed)을 넣습니다.
  2. 화면·위젯 생성 — 페이지를 BlocSignalProvider로 감싸고, 카드 같은 부품 위젯을 정해진 규칙으로 만듭니다.
  3. 화면 전환(Route) 생성@TypedGoRoute 방식으로 화면 이동 경로를 정의합니다.
  4. 금지 패턴 차단 — 옛날 방식(Key? key)이나 상대경로 import, BLoC이 데이터 저장소에 직접 손대는 잘못된 구조를 막습니다.
  5. 자체 점검(체크리스트) + 테스트 — 만든 결과가 규칙에 맞는지 항목별로 확인하고 테스트 코드까지 작성합니다.

⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)

Role#

Consistently generates BLoC (Event sealed class, State), Page/Widget, Route, tests, and Widgetbook.


Activation Conditions#

  • /cc-flutter:feature:presentation Activated when command is invoked
  • Invoked from /cc-flutter:feature:create orchestration Step 5

Parameters#

ParameterRequiredDescription
feature_nameFeature module name (snake_case)
entity_nameEntity name (PascalCase)
locationapplication, common, console (default: application)
pagesTo generate Page List

Generated Files#

feature/{location}/{feature_name}/lib/src/presentation/
├── bloc/
│   └── {feature}_list/
│       ├── {feature}_list_bloc.dart
│       ├── {feature}_list_event.dart
│       └── {feature}_list_state.dart
├── page/
│   └── {feature}_page.dart
├── widget/
│   └── {entity}_card.dart
└── route/
    └── {feature}_route.dart

# Tests 파일
feature/{location}/{feature_name}/test/presentation/
├── bloc/{feature}_list_bloc_test.dart
└── page/{feature}_page_test.dart

Core Patterns Summary#

BLoC Event/State#

📚 Details: BLoC Pattern

  • Event: sealed class + factory constructor + private Implementation
  • State: sealed class or Freezed union type
  • isClosed Check: Required after await, before emit!

UseCase Integration Pattern#

📚 Details: UseCase Pattern

PatternDescription
Optional Constructor Injection✅ Standard pattern - Direct creation/Test without getIt

Widget Generation Rules#

const MyWidget({
  required this.data,
  this.onTap,
  super.key,  // ✅ Always last
});

Route Pattern#

@TypedGoRoute<FeatureRoute>(path: '/feature')
class FeatureRoute extends GoRouteData { ... }

Prohibited Patterns#

// ❌ Key? key 패턴 금지 (super.key 사용)
const MyWidget({Key? key, required this.data}) : super(key: key);

// ❌ Relative path import prohibited
import '../domain/entity/user.dart';

// ❌ BLoC에서 Repository 직접 접근 금지 (UseCase 통해서만)
class MyBloc {
  final IRepository _repository;  // UseCase 우회!
}

Checklist#

Common (Required)#

  • Event: sealed class + factory + private implementation pattern
  • State: sealed class or Freezed union
  • BLoC: if (isClosed) return; Check (await After Required)
  • Page: BlocSignalProvider wrapping
  • Widget: super.key last position
  • Route: @TypedGoRoute annotation
  • package import only (relative path prohibited)

Tests#

  • BLoC Test Writing
  • Widget Test Writing
  • Widgetbook UseCase Writing

UseCase Patterns#

  • Optional Constructor Injection: Bloc(useCase: mockUseCase) Direct injection Test