20장 앱 구조
하나의 앱 안에 업무 도메인마다 독립된 하위 앱을 둡니다. 최상위 탐색만 함께 쓰고, 나머지 레이아웃과 페이지는 도메인이 소유합니다. 이 장은 그 폴더 구조와 Vue 파일 규칙을 설명합니다.
왜 필요한가
업무 앱 하나에는 관리비·회계·인사처럼 성격이 다른 업무가 함께 들어 있습니다. 업무마다 메뉴 구조와 머리글이 다릅니다. 모든 업무가 사이드 메뉴 하나와 레이아웃 하나를 함께 쓰면, 한 업무를 고칠 때 다른 업무 화면이 흔들립니다. 반대로 규칙 없이 나누면 같은 부품이 도메인마다 따로 생깁니다.
사람과 AI 에이전트는 파일 경로만 보고 「어디서나 쓰는 부품인가, 이 업무 전용인가, 라우터 진입점인가」를 알 수 있어야 합니다. 그래서 폴더와 파일 이름에 역할을 드러냅니다.
원칙: App in app
- 하나의 앱 안에 도메인(하위 앱, sub-app)이 독립적으로 있습니다.
- 최상위 탐색(top navigation)만 공유합니다. 사이드 메뉴·머리글·바닥글·페이지는 도메인마다 따로 둡니다.
- 홈 화면도 하나의 앱(
home-app)으로 취급합니다. - 도메인 폴더에는
-app접미사를 붙여 이 구조를 이름으로 드러냅니다. 예:console-app/,portal-app/.
leysys-design의 문서 사이트도 같은 구조입니다. foundation-app, component-app, pattern-app, home-app이 각자의 사이드 메뉴와 페이지를 갖습니다.
원칙: components 2구역
| 구역 | 폴더 | 내용 |
|---|---|---|
| 범용 UI | components/ui/ | 도메인과 무관하게 어디서든 재사용하는 부품 |
| 도메인 | components/{도메인}-app/ | 그 도메인의 레이아웃(App*)과 페이지 전용 부품 |
text
components/console-app/
├── AppHeader.vue 도메인 전용 머리글
├── AppAside.vue 도메인 전용 사이드 메뉴
├── AppFooter.vue 도메인 전용 바닥글
├── AppHomePage.vue 도메인에 처음 들어왔을 때의 페이지
├── AppRouteOutlet.vue RouterView를 감싸는 outlet
├── app-overlays/ 도메인 공용 오버레이
└── account-mgmt/billing/account/auth/
├── AccountAuthPage.vue
├── blocks/StatsCard.vue
└── overlays/CreatePaymentDialog.vueApp*레이아웃 부품은 도메인마다 다르므로 공유 폴더에 두지 않습니다.- 범용 UI를 도메인 하위 폴더에 두지 않습니다.
- 디자인 시스템 자체는 이 두 구역 밖입니다. CSS·토큰은 패키지로 받고, Vue wrapper는 registry에서 복사해
src/registry/에 둡니다. 이 사본은 AI 에이전트가 직접 편집하지 못하도록 권한 설정으로 막습니다 (24장).
원칙: views 2단계와 layouts
views/는 라우터 진입점이 있는 곳입니다. Nuxt의 pages/와 같은 역할입니다.
- AppView.vue — 도메인 레이아웃입니다. 그 도메인의
App*부품을 조립하고, 가운데에AppRouteOutlet.vue를 둡니다. - DefaultView.vue — 페이지 View입니다.
AppRouteOutlet안의<RouterView />에 그려집니다.
text
AppView.vue 도메인 레이아웃
├── AppHeader
├── AppAside
├── AppRouteOutlet.vue
│ └── <RouterView /> → DefaultView.vue
└── AppFooterlayouts/ | views/{도메인}-app/AppView.vue | |
|---|---|---|
| 범위 | 앱 전체 공통 | 도메인별 |
| 연결 | <slot /> | AppRouteOutlet.vue → <RouterView /> |
| 개수 | 1~2개 | 도메인 수만큼 |
layouts/에는 앱 전체가 함께 쓰는 레이아웃만 둡니다.- AppView에서
<RouterView />를 바로 쓰지 않고AppRouteOutlet.vue로 감쌉니다. 라우터 outlet이라는 책임을 한 파일이 맡습니다. - View는 import와 조립만 합니다. 하드코딩한 내용과
<style>을 두지 않습니다.
원칙: Vue 파일 규칙
- Composition API(
<script setup>)를 씁니다. 기존 Options API 페이지는 손댈 때 점진적으로 바꿉니다. - 파일명과 템플릿 태그는 PascalCase입니다.
<RouterView />는 맞고<router-view />는 틀립니다. - 파일명은 역할을 드러냅니다. 접미사는 라우터 진입점의
View하나만 둡니다.
| 역할 | 파일명 예 |
|---|---|
| 컴포넌트 | EButton.vue, SearchInput.vue |
| 도메인 콘텐츠 | StatsCard.vue, CreatePaymentDialog.vue |
| 페이지 본문 | AccountAuthPage.vue |
| 레이아웃 | DefaultLayout.vue |
| 라우터 outlet | AppRouteOutlet.vue |
| 라우터 진입점 | DefaultView.vue |
Page는 문서·시연·화면의 본문이라는 역할명입니다. 본명이 이미 Page로 끝나면 한 번만 씁니다(DashboardPage.vue). 탐색·본문·보조 영역을 배치하는 구조 컴포넌트 EPage·MPage와는 다른 것입니다.
실제 예
leysys-design 문서 사이트의 Button 문서는 진입점과 본문이 나뉘어 있습니다.
- 진입점
views/component-app/components/EButtonView.vue는 전역 레이아웃·머리글·본문을 가져와 조립만 합니다. - 본문
components/component-app/e-button/EButtonPage.vue가 실제 문서 내용을 가집니다.
vue
<template>
<DocLayout>
<template #header><DocHeader title="Button" description="…" /></template>
<ButtonPage />
</DocLayout>
</template>파일명 규칙도 결정 기록으로 바뀌었습니다. 2026-09-30 KST 결정 전에는 Vue 파일에 Ato·Mol·Org·Tem 같은 계층 약어 접미사를 붙였습니다. 백지에서 다시 보면, 파일명은 역할을 말하고 계층은 실제 의존성과 소유 경계가 말하는 편이 맞습니다. 재사용 범위나 import 계층은 파일명이 아니라 실제 코드로 판단해야 하기 때문입니다. 그래서 View만 남기고 나머지 접미사를 없앴습니다. 3.0 공개 전이어서 별칭이나 점진 이관 기간 없이 Vue 파일 428개를 한 변경으로 옮겼고, 문서 감사가 다루는 파일 집합 다섯 가지가 이관 전후에 같은지 확인했습니다.
경계와 예외
- Leysys는 라우팅을 직접 선언합니다. 파일 기반 라우팅을 쓰는 프레임워크에서는
views/가pages/에 해당합니다. - 파일명으로 재사용 범위나 조립 순서를 판정하지 않습니다. 재사용 범위는 도메인 의존성·props·소유 위치로 판단합니다.
- 화면을 무엇으로 조립하는지(컴포넌트·패턴·Tailwind, SFC
<style>금지)는 디자인 시스템 규칙입니다 (7장, 16장). - 디자인 정본보다 먼저 만든 제품 저장소에는 이 구조와 다른 폴더가 남아 있을 수 있습니다. 다루는 방법은 21장에 있습니다.
정리
- 도메인마다 독립된 하위 앱(
{도메인}-app)을 두고, 최상위 탐색만 공유합니다. - 부품은 범용 UI(
components/ui/)와 도메인 전용(components/{도메인}-app/) 두 구역에 둡니다. - 라우터 진입점은 AppView(도메인 레이아웃)와 DefaultView(페이지) 두 단계이고,
layouts/는 전역 레이아웃만 둡니다. - 파일명은 역할을 드러내고, 접미사는 라우터 진입점의
View만 씁니다.
정본
leysys-designdocs/process/leysys-prototyping-pipeline.md§6–10 — 폴더 구조, components 2구역, views 2단계leysys-designdocs/decisions/COMPONENT-FILE-SUFFIX-VIEW-ONLY-2026-09-30.md— Vue 파일명 결정leysys-designdocs/specs/NAMING-CONVENTION.md§5.5 — Vue 컴포넌트 파일명leysys-designAGENTS.md「폴더 구조 컨벤션」 — App in app, components 2구역, Vue 3 원칙