# Theme Architecture — 4-Theme Built-in System ## 0. 요구사항 (사용자 명시) > "테마 관리에서 리액트 기반 한 가지 — **기본 / 이윰빌더 / 아미나빌더 / 영카드** — 이렇게 선택할 수 있게 구현" → 운영자가 어드민 화면에서 사이트 전체 테마를 한 번에 전환 가능. 페이지 단위 / 게시판 단위 오버라이드도 지원. ## 1. 4종 테마 정의 | 코드 | 한글명 | 모티프 | 활용 시나리오 | |------|--------|--------|--------------| | `basic` | **기본** | 그누보드5 default skin (responsive bootstrap-ish) | 미니멀, 신규 도메인 시작 | | `eyoom` | **이윰빌더** | 현재 운영 중인 `eb4_maga_005` (매거진 + 사이드바 + 위젯) | 컨텐츠 중심 커뮤니티 | | `amina` | **아미나빌더** | 그누보드용 Amina Builder (모던 카드형 + 메가메뉴) | 트래픽 큰 종합 커뮤니티 | | `youngcart` | **영카드(영카트)** | 영카트 쇼핑몰 + 게시판 + 마이페이지 | 쇼핑 중심 사이트 | ## 2. 패키지 구조 — `packages/themes/` ``` packages/themes/ ├── core/ # 테마 공통 인터페이스 │ ├── ThemeProvider.tsx # context, 토큰, css var 주입 │ ├── ThemeRegistry.ts # 모든 테마 메타데이터 + lazy loader │ ├── types.ts # ThemeManifest, Slot, Layout 타입 │ └── slots.ts # Header/Footer/Side/Banner/PostList/PostView 슬롯 ├── basic/ │ ├── manifest.ts │ ├── tokens.ts # CSS variables (--color-primary, --space-md, etc.) │ ├── layouts/{root,board,post,shop}.tsx │ ├── components/{Header,Footer,Sidebar,PostCard,...}.tsx │ ├── styles/ # tailwind.config 또는 sass │ └── index.ts # default export = ThemeManifest ├── eyoom/ │ ├── manifest.ts │ ├── tokens.ts # 이윰 매거진 컬러/타이포 (참고: src/theme/eb4_maga_005) │ ├── layouts/... │ ├── components/{MegaMenu,RankingSidebar,LatestWidget,...}.tsx │ └── index.ts ├── amina/ # Aminam Builder reproduction │ └── ... └── youngcart/ # YoungCart shop-centric ├── components/{ProductGrid,CartDrawer,CategoryNav,...}.tsx └── ... ``` ## 3. 테마 인터페이스 ```ts // packages/themes/core/types.ts export interface ThemeManifest { id: 'basic' | 'eyoom' | 'amina' | 'youngcart'; name: string; // 한글 표시명 preview: string; // 썸네일 URL tokens: ThemeTokens; // CSS 변수 (런타임 주입) layouts: { root: ComponentType; board: ComponentType; post: ComponentType; shop: ComponentType; page: ComponentType; }; slots: { Header: ComponentType; Footer: ComponentType; Sidebar: ComponentType; PostList: ComponentType; PostCard: ComponentType; PostView: ComponentType; LoginForm: ComponentType; NewWindow: ComponentType; // ...20개 정도 슬롯 표준화 }; features?: { shop?: boolean; // youngcart 만 true magazineWidgets?: boolean; // eyoom 만 true megaMenu?: boolean; // amina, eyoom }; } ``` ## 4. Slot/Override 메커니즘 ### 4.1 글로벌 테마 - `app_settings.theme = 'eyoom'` (DB) 가 활성 테마 - `apps/web/src/app/layout.tsx` 가 `ThemeRegistry.load(activeTheme)` 으로 동적 import - React Server Component 단계에서 결정 → 첫 페인트부터 올바른 레이아웃 ### 4.2 페이지 단위 override - 게시판/카테고리/페이지에 `theme_override` 컬럼 - 예: 자유게시판은 `eyoom`, 쇼핑은 `youngcart` 동시 운영 가능 ### 4.3 사용자 토글 (옵션) - 회원이 `mb_theme_pref` 로 본인 선호 테마 선택 가능 - cookie + DB 저장 - 관리자가 기능 on/off 제어 ## 5. 관리자 — 테마 선택 UI `apps/admin/src/app/themes/page.tsx`: ``` ┌─ 테마 관리 ──────────────────────────────┐ │ [기본] [이윰빌더] [아미나빌더] [영카드] │ ← 4개 카드, 활성 테마 강조 │ │ │ ◉ 기본 사이트 테마: [이윰빌더 ▼] │ │ │ │ ─ 영역별 오버라이드 ─ │ │ · 자유게시판: (글로벌) │ │ · 쇼핑몰: 영카드 │ │ · /event 페이지: 아미나빌더 │ │ │ │ ─ 미리보기 ─ │ │ https://localhost:3000/?_preview=amina │ │ │ │ [저장] [기본값 복원] │ └──────────────────────────────────────────┘ ``` DB: ```sql CREATE TABLE app_settings ( key TEXT PRIMARY KEY, value JSONB ); INSERT INTO app_settings VALUES ('theme.global', '"eyoom"'::jsonb), ('theme.overrides', '[{"path":"/shop/*","theme":"youngcart"}]'); ``` ## 6. 디자인 토큰 표준 각 테마는 동일한 토큰 스키마를 만족 → CSS 변수로 주입 → 컴포넌트는 토큰만 참조 (매직 컬러 금지): ```ts // tokens.ts (예: eyoom) export const tokens: ThemeTokens = { color: { primary: '#ff5722', primaryDark: '#e64a19', bg: '#0e0f12', bgSurface: '#16181d', text: '#e6e6e6', textMuted: '#9aa0a6', border: '#2a2d34', success: '#21d07a', danger: '#e74c3c', warning: '#f5b041', }, font: { sans: '"Noto Sans KR", system-ui, sans-serif', mono: '"JetBrains Mono", monospace', }, radius: { sm: '4px', md: '8px', lg: '14px', pill: '999px' }, space: { xs: '4px', sm: '8px', md: '16px', lg: '24px', xl: '40px' }, shadow: { sm: '...', md: '...', lg: '...' }, z: { sticky: 100, modal: 1000, toast: 2000 }, }; ``` 각 테마는 동일 키를 채우되 값만 다르게 (basic 은 라이트, eyoom 은 다크 매거진, amina 는 그라디언트, youngcart 는 화이트 + 액센트) ## 7. 마이그레이션 매핑 (이윰 → React) | 기존 (`theme/eb4_maga_005/`) | 신규 (`packages/themes/eyoom/`) | |-----------------------------|-------------------------------| | `head.html.php` | `layouts/root.tsx` (Header) | | `head.sub.html.php` | `slots/Header.tsx` | | `tail.html.php` | `slots/Footer.tsx` | | `side.html.php` | `slots/Sidebar.tsx` | | `index.html.php` | `layouts/root.tsx` (홈 위젯) | | `skin/board//list.skin.html.php` | `slots/PostList.tsx` | | `skin/board//view.skin.html.php` | `slots/PostView.tsx` | | `css/eyoom.css`, `css/eyoom-style.css` | `styles/*.css` (CSS module 또는 tailwind) | | `js/eyoom.js` | React hooks / event handlers | ### 매거진 위젯 (이윰 코어) - 최신글 슬라이더 (`eyoom_slider`) → `` - 회원 랭킹 (`eyoom_ranking`) → `` - 출석 (`eyoom_attendance`) → `` - 배너 (`eyoom_banner`) → `` ## 8. 아미나빌더 디자인 노트 - 메가메뉴 (1단 큰 카테고리 + 2단 서브) - 카드형 그리드 (3열 → 모바일 1열) - 섹션별 스킨 시스템 (홈에 여러 게시판 위젯 동시 렌더) - 라이트/다크 테마 토글 - 인기 회원 랭킹, 실시간 댓글, 인기글 사이드바 ## 9. 영카드 디자인 노트 - 상단 카테고리 가로 네비 - 메인 = 베스트 상품 그리드 + 쿠폰존 + 이벤트 슬라이더 - 마이페이지: 주문/배송/쿠폰/적립금 - 게시판은 영카트 기본 룩 (테이블형 리스트) ## 10. 신규 테마 추가 절차 (확장성) 1. `packages/themes//` 폴더 생성, manifest 작성 2. `ThemeRegistry.register({ id: '', loader: () => import('./') })` 추가 3. `app_settings.theme.global` 후보에 자동 노출 4. 별도 빌드 없이 hot reload (Next.js dev 모드) ## 11. 성능 - 각 테마 번들은 lazy chunk → 활성 테마만 다운로드 - 테마 토큰은 `` 인라인 → FOUC 방지 - RSC 단에서 테마 결정 → 클라이언트 hydration 최소화