직원 셸의 자리 — 앱과 콘솔이 같은 셸을 쓴다 (R2)
결정: 공용 직원 셸은
feature/clinic/app_shell(패키지clinic_shell)에 한 번 짓고, 앱(clinic)과 콘솔 (R3 의console_clinic)이 둘 다 의존한다. 한정 역할(qualified role) 슬롯이며 새 계층 규칙이 필요 없다.
왜 공용 셸인가
Figma 56프레임은 모두 같은 틀이다 — 데스크톱은 사이드바 240(7항목) + 상단 막대 64, 태블릿은 아이콘 레일 80(5항목),
폰은 앱 바 + 하단 탭 4(홈 · 대기 · 환자 · 알림). 「약관 · 정책」(HP-1315)과 「버그 · 개선」(HP-1923)처럼
관리자급 화면도 같은 사이드바의 「설정」 안에 있다(surface-split.md 근거 E1~E9).
앱 호스트(app/app)와 콘솔 호스트(app/console)를 따로 두더라도 화면 틀은 하나다 — 두 번 지으면 사이드바
항목 · 레일 라벨 · 탭 4개가 한쪽만 바뀌는 순간 어긋난다.
비교한 안
| 안 | 자리 | 막히는 곳 |
|---|---|---|
| A | package/<x> 공용 패키지 |
dependency_layers.json 에 새 규칙 행이 필요하다(없으면 게이트가 「분류되지 않은 워크스페이스 패키지」로 실패). package/* 는 「모듈 공용 계약」(core · resources …)의 자리인데 직원 셸은 기능 소유 UI 다. 번들 도구(feature_modules 검사 · 코드 생성 · 역할별 시험)의 밖이라 번역 · 시험 게이트가 따로 필요하다 |
| B | 셸을 feature/clinic/app(clinic)에 두고 console_clinic 이 clinic 에 의존 |
콘솔 호스트가 앱 패키지 전체(도메인 · DI 등록 · 앱 라우트)를 끌고 들어온다. 역할 패키지가 자기 몫만 갖는다는 S-19 번들 배치에 어긋나고, 콘솔 → 앱 방향 의존이 굳는다 |
| C | 앱 · 콘솔 패키지에 셸을 각각 둔다(shop · class 의 관리자 셸 방식) | 같은 틀을 두 벌 유지한다 — 위의 어긋남 위험 그대로. shop · class 는 앱 셸과 관리자 셸이 다른 화면 틀이라 두 벌이 맞지만 여기는 같은 틀이다 |
| D (채택) | feature/clinic/app_shell — 한정 역할 슬롯 |
아래 |
채택한 안의 근거 (저장소 사실)
- 한정 역할은 번들 도구가 이미 지원한다.
tool/feature_modules.py의QUALIFIED_ROLE = (app|console)_<name>— 기본 패키지 이름은<기능>_<이름>(여기서는clinic_shell), 기본 역할(app)이 있어야 하고 디렉터리는 형제 (feature/clinic/app_shell)여야 한다.bundle.json의packages에"app_shell": "app_shell"한 줄로 선언한다(feature_modules check가 경로 · 이름 · 워크스페이스 · 역할을 검사한다). - 계층 규칙이 이미 있다.
dependency_layers.json의{"path": "feature/*/app_*", "inheritsRole": "app"}가app_shell을 계층 5 · flutter 로 분류한다 — 새 규칙 행 없이python3 tool/gates/check_package_layers.py가upwardEdges 0 · runtimeViolations 0 · cyclicPackages 0으로 통과한다(실측).clinic → clinic_shell은 5→5 같은 계층 간선이고 DAG 라 허용된다. R3 의console_clinic → clinic_shell도 5→5 · flutter→flutter 라 같다. - 모듈은 호스트를 import 하지 않는다(S-19). 셸은 라우터 · 세션 · 데이터를 모른다 — 호스트의 라우트가 지금
목적지와 이동 콜백을 넘기고, 이름 · 호칭 · 소속은 호스트가 지금 언어로 만든 글자(
StaffProfile·brandCaption)를 넘긴다. 호스트 import · 앱 라우트 import 가 없다.
경계
clinic_shell 이 가진 것: 배치 단계(폭 768 · 1280 — StaffFormFactor) · 목적지 모델 8개(사이드바 7 · 레일 5 ·
폰 탭 4 — StaffDestination) · 사이드바 · 레일 · 하단 탭 · 상단 막대 · 화면 머리 틀(StaffPageFrame) · 프로필 ·
로고 · 자기 번역 카탈로그(내비게이션 라벨 11개 로케일) · 스케일 불변 · 언어별 넘침 시험.
가지지 않는 것: 라우트(@TypedStatefulShellRoute 는 호스트별 — 앱은 clinic 의 StaffShellRoute, 콘솔은 R3 에서
같은 틀로) · 세션 · 도메인 · 표시 투영 · 화면 본문.
R3 이 알아야 할 것
- 콘솔 패키지가
dependencies: clinic_shell:을 더하고StaffShell·StaffPageFrame을 그대로 쓴다. 셸이 앱 이름을AppIdentity.displayName으로 읽으므로 앱과 콘솔이 같은 이름을 보인다. - 아이콘: Lucide 중 CoUI 묶음에 없는 7개는
registerStaffShellIcons()가 등록한다 — 호스트의 모듈 등록과 시험 · 골든 준비가 먼저 부른다(앱은registerClinicModule()이 부른다). - 목적지 순서가 라우터 가지 순서다(
StaffDestination.values[navigationShell.currentIndex]) — 바꾸면 라우트가 어긋나므로 시험(staff_destination_test)이 순서를 고정한다. - 폰 하단 탭에 없는 목적지(예약 · 수납 · 통계 · 설정)에서는 선택된 탭이 없다 · 레일에 없는 대시보드 · 통계도 같다 — Figma 그대로이고 디자이너 확인 대상이다(PR 본문 「확인 후보」).