cob compose#
매니페스트 v1(feature.yaml) 선언 한 장으로 풀스택 feature 골격을 1회(one-shot) 생성합니다.
cob compose --manifest feature.yaml
cob compose -m feature.yaml -d ../my_project --force
실행 흐름:
- 매니페스트 v1(
feature.yaml) 파싱·검증 (실패 시 hard fail) - atomic brick(usecase/bloc/widget/entity/repository/b-entity) N회 generate
- 배치 규칙에 따라 단일 feature 패키지(
feature/{target}/{feature})로 병합 - barrel(usecase/entity/bloc/widget) 재생성 — atomic brick은 자기 파일만 생성하므로 barrel은 cob 책임
- 라우터 마커 기반으로 라우트 등록 + workspace pubspec 갱신
백엔드는 backend_feature 브릭 1회 + (entities 선언 시) b-entity N회 generate로 backend/{project_name}_server에 합성됩니다. 기존 feature에 부품을 추가하려면
cob compose가 아닌 cob add를 사용하세요.
옵션#
| 옵션 | 약어 | 설명 | 기본값 |
|---|---|---|---|
--manifest |
-m |
feature 매니페스트 파일 경로 | feature.yaml |
--project-dir | -d | 대상 프로젝트 디렉토리 | 현재 디렉토리 |
--bricks-dir |
-b |
bricks/ 디렉토리 경로 |
자동 탐지 (상위 디렉토리 순회) |
--force | - | git-clean 가드 우회 (one-shot 가드는 우회 불가) | false |
실행 전 가드 4종#
compose는 파일을 하나라도 만들기 전에 아래 가드를 순서대로 검사합니다. 하나라도 실패하면 즉시 종료하고 아무것도 생성하지 않습니다.
1. one-shot 가드#
대상 feature 디렉토리(feature/{target}/{feature} 또는 백엔드 lib/src/feature/{feature})가
하나라도 이미 존재하면 hard fail합니다.
❌ 대상 feature가 이미 존재합니다 (compose는 1회용):
• feature/application/notice_board
기존 feature에 부품을 추가하려면 cob add를 사용하세요. 예:
cob add usecase <name> --feature notice_board
--force로도 우회할 수 없습니다. compose는 빈 슬레이트 전제의 1회용 명령입니다.
2. git-clean 가드#
git status --porcelain으로 작업트리를 검사합니다. 더러우면 거부하고 커밋/스태시를 안내합니다 (변경 목록 최대 10줄 표시).
❌ git 작업트리가 깨끗하지 않습니다. compose 실패 시 복구를 위해
커밋/스태시 후 다시 실행하세요 (--force로 우회 가능).
--force로 우회 가능 (경고 출력 후 계속)- git 저장소가 아니면 차단하지 않고 "실패 시 자동 복구 수단이 없습니다" 경고만 출력
3. 라우터 마커 pre-flight#
target별 라우트 파일(application → app_routes.dart, console → console_routes.dart)을 찾고, 라우트 배열 안에 AUTO-REGISTER 마커가 있는지 생성 전에 확인합니다. 파일이 없거나 마커가 없으면 실패합니다.
// 🔧 AUTO-REGISTER: 새 라우트를 여기에 추가하세요
마커가 없으면 위 마커를 라우트 배열 안에 추가한 뒤 다시 실행하라고 안내합니다. 합성 성공 후에는 이 마커 위치에 {Feature}RouteName.base
라우트가 자동 등록됩니다.
4. 백엔드 모델 pre-flight#
serverpod 모델명(class/enum/exception)은 서버 전역 네임스페이스를 공유하므로, serverpod generate
단계까지 가지 않고 생성 전에 충돌을 4가지로 검사합니다. 백엔드 서버 디렉토리가 없으면 (백엔드 합성 자체가 스킵되므로) 이 검사도 스킵됩니다.
| # | 검사 | 실패 메시지 요지 | 해결 안내 |
|---|---|---|---|
| 4-a | 내부 중복 — 생성 예정 모델명이 매니페스트 안에서 서로 겹침 (entities ↔ backend_feature placeholder/enum/dto) | 생성 예정 serverpod 모델명이 매니페스트 안에서 중복됩니다 + 충돌 쌍 목록 |
entity 이름 변경, 또는 겹치는 backend: 토글(entity/enum/dto) 끄기 |
| 4-b | 기존 spy 충돌 — 생성 예정 모델명이 서버의 기존 .spy.yaml/protocol 모델과 겹침 |
serverpod 모델명이 기존 spy 모델과 충돌합니다 (전역 네임스페이스) + 기존/생성 예정 출처 |
entities가 출처면 이름 변경·선언 제거(기존 모델 재사용), backend_feature가 출처면 해당 토글 끄기 또는 feature 이름 변경 |
| 4-c |
동명 엔티티 계약
— endpoint/service/dto 골격은 feature 동명 protocol 클래스(
{Feature}
)를 참조하는데 어디서도 공급되지 않음
|
endpoint/service/dto 골격은 feature 동명 엔티티({Feature})를 참조하지만 어디서도 공급되지 않습니다 |
models.entities
에 동명 엔티티 추가,
backend.entity: true
(placeholder 생성), 또는 endpoint/console_endpoint/service/dto 토글 전부 끄기
|
| 4-d |
placeholder → enum 역계약
— entity placeholder 템플릿이
status: {Feature}Status?
를 하드 참조하는데 enum 토글이 꺼져 있고 기존 모델에도 없음
|
entity placeholder는 {Feature}Status enum을 참조하지만 enum 토글이 꺼져 있고 기존 모델에도 없습니다 |
backend.enum: true로 되돌리거나, placeholder 대신 models.entities에 직접 선언 |
생성 후 수동 단계#
cob은 codegen을 자동 실행하지 않습니다. 합성 완료 후 출력되는 가이드를 따라 직접 실행하세요.
cd backend/{project_name}_server && serverpod generate # 1. serverpod 산출물
melos run build # 2. build_runner 산출물
melos run analyze # 3. 검증
추가 수동 작업:
-
serverpod_service getter 스니펫:
network: serverpod이면 클라이언트 래퍼 getter를 출력해 줍니다. getter가 2계열이라 자동 추가하지 않으므로package/network/serverpod_service에 직접 붙여넣으세요.
// package/network/serverpod_service의 클라이언트 래퍼에 추가:
EndpointNoticeBoard get noticeBoard => client.noticeBoard;
-
BLoC 와이어링: 생성자 주입 전용입니다 (getIt/injectable 미사용, service_locator 등록 없음). 출력되는
BlocProvider예시를 참고해 직접 연결하세요.
매니페스트 스키마#
feature.yaml(v1) 필드 상세는 Feature 매니페스트 레퍼런스를 참고하세요.
예시#
최소 매니페스트:
# feature.yaml
feature: notice_board
project_name: cocode
targets: [application]
network: serverpod
frontend:
usecases: [get_notices, create_notice]
blocs:
- { name: notice_list, usecases: [get_notices] }
widgets: [notice_list_tile]
models:
entities:
- { name: notice, fields: { title: String, content: String } }
backend:
cache: false
console_endpoint: false
실행:
# 프로젝트 루트에서 (feature.yaml이 프로젝트 루트에 있을 때)
cob compose
# 매니페스트·프로젝트 경로 지정
cob compose -m feature.yaml -d template/cocode
# 작업트리가 더럽지만 강행 (one-shot 가드는 여전히 적용)
cob compose -m feature.yaml --force