매뉴얼 진입점 규약 (MANUAL CONVENTION)
| 항목 | 내용 |
|---|---|
| 상태 | 채택 (2026-09-25) |
| 범위 | portal-foundation 을 소비하는 모든 포털의 매뉴얼 화면 진입 |
| 결정 | 매뉴얼 진입점은 셸 슬롯(PortalShell / PortalAdminShell 의 manualLink)으로 노출한다. 진입 자리·모양은 셸이 소유하고 콘텐츠는 포털이 소유한다 |
| 대상 | AgentCenter(참조 구현) · ProcessCenter · GuideCenter · DocumentLibrary · lunchapp |
| 관련 | ADMIN_MENU_CONVENTION.md(관리자 셸·구간) · ROUTING_CONVENTION.md(경로가 화면의 원천) · MENU_GOVERNANCE_DESIGN.md(메뉴 공급 L1→L3) · EXPLORE_ANSWER_CONVENTION.md(통합 검색·근거 기반 답변) |
1. 왜 셸 슬롯인가
매뉴얼은 모든 포털에 있고, 업무 도메인이 아니라 사용법이다. 그런데 진입 자리를 포털마다 정하면 사용자가 매뉴얼을 열 때마다 다시 찾아야 한다.
| 대안 | 채택하지 않은 이유 |
|---|---|
| 사이드바 메뉴 트리 항목(포털이 정의) | 자리가 포털마다 달라진다. AgentCenter 실측: 사용자 메뉴 9번째(맨 아래)라 그룹을 펼치면 스크롤에 묻혀 "바로 보이지" 않는다 |
상단 바 버튼(topNavEnd) | 진입점이 둘이 되어 "한 곳에서 찾는다"가 성립하지 않는다. 알림·계정 아이콘과 성격이 섞인다 |
| 사용자 메뉴 DB(L2)·중앙(L3) 관리 항목 | 사용자 메뉴는 L1→L2→L3 이전 경로가 예정돼 있다. 매뉴얼을 메뉴 항목으로 두면 공급처가 바뀔 때마다 포털마다 다시 붙여야 하고, 중앙 시드에 포털별 경로를 등록해야 한다(MENU_GOVERNANCE_DESIGN.md §7-5) |
셸 슬롯은 메뉴 공급 경로와 무관하게 유지된다 — 메뉴가 로컬 배열이든 포털 DB 든 중앙 캐시든 매뉴얼 진입점은 그대로다.
2. 규칙 (필수)
- 진입은 셸 슬롯 —
manualLink={{ href, label?, iconKey?, active? }}. 포털은href만 넘겨도 된다(라벨 기본값매뉴얼/Manual·아이콘BookOpen은 셸이 정한다). - 메뉴 행으로 중복 정의하지 않는다 — 진입점은 하나다. 메뉴 트리에 매뉴얼 항목을 남기지 않는다.
- 경로는 라우팅 표에 등록한다 — 메뉴 행이 아니어도 화면은 경로를 갖는다(
ROUTING_CONVENTION.md§2.4). 경로는 한 곳에서만 정의한다. - 콘텐츠는 포털 소유 — 업무 용어·절차는 포털이 쓴다. 셸은 진입점만 갖는다.
- 관리자 매뉴얼도 같은 슬롯 —
PortalAdminShell은PortalShellProps를 상속하므로 관리자 셸에서도manualLink하나로 같은 자리에 놓인다. - 노출 범위 — 사용자 매뉴얼은 인증 사용자 전체에게, 관리자 매뉴얼은 관리자 셸 안에서만 노출된다. 매뉴얼 본문을 역할별로 나눠야 하면 본문 안에서 표시한다(셸 게이트를 추가하지 않는다).
- 현재 화면 표시 — 매뉴얼 화면에 있을 때
active: true를 넘긴다. 셸이aria-current="page"로 표시한다. - 물어보는 진입은 통합 검색창 — 매뉴얼을 "읽는" 진입은
manualLink, "물어보는" 진입은 셸 통합 검색창과 페이지 내PortalExploreSearch다(§7). 매뉴얼용 챗 패널을 따로 만들지 않는다.
3. 경로
| 구분 | 경로 | 노출 |
|---|---|---|
| 사용자 매뉴얼 | /manual | PortalShell.manualLink |
| 관리자 매뉴얼 | /admin/manual | PortalAdminShell.manualLink |
/manual 은 ROUTING_CONVENTION.md §3 의 "1 Depth 화면", /admin/manual 은 "관리자" 행을 따른다. 매뉴얼은 UI 번호가 붙은 업무 화면이 아니므로 화면 id 표에서 HELP 처럼 별도 구분을 쓸 수 있다(포털 판단).
4. 구현 예시 (AgentCenter)
tsx
// 메뉴 정의(MENU_TREE)에는 매뉴얼 항목을 두지 않는다 — 진입은 셸이 그린다.
const MANUAL_PATH = "/manual";
const ADMIN_MANUAL_PATH = "/admin/manual";
<PortalShell
navigationItems={buildNavigationItems(activeView, roles)}
manualLink={{ href: MANUAL_PATH, active: activeView === "manual" }}
>
{routes} {/* 라우팅 표에 /manual 이 등록돼 있다 */}
</PortalShell>
<PortalAdminShell
commonAdminItems={adminMenu.commonAdminItems}
portalAdminItems={adminMenu.portalAdminItems}
manualLink={{ href: ADMIN_MANUAL_PATH, label: "관리자 매뉴얼", active: activeView === "admin-manual" }}
>
{adminRoutes}
</PortalAdminShell>5. 소비 포털 이식 체크리스트
- 사용자·관리자 매뉴얼 화면을 갖췄는가(콘텐츠는 포털이 쓴다).
- 매뉴얼 경로를 라우팅 표에 등록했는가(메뉴 행이 아니어도).
- 셸에
manualLink를 넘기고, 메뉴 정의에 매뉴얼 항목을 남기지 않았는가. - 현재 화면에서
active를 넘기는가. - 매뉴얼 본문의 화면 이름·경로가 실제 화면과 일치하는가(문구를 화면에서 유추하지 않는다).
6. 검증
- 셸: 슬롯 렌더·기본 라벨(로케일)·접힘 상태·미지정 시 미렌더·관리자 셸 상속 —
packages/ui-react/src/manualLink.contract.test.tsx. - 포털: 매뉴얼 경로가 라우팅 표에는 있고 메뉴 정의에는 없음을 테스트로 고정한다(중복 진입점 회귀 방지). 화면 배선도 함께 검증한다.
7. 대화형 매뉴얼 진입(통합 검색창)
매뉴얼을 읽는 대신 물어보는 경로도 같은 진입점을 쓴다. 매뉴얼 전용 챗 패널을 만들지 않고 셸 통합 검색창을 쓴다 — 상세 계약은 EXPLORE_ANSWER_CONVENTION.md.
| 사용자 행동 | 진입 | 결과 |
|---|---|---|
| "이 화면 어떻게 써?" | 셸 상단 검색창(Ctrl/⌘ K) · 페이지 내 PortalExploreSearch | 검색 결과 + 근거 기반 답변(인용 링크) |
| "매뉴얼 문서를 보고 싶어" | 사이드바 manualLink(§2-1) | 매뉴얼 화면 |
- 답변은 인용이 있을 때만 렌더한다. 인용이 없으면 매뉴얼 화면으로 안내한다.
- 매뉴얼 본문은 검색 색인의 근거 문서가 되므로 화면 이름·경로를 실제 화면과 일치시킨다(§5-5).