From 4b8ca09ea5d77f9dd55aa178583765d21c662987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=B3=91=EC=B2=A0?= Date: Wed, 18 Mar 2026 15:40:53 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20[module]=20Phase=203=20=E2=80=94=20?= =?UTF-8?q?=EB=AC=BC=EB=A6=AC=EC=A0=81=20=EB=B6=84=EB=A6=AC=20(=EA=B2=BD?= =?UTF-8?q?=EA=B3=84=20=EB=A7=88=EC=BB=A4,=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8,=20=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=ED=8A=B8=20=EA=B0=80=EB=93=9C,=20=EB=AC=B8=EC=84=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MODULE.md 경계 마커 4개 (production, quality, construction, vehicle-management) - verify-module-separation.sh: Common→Tenant 금지 임포트 검증 스크립트 - 영업 생산지시 3개 페이지에 useModules 가드 추가 - MODULE_SEPARATION_OK 주석 마커 (공유 래퍼 허용) - tsconfig @modules/* path alias 추가 - CLAUDE.md 모듈 분리 아키텍처 섹션 추가 - 모듈 분리 가이드 문서 (claudedocs/architecture/) --- CLAUDE.md | 67 +++++ .../architecture/module-separation-guide.md | 234 ++++++++++++++++++ scripts/verify-module-separation.sh | 97 ++++++++ .../[id]/production-order/page.tsx | 19 ++ .../production-orders/[id]/page.tsx | 19 ++ .../production-orders/page.tsx | 18 ++ .../business/construction/MODULE.md | 32 +++ src/components/production/MODULE.md | 25 ++ src/components/quality/MODULE.md | 21 ++ src/components/vehicle-management/MODULE.md | 20 ++ src/lib/api/production-orders/actions.ts | 2 +- src/lib/api/production-orders/types.ts | 2 +- tsconfig.json | 3 + 13 files changed, 557 insertions(+), 2 deletions(-) create mode 100644 claudedocs/architecture/module-separation-guide.md create mode 100755 scripts/verify-module-separation.sh create mode 100644 src/components/business/construction/MODULE.md create mode 100644 src/components/production/MODULE.md create mode 100644 src/components/quality/MODULE.md create mode 100644 src/components/vehicle-management/MODULE.md diff --git a/CLAUDE.md b/CLAUDE.md index 18adf690..785d508b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -593,6 +593,73 @@ import { FormField } from '@/components/molecules/FormField'; --- +## Module Separation Architecture +**Priority**: 🔴 + +### 개요 +멀티테넌트 모듈 분리 아키텍처. 테넌트별로 필요한 모듈만 활성화하여 불필요한 기능 숨김. +`tenant.options.industry` 미설정 시 **모든 모듈 활성화** (기존 동작 100% 유지). + +### 핵심 패턴: moduleAware 안전 장치 +```typescript +const { isEnabled, tenantIndustry } = useModules(); +const moduleAware = !!tenantIndustry; // industry 미설정 → false → 전부 허용 + +if (!moduleAware) return allData; // 기존과 동일 +return filteredData; // 모듈 기반 필터링 +``` + +### 모듈 구조 +``` +src/modules/ +├── types.ts # ModuleId, TenantIndustry, MODULE_REGISTRY +├── config.ts # INDUSTRY_MODULES (업종별 활성 모듈 매핑) +├── ModuleGuard.tsx # 라우트 기반 접근 제어 (layout.tsx에서 사용) +└── ModuleProvider.tsx # React Context (tenant API → enabledModules 계산) + +src/hooks/useModules.ts # { isEnabled, tenantIndustry, enabledModules, ... } +``` + +### 모듈 ID 목록 +| ModuleId | 설명 | 테넌트 | +|----------|------|--------| +| `production` | 생산관리 | 경동 | +| `quality` | 품질관리 | 경동 | +| `construction` | 시공관리 | 주일 | +| `vehicle-management` | 차량관리 | 선택적 | + +### 라우트 가드 vs 명시적 가드 +- **라우트 가드 (ModuleGuard)**: `/production/*`, `/quality/*` 등 전용 라우트 +- **명시적 가드 (useModules)**: 공통 라우트 내 모듈 의존 페이지 (예: `/sales/*/production-orders`) + +```typescript +// 공통 라우트 내 모듈 의존 페이지 — 명시적 가드 필수 +if (tenantIndustry && !isEnabled('production')) { + return
생산관리 모듈이 활성화되어 있지 않습니다.
; +} +``` + +### 크로스 모듈 임포트 규칙 +- **Common → Tenant 직접 import 금지** (검증 스크립트: `scripts/verify-module-separation.sh`) +- **허용 예외**: `// MODULE_SEPARATION_OK` 주석 + `src/lib/api/` 공유 래퍼 +- **Tenant → Common import**: 자유 +- **Tenant → Tenant import**: 금지 (dynamic import만 허용) + +### MODULE.md 경계 마커 +각 테넌트 모듈 디렉토리에 `MODULE.md` 파일로 모듈 경계 문서화: +- `src/components/production/MODULE.md` +- `src/components/quality/MODULE.md` +- `src/components/business/construction/MODULE.md` +- `src/components/vehicle-management/MODULE.md` + +### Path Aliases +```json +// tsconfig.json +"@modules/*": ["./src/modules/*"] +``` + +--- + ## User Environment **Priority**: 🟢 diff --git a/claudedocs/architecture/module-separation-guide.md b/claudedocs/architecture/module-separation-guide.md new file mode 100644 index 00000000..eab259f8 --- /dev/null +++ b/claudedocs/architecture/module-separation-guide.md @@ -0,0 +1,234 @@ +# SAM ERP 멀티테넌트 모듈 분리 아키텍처 + +> 작성일: 2026-03-18 +> 상태: 프론트엔드 Phase 0~3 완료 / 백엔드 작업 필요 + +--- + +## 1. 개요 + +### 목표 +하나의 SAM ERP 코드베이스에서 **테넌트(회사)별로 필요한 모듈만 활성화**하여, +불필요한 메뉴·페이지·대시보드 섹션을 숨기는 구조. + +### 현재 테넌트별 모듈 구성 +| 업종 코드 | 테넌트 예시 | 활성 모듈 | +|-----------|------------|-----------| +| `shutter_mes` | 경동 | 생산관리, 품질관리, 차량관리 | +| `construction` | 주일 | 시공관리, 차량관리 | +| (미설정) | 기타 모든 테넌트 | **전체 모듈 활성화 (기존과 동일)** | + +### 안전 원칙 +``` +tenant.options.industry가 설정되지 않은 테넌트 → 모든 기능 그대로 사용 가능 += 기존 동작 100% 유지, 부작용 제로 +``` + +--- + +## 2. 프론트엔드 구조 (완료) + +### 파일 구조 +``` +src/modules/ +├── types.ts # ModuleId 타입 정의 +├── tenant-config.ts # 업종→모듈 매핑 (resolveEnabledModules) +└── index.ts # 모듈 레지스트리 (라우트 매핑, 대시보드 섹션) + +src/hooks/ +└── useModules.ts # React 훅: isEnabled(), isRouteAllowed(), tenantIndustry +``` + +### 모듈 ID 목록 +| ModuleId | 이름 | 소유 라우트 | 대시보드 섹션 | +|----------|------|------------|--------------| +| `common` | 공통 ERP | /dashboard, /accounting, /sales, /hr, /approval, /settings 등 | 전부 | +| `production` | 생산관리 | /production | dailyProduction, unshipped | +| `quality` | 품질관리 | /quality | - | +| `construction` | 시공관리 | /construction | construction | +| `vehicle-management` | 차량관리 | /vehicle-management, /vehicle | - | + +### 프론트엔드 동작 흐름 +``` +1. 로그인 → authStore에 tenant 정보 저장 +2. useModules() 훅이 tenant.options.industry 읽음 +3. industry 값으로 INDUSTRY_MODULE_MAP 조회 → 활성 모듈 목록 결정 +4. 각 컴포넌트에서 isEnabled('production') 등으로 분기 +``` + +### 적용된 영역 + +#### A. CEO 대시보드 +- **섹션 필터링**: 비활성 모듈의 대시보드 섹션 자동 제외 +- **API 호출 차단**: 비활성 모듈의 API는 호출하지 않음 (null endpoint) +- **설정 팝업**: 비활성 모듈 섹션은 설정에서도 안 보임 +- **캘린더**: 비활성 모듈의 일정 유형 필터 숨김 +- **요약 네비**: 비활성 섹션 자동 제외 + +#### B. 라우트 접근 제어 +- `/production/*`, `/quality/*`, `/construction/*` 등 전용 라우트는 모듈 비활성 시 접근 차단 +- `/sales/*/production-orders` 같은 공통 라우트 내 모듈 의존 페이지는 명시적 가드 적용 + +#### C. 사이드바 메뉴 +- 비활성 모듈의 메뉴 항목 숨김 (isRouteAllowed 기반) + +--- + +## 3. 백엔드 필요 작업 + +### 3.1 tenants 테이블 options 필드에 industry 추가 +**우선순위: 🔴 필수** + +현재 프론트엔드는 `tenant.options.industry` 값을 읽어서 모듈을 결정합니다. +이 값이 백엔드에서 내려와야 실제로 동작합니다. + +```php +// tenants 테이블의 options JSON 컬럼에 industry 추가 +// 예시 데이터: +{ + "industry": "shutter_mes" // 경동: 셔터 MES +} +{ + "industry": "construction" // 주일: 건설 +} +// 다른 테넌트: industry 키 없음 → 프론트에서 전체 모듈 활성화 +``` + +**작업 내용:** +1. `tenants` 테이블의 `options` JSON 컬럼에 `industry` 키 추가 (마이그레이션 불필요, JSON이므로) +2. 경동 테넌트: `options->industry = 'shutter_mes'` +3. 주일 테넌트: `options->industry = 'construction'` +4. 테넌트 정보 API 응답에 `options.industry` 포함 확인 + +**확인 포인트:** +- 프론트엔드에서 `authStore.currentUser.tenant.options.industry`로 접근 +- 현재 로그인 API(`/api/v1/auth/me` 또는 유사)의 응답에서 tenant.options가 포함되는지 확인 +- 포함 안 되면 응답에 추가 필요 + +### 3.2 (선택) 테넌트 관리 화면에서 industry 설정 UI +**우선순위: 🟡 선택** + +관리자가 테넌트별 업종을 설정할 수 있는 UI. 급하지 않음 — DB 직접 수정으로 충분. + +### 3.3 (Phase 2 예정) 명시적 모듈 목록 API +**우선순위: 🟢 향후** + +현재는 `industry` → 프론트엔드 하드코딩 매핑으로 모듈 결정. +향후 백엔드에서 직접 모듈 목록을 내려주면 더 유연해짐. + +```php +// tenant.options 예시 (Phase 2) +{ + "industry": "shutter_mes", + "modules": ["production", "quality", "vehicle-management"] // 명시적 목록 +} +``` + +프론트엔드는 이미 이 구조를 지원하도록 준비되어 있음: +```typescript +// src/modules/tenant-config.ts +export function resolveEnabledModules(options) { + // Phase 2: 백엔드가 명시적 모듈 목록 제공 → 우선 사용 + if (explicitModules && explicitModules.length > 0) { + return explicitModules; + } + // Phase 1: industry 기반 기본값 (현재) + if (industry) { + return INDUSTRY_MODULE_MAP[industry] ?? []; + } + return []; +} +``` + +--- + +## 4. 업종별 모듈 매핑 (프론트엔드 하드코딩) + +```typescript +// src/modules/tenant-config.ts +const INDUSTRY_MODULE_MAP: Record = { + shutter_mes: ['production', 'quality', 'vehicle-management'], + construction: ['construction', 'vehicle-management'], +}; +``` + +새로운 업종 추가 시: +1. 여기에 매핑 추가 +2. 필요하면 `ModuleId` 타입에 새 모듈 ID 추가 +3. `MODULE_REGISTRY` (src/modules/index.ts)에 라우트/대시보드 섹션 등록 + +--- + +## 5. 핵심 코드 패턴 + +### 기본 사용법 +```typescript +import { useModules } from '@/hooks/useModules'; + +function MyComponent() { + const { isEnabled, tenantIndustry } = useModules(); + + // 안전 장치: industry 미설정이면 모든 기능 활성 + const moduleAware = !!tenantIndustry; + + if (moduleAware && !isEnabled('production')) { + return
생산관리 모듈이 비활성화되어 있습니다.
; + } + + // 생산관리 기능 렌더링... +} +``` + +### 크로스 모듈 임포트 규칙 +``` +✅ Common → Common (자유) +✅ Tenant → Common (자유) +✅ Common → Tenant (래퍼 경유) (src/lib/api/에서 MODULE_SEPARATION_OK 주석과 함께) +❌ Common → Tenant (직접) (scripts/verify-module-separation.sh가 검출) +❌ Tenant → Tenant (금지, dynamic import만 허용) +``` + +--- + +## 6. 구현 이력 + +| Phase | 내용 | 커밋 | 상태 | +|-------|------|------|------| +| Phase 0 | 크로스 모듈 의존성 해소 | `a99c3b39` | ✅ 완료 | +| Phase 1 | 모듈 레지스트리 + 라우트 가드 | `0a65609e` | ✅ 완료 | +| Phase 2 | CEO 대시보드 모듈 디커플링 | `46501214` | ✅ 완료 | +| Phase 3 | 물리적 분리 (경계 마커, 검증, 가드, 문서) | (미커밋) | ✅ 완료 | + +--- + +## 7. 테스트 시나리오 + +### 테스트 방법 +백엔드에서 `tenant.options.industry`를 설정한 후: + +| 시나리오 | 예상 결과 | +|----------|----------| +| industry 미설정 테넌트 로그인 | 기존과 완전 동일 (모든 메뉴/기능 표시) | +| `shutter_mes` 테넌트 로그인 | 시공관리 메뉴 숨김, 대시보드 시공 섹션 안 보임 | +| `construction` 테넌트 로그인 | 생산/품질 메뉴 숨김, 대시보드 생산 섹션 안 보임 | +| `shutter_mes`에서 `/construction` 직접 접근 | 접근 차단 메시지 표시 | +| `construction`에서 `/production` 직접 접근 | 접근 차단 메시지 표시 | + +### 롤백 방법 +문제 발생 시 DB에서 `tenant.options.industry` 값만 제거하면 즉시 원복. +프론트엔드 코드 변경 불필요. + +--- + +## 8. 향후 로드맵 + +``` +현재 (Phase 1) 향후 (Phase 2) 최종 (Phase 3) +┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────────┐ +│ industry 하드코딩 │ → │ 백엔드 modules 목록 │ → │ JSON 스키마 기반 │ +│ 매핑으로 모듈 결정 │ │ API에서 직접 수신 │ │ 동적 페이지 조립 │ +└─────────────────┘ └──────────────────────┘ └─────────────────────┘ +``` + +- **Phase 2**: `tenant.options.modules = ["production", "quality"]` 형태로 백엔드에서 명시적 모듈 목록 전달 → 업종 매핑 테이블 불필요 +- **Phase 3**: 각 모듈의 페이지 구성을 JSON 스키마로 정의 → 코드 변경 없이 테넌트별 화면 커스터마이징 diff --git a/scripts/verify-module-separation.sh b/scripts/verify-module-separation.sh new file mode 100755 index 00000000..df268a26 --- /dev/null +++ b/scripts/verify-module-separation.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# =================================================================== +# Module Separation Verification Script +# +# 공통 ERP → 테넌트 모듈 간 금지된 정적 import를 검사합니다. +# Phase 0에서 해소한 의존성이 다시 발생하지 않도록 CI에서 실행 가능. +# +# 사용법: bash scripts/verify-module-separation.sh +# 종료코드: 0 = 통과, 1 = 위반 발견 +# =================================================================== + +set -euo pipefail + +echo "=================================================" +echo " Module Separation Verification" +echo "=================================================" +echo "" + +# 테넌트 전용 경로 패턴 (from 'xxx' 또는 from "xxx" 형태로 검색) +TENANT_PATHS=( + "@/components/production/" + "@/components/quality/" + "@/components/business/construction/" + "@/components/vehicle-management/" +) + +# 공통 ERP 소스 디렉토리 (테넌트 페이지 제외) +COMMON_DIRS=( + "src/components/approval" + "src/components/accounting" + "src/components/auth" + "src/components/atoms" + "src/components/board" + "src/components/business/CEODashboard" + "src/components/business/DashboardSwitcher.tsx" + "src/components/clients" + "src/components/common" + "src/components/customer-center" + "src/components/document-system" + "src/components/hr" + "src/components/items" + "src/components/layout" + "src/components/material" + "src/components/molecules" + "src/components/organisms" + "src/components/orders" + "src/components/outbound" + "src/components/pricing" + "src/components/providers" + "src/components/reports" + "src/components/settings" + "src/components/stocks" + "src/components/templates" + "src/components/ui" + "src/lib" + "src/hooks" + "src/stores" + "src/contexts" +) + +VIOLATIONS=0 + +for dir in "${COMMON_DIRS[@]}"; do + # 디렉토리/파일이 없으면 스킵 + [ -e "$dir" ] || continue + + for tenant_path in "${TENANT_PATHS[@]}"; do + # 정적 import 검색 (dynamic import는 허용) + found=$(grep -rn "from ['\"]${tenant_path}" "$dir" \ + --include="*.ts" --include="*.tsx" 2>/dev/null \ + | grep -v "dynamic(" \ + | grep -v "// MODULE_SEPARATION_OK" \ + || true) + + if [ -n "$found" ]; then + echo "VIOLATION: $dir → $tenant_path" + echo "$found" + echo "" + VIOLATIONS=$((VIOLATIONS + 1)) + fi + done +done + +echo "=================================================" +if [ $VIOLATIONS -eq 0 ]; then + echo " PASSED: No forbidden imports found." + exit 0 +else + echo " FAILED: Found $VIOLATIONS forbidden import(s)." + echo "" + echo " 해결 방법:" + echo " - dynamic import (next/dynamic)로 교체" + echo " - @/lib/api/ 또는 @/interfaces/로 타입 이동" + echo " - @/components/document-system/으로 공유 모달 이동" + echo " - 불가피한 경우 // MODULE_SEPARATION_OK 주석 추가" + exit 1 +fi diff --git a/src/app/[locale]/(protected)/sales/order-management-sales/[id]/production-order/page.tsx b/src/app/[locale]/(protected)/sales/order-management-sales/[id]/production-order/page.tsx index b7e20aba..bf39bcda 100644 --- a/src/app/[locale]/(protected)/sales/order-management-sales/[id]/production-order/page.tsx +++ b/src/app/[locale]/(protected)/sales/order-management-sales/[id]/production-order/page.tsx @@ -16,6 +16,7 @@ import { useState, useEffect, useCallback } from "react"; import { useRouter, useParams } from "next/navigation"; +import { useModules } from "@/hooks/useModules"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { @@ -345,6 +346,24 @@ export default function ProductionOrderCreatePage() { const router = useRouter(); const params = useParams(); const orderId = params.id as string; + const { isEnabled, tenantIndustry } = useModules(); + + // 생산 모듈 비활성 시 접근 차단 (tenantIndustry 미설정 시 전부 허용) + if (tenantIndustry && !isEnabled('production')) { + return ( + +
+

생산관리 모듈이 활성화되어 있지 않습니다.

+ +
+
+ ); + } const [loading, setLoading] = useState(true); const [error, setError] = useState(null); diff --git a/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/[id]/page.tsx b/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/[id]/page.tsx index 0e0c97f8..1b0ec878 100644 --- a/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/[id]/page.tsx +++ b/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/[id]/page.tsx @@ -11,6 +11,7 @@ import { useState, useEffect } from "react"; import { useRouter, useParams } from "next/navigation"; +import { useModules } from "@/hooks/useModules"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; @@ -194,6 +195,24 @@ export default function ProductionOrderDetailPage() { const router = useRouter(); const params = useParams(); const orderId = params.id as string; + const { isEnabled, tenantIndustry } = useModules(); + + // 생산 모듈 비활성 시 접근 차단 (tenantIndustry 미설정 시 전부 허용) + if (tenantIndustry && !isEnabled('production')) { + return ( + +
+

생산관리 모듈이 활성화되어 있지 않습니다.

+ +
+
+ ); + } const [detail, setDetail] = useState(null); const [loading, setLoading] = useState(true); diff --git a/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/page.tsx b/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/page.tsx index da143646..1ac16634 100644 --- a/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/page.tsx +++ b/src/app/[locale]/(protected)/sales/order-management-sales/production-orders/page.tsx @@ -12,6 +12,7 @@ import { useState, useCallback } from "react"; import { useRouter } from "next/navigation"; +import { useModules } from "@/hooks/useModules"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; @@ -174,6 +175,23 @@ const TABLE_COLUMNS: TableColumn[] = [ export default function ProductionOrdersListPage() { const router = useRouter(); + const { isEnabled, tenantIndustry } = useModules(); + + // 생산 모듈 비활성 시 접근 차단 (tenantIndustry 미설정 시 전부 허용) + if (tenantIndustry && !isEnabled('production')) { + return ( +
+

생산관리 모듈이 활성화되어 있지 않습니다.

+ +
+ ); + } + const [stats, setStats] = useState({ total: 0, waiting: 0, diff --git a/src/components/business/construction/MODULE.md b/src/components/business/construction/MODULE.md new file mode 100644 index 00000000..b1498417 --- /dev/null +++ b/src/components/business/construction/MODULE.md @@ -0,0 +1,32 @@ +# Construction Module (건설관리) + +**Module ID**: `construction` +**Tenant**: Juil (주일건설) +**Route Prefixes**: `/construction` +**Component Count**: 161 files + +## Dependencies on Common ERP +- `@/lib/api/*` — Server actions, API client +- `@/components/ui/*` — UI primitives (shadcn/ui) +- `@/components/templates/*` — IntegratedListTemplateV2 등 +- `@/components/organisms/*` — PageLayout, PageHeader +- `@/hooks/*` — usePermission, useModules 등 +- `@/stores/authStore` — Tenant 정보 +- `@/components/common/*` — 공통 컴포넌트 + +## Exports to Common ERP +**NONE** — 건설 모듈은 독립적으로 작동. + +## Related Dashboard Sections +- `construction` (시공 현황) + +## Subdirectories +- `bidding/` — 입찰 관리 +- `contract/` — 계약 관리 +- `estimates/` — 견적 관리 +- `progress-billing/` — 기성 관리 +- `site-management/` — 현장 관리 +- `labor-management/` — 노무 관리 +- `item-management/` — 자재 관리 +- `partners/` — 협력업체 관리 +- 기타 20개 하위 도메인 diff --git a/src/components/production/MODULE.md b/src/components/production/MODULE.md new file mode 100644 index 00000000..98e75450 --- /dev/null +++ b/src/components/production/MODULE.md @@ -0,0 +1,25 @@ +# Production Module (생산관리) + +**Module ID**: `production` +**Tenant**: Kyungdong (경동 셔터 MES) +**Route Prefixes**: `/production` +**Component Count**: 56 files + +## Dependencies on Common ERP +- `@/lib/api/*` — Server actions, API client +- `@/components/ui/*` — UI primitives (shadcn/ui) +- `@/components/templates/*` — IntegratedListTemplateV2 등 +- `@/components/organisms/*` — PageLayout, PageHeader +- `@/hooks/*` — usePermission, useModules 등 +- `@/stores/authStore` — Tenant 정보 +- `@/stores/menuStore` — 사이드바 상태 + +## Exports to Common ERP +**NONE** — Phase 0에서 모든 교차 참조 해소 완료. +- 타입: `@/lib/api/production-orders/types.ts` (re-export) +- 서버 액션: `@/lib/api/production-orders/actions.ts` (async wrapper) +- 모달: `@/components/document-system/modals/` (dynamic import wrapper) + +## Related Dashboard Sections +- `production` (생산 현황) +- `shipment` (출고 현황) diff --git a/src/components/quality/MODULE.md b/src/components/quality/MODULE.md new file mode 100644 index 00000000..539e77cf --- /dev/null +++ b/src/components/quality/MODULE.md @@ -0,0 +1,21 @@ +# Quality Module (품질관리) + +**Module ID**: `quality` +**Tenant**: Kyungdong (경동 셔터 MES) +**Route Prefixes**: `/quality` +**Component Count**: 35 files + +## Dependencies on Common ERP +- `@/lib/api/*` — Server actions, API client +- `@/components/ui/*` — UI primitives (shadcn/ui) +- `@/components/templates/*` — IntegratedListTemplateV2 등 +- `@/components/organisms/*` — PageLayout, PageHeader +- `@/hooks/*` — usePermission, useModules 등 +- `@/stores/authStore` — Tenant 정보 + +## Exports to Common ERP +**NONE** — Phase 0에서 교차 참조 해소 완료. +- 모달: `@/components/document-system/modals/` (WorkLogModal — dynamic import) + +## Related Dashboard Sections +없음 (품질 대시보드 섹션은 아직 미구현) diff --git a/src/components/vehicle-management/MODULE.md b/src/components/vehicle-management/MODULE.md new file mode 100644 index 00000000..cce7d21d --- /dev/null +++ b/src/components/vehicle-management/MODULE.md @@ -0,0 +1,20 @@ +# Vehicle Management Module (차량관리) + +**Module ID**: `vehicle-management` +**Tenant**: Optional (경동 + 주일 공통 선택) +**Route Prefixes**: `/vehicle-management`, `/vehicle` +**Component Count**: 13 files + +## Dependencies on Common ERP +- `@/lib/api/*` — Server actions, API client +- `@/components/ui/*` — UI primitives (shadcn/ui) +- `@/components/templates/*` — IntegratedListTemplateV2 등 +- `@/components/organisms/*` — PageLayout, PageHeader +- `@/hooks/*` — usePermission, useModules 등 +- `@/stores/authStore` — Tenant 정보 + +## Exports to Common ERP +**NONE** + +## Related Dashboard Sections +없음 diff --git a/src/lib/api/production-orders/actions.ts b/src/lib/api/production-orders/actions.ts index e863b576..307927a2 100644 --- a/src/lib/api/production-orders/actions.ts +++ b/src/lib/api/production-orders/actions.ts @@ -11,7 +11,7 @@ import { getProductionOrders as _getProductionOrders, getProductionOrderStats as _getProductionOrderStats, getProductionOrderDetail as _getProductionOrderDetail, -} from '@/components/production/ProductionOrders/actions'; +} from '@/components/production/ProductionOrders/actions'; // MODULE_SEPARATION_OK — 공유 액션 래퍼 (Phase 0) import type { ProductionOrderListParams } from './types'; export async function getProductionOrders(params: ProductionOrderListParams) { diff --git a/src/lib/api/production-orders/types.ts b/src/lib/api/production-orders/types.ts index 95c61370..2ed15da6 100644 --- a/src/lib/api/production-orders/types.ts +++ b/src/lib/api/production-orders/types.ts @@ -19,4 +19,4 @@ export type { ApiProductionWorkOrder, ApiBomProcessGroup, ApiBomItem, -} from '@/components/production/ProductionOrders/types'; +} from '@/components/production/ProductionOrders/types'; // MODULE_SEPARATION_OK — 공유 인터페이스 (Phase 0) diff --git a/tsconfig.json b/tsconfig.json index 50296bbe..417c2930 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,6 +25,9 @@ "paths": { "@/*": [ "./src/*" + ], + "@modules/*": [ + "./src/modules/*" ] } },