diff --git a/claudedocs/[PLAN-2026-01-23] vendor-credit-analysis-modal.md b/claudedocs/[PLAN-2026-01-23] vendor-credit-analysis-modal.md
new file mode 100644
index 00000000..18e65216
--- /dev/null
+++ b/claudedocs/[PLAN-2026-01-23] vendor-credit-analysis-modal.md
@@ -0,0 +1,103 @@
+# 신규 거래처 신용분석 모달
+
+## 개요
+- **목적**: 신규 거래처 등록 시 국가관리 API를 통해 받아온 기업 신용정보를 표시
+- **위치**: 거래처 등록 완료 후 모달로 표시
+- **현재 단계**: 목업 데이터로 UI 구현 (추후 API 연동)
+
+## 화면 구성
+
+### 1. 헤더
+- 로고 + "SAM 기업 신용분석 리포트"
+- 조회일시 표시
+
+### 2. 기업 정보
+- "신규거래 신용정보 조회" 뱃지
+- "기업 신용 분석" 제목
+- 사업자번호, 법인명 (대표자명), 평가기준일 정보
+
+### 3. 자료 효력기간 안내
+- 노란 배경의 알림 박스
+- 데이터 유효기간 및 면책 안내
+
+### 4. 종합 신용 신호등
+- 5단계 신호등 표시 (Level 1~5)
+- 현재 레벨 강조 (예: 양호 Level 4)
+- 신용 등급 설명 텍스트
+- "유료 상세 분석 제공받기" 버튼
+
+### 5. 신용 리스크 프로필
+- 오각형 레이더 차트
+ - 한국신용평가등급
+ - 금융 종합 위험도
+ - 매입 결제
+ - 매출 결제
+ - 저당권설정
+
+### 6. 신용 상세 정보
+- 신용채무정보 버튼
+- 신용등급추이정보 버튼
+- 정보 없음 안내 텍스트
+
+### 7. 하단 거래 승인 판정
+- 안전/위험 배지
+- 신용등급 (Level 1~5)
+- 거래 유형 (계속사업자/신규거래 등)
+- 외상 가능 여부
+- "거래 승인 완료" 버튼
+
+## 데이터 구조
+
+```typescript
+interface CreditAnalysisData {
+ // 기업 정보
+ businessNumber: string; // 사업자번호
+ companyName: string; // 법인명
+ representativeName: string; // 대표자명
+ evaluationDate: string; // 평가기준일
+
+ // 신용 등급
+ creditLevel: 1 | 2 | 3 | 4 | 5; // 1: 위험, 5: 최우량
+ creditStatus: '위험' | '주의' | '보통' | '양호' | '우량';
+
+ // 리스크 프로필 (0~100)
+ riskProfile: {
+ koreaCreditRating: number; // 한국신용평가등급
+ financialRisk: number; // 금융 종합 위험도
+ purchasePayment: number; // 매입 결제
+ salesPayment: number; // 매출 결제
+ mortgageSetting: number; // 저당권설정
+ };
+
+ // 거래 승인 판정
+ approval: {
+ safety: '안전' | '주의' | '위험';
+ level: number;
+ businessType: string; // 계속사업자, 신규거래 등
+ creditAvailable: boolean; // 외상 가능 여부
+ };
+}
+```
+
+## 파일 구조
+
+```
+src/components/accounting/VendorManagement/
+├── CreditAnalysisModal.tsx # 신용분석 모달 컴포넌트
+└── CreditAnalysisModal/
+ ├── index.tsx # 메인 모달
+ ├── CreditSignal.tsx # 신용 신호등 컴포넌트
+ ├── RiskRadarChart.tsx # 레이더 차트 컴포넌트
+ └── types.ts # 타입 정의
+
+src/app/[locale]/(protected)/dev/
+└── credit-analysis-test/
+ └── page.tsx # 테스트 페이지
+```
+
+## 구현 순서
+
+1. [x] 계획 md 파일 작성
+2. [ ] CreditAnalysisModal 컴포넌트 생성
+3. [ ] 테스트 페이지 생성
+4. [ ] dev/test-urls에 URL 추가
diff --git a/public/sam-logo.png b/public/sam-logo.png
new file mode 100644
index 00000000..a5cde92f
Binary files /dev/null and b/public/sam-logo.png differ
diff --git a/src/app/favicon.ico b/src/app/favicon.ico
deleted file mode 100644
index 718d6fea..00000000
Binary files a/src/app/favicon.ico and /dev/null differ
diff --git a/src/app/icon.svg b/src/app/icon.svg
new file mode 100644
index 00000000..a1b293f6
--- /dev/null
+++ b/src/app/icon.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/src/components/accounting/VendorManagement/CreditAnalysisModal/CreditAnalysisDocument.tsx b/src/components/accounting/VendorManagement/CreditAnalysisModal/CreditAnalysisDocument.tsx
new file mode 100644
index 00000000..0e8814ab
--- /dev/null
+++ b/src/components/accounting/VendorManagement/CreditAnalysisModal/CreditAnalysisDocument.tsx
@@ -0,0 +1,208 @@
+'use client';
+
+import { useState } from 'react';
+import { AlertTriangle, CheckCircle } from 'lucide-react';
+import { Button } from '@/components/ui/button';
+import { Badge } from '@/components/ui/badge';
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { cn } from '@/lib/utils';
+import { CreditSignal } from './CreditSignal';
+import { RiskRadarChart } from './RiskRadarChart';
+import type { CreditAnalysisData } from './types';
+import { CREDIT_LEVEL_CONFIG } from './types';
+
+interface CreditAnalysisDocumentProps {
+ data: CreditAnalysisData;
+ onApprove?: () => void;
+}
+
+export function CreditAnalysisDocument({
+ data,
+ onApprove,
+}: CreditAnalysisDocumentProps) {
+ const levelConfig = CREDIT_LEVEL_CONFIG[data.creditLevel];
+ const [activeTab, setActiveTab] = useState('shortTermOverdue');
+
+ // 탭 콘텐츠 렌더링
+ const renderTabContent = (content: string | null, emptyMessage: string) => {
+ if (content) {
+ return
{content}
;
+ }
+ return (
+
+ );
+ };
+
+ return (
+
+ {/* 헤더 */}
+
+
+
+ S
+
+
+ SAM 기업 신용분석 리포트
+
+
+
+ {data.evaluationDate}
+
+
+
+
+ {/* 기업 정보 */}
+
+
+ 신규거래 신용정보 조회
+
+
+ - 기업 신용 분석 -
+
+
+ 사업자번호: {data.businessNumber} | {data.companyName} | 거래기준일: {data.evaluationDate.split(' ')[0]}
+
+
+ 조회일자: {data.queryDate}
+
+
+
+ {/* 자료 효력기간 안내 */}
+
+
+
+
+
자료 효력기간 안내
+
+ 본 보고서(신용분석 6개월 {data.evaluationDate}) 자료는 기준일 당시의 시점이며, 이후 발생한 신용상태의 변동은 반영되지 않았음을 알려드립니다. 신용분석 결과에 의한 거래 관련 판단 및 결정에 대해서는 본사에서 책임지지 않습니다.
+
+
+
+
+
+ {/* 종합 신용 신호등 & 리스크 프로필 */}
+
+ {/* 종합 신용 신호등 */}
+
+
+ 종합 신용 신호등
+
+
+
+
+
+
+
+ {/* 신용 리스크 프로필 */}
+
+
+
+
+
+ {/* 신용 상세 정보 - 탭 */}
+
+
+ 신용 상세 정보
+
+
+
+
+ 단기연체정보
+
+
+ 신용도판단정보
+
+
+ 당좌거래정지
+
+
+ 법정관리/워크아웃
+
+
+
+ {renderTabContent(data.creditDetailTab.shortTermOverdue, '단기연체 정보가 없습니다')}
+
+
+ {renderTabContent(data.creditDetailTab.creditJudgment, '신용도판단 정보가 없습니다')}
+
+
+ {renderTabContent(data.creditDetailTab.checkingSuspension, '당좌거래정지 정보가 없습니다')}
+
+
+ {renderTabContent(data.creditDetailTab.courtManagement, '법정관리/워크아웃 정보가 없습니다')}
+
+
+
+
+ {/* 거래 승인 판정 */}
+
+
+
+
+
거래 승인 판정
+
+
+ {data.approval.safety}
+
+
+
+
+
+
신용등급
+
+ Level {data.approval.level}
+
+
+
+
+
거래
+
{data.approval.businessType}
+
+
+
+
외상가능
+
+ {data.approval.creditAvailable ? '가능' : '불가'}
+
+
+
+ {onApprove && (
+
+ )}
+
+
+
+ {/* 푸터 */}
+
+
SAM Intelligence
+
본 신용정보 보고서에 수록된 정보는 특정기업의 신용을 평가하는 자료로 활용될 수 있습니다
+
+
+
+ );
+}
diff --git a/src/components/accounting/VendorManagement/CreditAnalysisModal/CreditSignal.tsx b/src/components/accounting/VendorManagement/CreditAnalysisModal/CreditSignal.tsx
new file mode 100644
index 00000000..504a936e
--- /dev/null
+++ b/src/components/accounting/VendorManagement/CreditAnalysisModal/CreditSignal.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import { cn } from '@/lib/utils';
+import type { CreditLevel } from './types';
+import { CREDIT_LEVEL_CONFIG } from './types';
+
+interface CreditSignalProps {
+ level: CreditLevel;
+ taxStatus?: string;
+ showDescription?: boolean;
+}
+
+export function CreditSignal({
+ level,
+ taxStatus,
+ showDescription = false,
+}: CreditSignalProps) {
+ const config = CREDIT_LEVEL_CONFIG[level];
+
+ return (
+
+ {/* 신호등 */}
+
+ {[1, 2, 3, 4, 5].map((l) => (
+
+ ))}
+
+
+ {/* 등급 표시 */}
+
+
+ {config.status} (Level {level})
+
+ {taxStatus && (
+
+ {taxStatus}
+
+ )}
+
+
+ {/* 설명 */}
+ {showDescription && (
+
+ {config.description}
+
+ )}
+
+ );
+}
diff --git a/src/components/accounting/VendorManagement/CreditAnalysisModal/RiskRadarChart.tsx b/src/components/accounting/VendorManagement/CreditAnalysisModal/RiskRadarChart.tsx
new file mode 100644
index 00000000..9f5efc46
--- /dev/null
+++ b/src/components/accounting/VendorManagement/CreditAnalysisModal/RiskRadarChart.tsx
@@ -0,0 +1,94 @@
+'use client';
+
+import {
+ Radar,
+ RadarChart,
+ PolarGrid,
+ PolarAngleAxis,
+ PolarRadiusAxis,
+ ResponsiveContainer,
+} from 'recharts';
+import { cn } from '@/lib/utils';
+import type { RiskProfile, CreditDetailInfo } from './types';
+
+interface RiskRadarChartProps {
+ data: RiskProfile;
+ creditDetailInfo?: CreditDetailInfo;
+}
+
+const RISK_LABELS: Record = {
+ corporateRisk: '기업 리스크',
+ publicRecord: '공공기록',
+ stability: '안정성',
+ growth: '성장성',
+ overdueHistory: '연체이력',
+};
+
+const DETAIL_LABELS: Record = {
+ koreaCreditRating: '한국신용평가등급',
+ financialRisk: '금융 종합 위험도',
+ purchasePayment: '매입 결제',
+ salesPayment: '매출 결제',
+ mortgageSetting: '저당권설정',
+};
+
+export function RiskRadarChart({ data, creditDetailInfo }: RiskRadarChartProps) {
+ const chartData = Object.entries(data).map(([key, value]) => ({
+ subject: RISK_LABELS[key as keyof RiskProfile],
+ value,
+ fullMark: 100,
+ }));
+
+ return (
+
+
신용 리스크 프로필
+
+
+
+ {/* 레이더 차트 하단 상세 정보 */}
+ {creditDetailInfo && (
+
+ {Object.entries(creditDetailInfo).map(([key, value]) => (
+
+ {DETAIL_LABELS[key as keyof CreditDetailInfo]}
+
+ {value}
+
+
+ ))}
+
+ )}
+
+ );
+}
diff --git a/src/components/accounting/VendorManagement/CreditAnalysisModal/index.tsx b/src/components/accounting/VendorManagement/CreditAnalysisModal/index.tsx
new file mode 100644
index 00000000..5fd34384
--- /dev/null
+++ b/src/components/accounting/VendorManagement/CreditAnalysisModal/index.tsx
@@ -0,0 +1,38 @@
+'use client';
+
+import { DocumentViewer } from '@/components/document-system';
+import { CreditAnalysisDocument } from './CreditAnalysisDocument';
+import type { CreditAnalysisData } from './types';
+
+interface CreditAnalysisModalProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ data: CreditAnalysisData;
+ onApprove?: () => void;
+}
+
+export function CreditAnalysisModal({
+ open,
+ onOpenChange,
+ data,
+ onApprove,
+}: CreditAnalysisModalProps) {
+ return (
+
+
+
+ );
+}
+
+export { MOCK_CREDIT_DATA } from './types';
+export type { CreditAnalysisData } from './types';
diff --git a/src/components/accounting/VendorManagement/CreditAnalysisModal/types.ts b/src/components/accounting/VendorManagement/CreditAnalysisModal/types.ts
new file mode 100644
index 00000000..70fcad6f
--- /dev/null
+++ b/src/components/accounting/VendorManagement/CreditAnalysisModal/types.ts
@@ -0,0 +1,142 @@
+// ===== 기업 신용분석 데이터 타입 =====
+
+export type CreditLevel = 1 | 2 | 3 | 4 | 5;
+export type CreditStatus = '위험' | '주의' | '보통' | '양호' | '우량';
+export type SafetyLevel = '안전' | '주의' | '위험';
+export type RiskStatus = '우량' | '양호' | '보통' | '주의' | '위험';
+
+// 레이더 차트용 - 신용 리스크 프로필 (5각형)
+export interface RiskProfile {
+ corporateRisk: number; // 기업 리스크 (0~100)
+ publicRecord: number; // 공공기록 (0~100)
+ stability: number; // 안정성 (0~100)
+ growth: number; // 성장성 (0~100)
+ overdueHistory: number; // 연체이력 (0~100)
+}
+
+// 신호등 아래 표시될 상세 정보
+export interface CreditDetailInfo {
+ koreaCreditRating: RiskStatus; // 한국신용평가등급
+ financialRisk: RiskStatus; // 금융 종합 위험도
+ purchasePayment: RiskStatus; // 매입 결제
+ salesPayment: RiskStatus; // 매출 결제
+ mortgageSetting: RiskStatus; // 저당권설정
+}
+
+// 신용 상세 정보 탭 데이터
+export interface CreditDetailTabData {
+ shortTermOverdue: string | null; // 단기연체정보
+ creditJudgment: string | null; // 신용도판단정보
+ checkingSuspension: string | null; // 당좌거래정지
+ courtManagement: string | null; // 법정관리/워크아웃
+}
+
+export interface ApprovalInfo {
+ safety: SafetyLevel;
+ level: CreditLevel;
+ businessType: string; // 계속사업자, 신규거래 등
+ creditAvailable: boolean; // 외상 가능 여부
+}
+
+export interface CreditAnalysisData {
+ // 기업 정보
+ businessNumber: string; // 사업자번호
+ companyName: string; // 법인명
+ representativeName: string; // 대표자명
+ evaluationDate: string; // 평가기준일
+ queryDate: string; // 조회일자
+
+ // 신용 등급
+ creditLevel: CreditLevel;
+ creditStatus: CreditStatus;
+ taxStatus: string; // 국세청 상태 (예: "국세청 상태 기준")
+
+ // 리스크 프로필 (레이더 차트용)
+ riskProfile: RiskProfile;
+
+ // 신호등 아래 상세 정보
+ creditDetailInfo: CreditDetailInfo;
+
+ // 신용 상세 정보 탭 데이터
+ creditDetailTab: CreditDetailTabData;
+
+ // 거래 승인 판정
+ approval: ApprovalInfo;
+}
+
+// ===== 신용 레벨 설정 =====
+export const CREDIT_LEVEL_CONFIG: Record = {
+ 1: {
+ status: '위험',
+ color: 'text-red-600',
+ bgColor: 'bg-red-500',
+ description: '신용 위험 등급으로 거래 시 주의가 필요합니다.',
+ },
+ 2: {
+ status: '주의',
+ color: 'text-orange-600',
+ bgColor: 'bg-orange-500',
+ description: '신용 주의 등급으로 거래 조건 검토가 필요합니다.',
+ },
+ 3: {
+ status: '보통',
+ color: 'text-yellow-600',
+ bgColor: 'bg-yellow-500',
+ description: '신용 보통 등급으로 일반적인 거래가 가능합니다.',
+ },
+ 4: {
+ status: '양호',
+ color: 'text-green-600',
+ bgColor: 'bg-green-500',
+ description: '신용 양호 등급으로 안정적인 거래가 가능합니다.',
+ },
+ 5: {
+ status: '우량',
+ color: 'text-blue-600',
+ bgColor: 'bg-blue-500',
+ description: '신용 우량 등급으로 최상의 거래 조건이 가능합니다.',
+ },
+};
+
+// ===== 목업 데이터 =====
+export const MOCK_CREDIT_DATA: CreditAnalysisData = {
+ businessNumber: '514-87-00635',
+ companyName: '(주)한가 양산공장',
+ representativeName: '홍길동',
+ evaluationDate: '2026-01-22 21:05:04',
+ queryDate: '2026-01-23 09:30:00',
+ creditLevel: 4,
+ creditStatus: '양호',
+ taxStatus: '국세청 상태 기준',
+ riskProfile: {
+ corporateRisk: 80,
+ publicRecord: 75,
+ stability: 85,
+ growth: 70,
+ overdueHistory: 90,
+ },
+ creditDetailInfo: {
+ koreaCreditRating: '양호',
+ financialRisk: '양호',
+ purchasePayment: '양호',
+ salesPayment: '양호',
+ mortgageSetting: '양호',
+ },
+ creditDetailTab: {
+ shortTermOverdue: null,
+ creditJudgment: null,
+ checkingSuspension: null,
+ courtManagement: null,
+ },
+ approval: {
+ safety: '안전',
+ level: 4,
+ businessType: '계속사업자',
+ creditAvailable: true,
+ },
+};
diff --git a/src/components/accounting/VendorManagement/VendorDetail.tsx b/src/components/accounting/VendorManagement/VendorDetail.tsx
index f5e6e78e..64dd70b2 100644
--- a/src/components/accounting/VendorManagement/VendorDetail.tsx
+++ b/src/components/accounting/VendorManagement/VendorDetail.tsx
@@ -8,6 +8,7 @@ import { toast } from 'sonner';
import { getClientById, createClient, updateClient, deleteClient } from './actions';
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
import { vendorConfig } from './vendorConfig';
+import { CreditAnalysisModal, MOCK_CREDIT_DATA } from './CreditAnalysisModal';
// 필드명 매핑
const FIELD_NAME_MAP: Record = {
@@ -145,6 +146,9 @@ export function VendorDetail({ mode, vendorId }: VendorDetailProps) {
// 새 메모 입력
const [newMemo, setNewMemo] = useState('');
+ // 신용분석 모달
+ const [isCreditModalOpen, setIsCreditModalOpen] = useState(false);
+
// Validation 함수
const validateForm = useCallback(() => {
const errors: Record = {};
@@ -478,8 +482,17 @@ export function VendorDetail({ mode, vendorId }: VendorDetailProps) {
{/* 신용/거래 정보 */}
-
+
신용/거래 정보
+ {isViewMode && (
+
+ )}
{renderSelectField('신용등급', 'creditRating', formData.creditRating, CREDIT_RATING_SELECTOR_OPTIONS)}
@@ -635,16 +648,25 @@ export function VendorDetail({ mode, vendorId }: VendorDetailProps) {
};
return (
- }
- itemId={vendorId}
- isLoading={isLoading}
- onSubmit={handleSubmit}
- onDelete={vendorId ? handleDelete : undefined}
- renderView={() => renderFormContent()}
- renderForm={() => renderFormContent()}
- />
+ <>
+ }
+ itemId={vendorId}
+ isLoading={isLoading}
+ onSubmit={handleSubmit}
+ onDelete={vendorId ? handleDelete : undefined}
+ renderView={() => renderFormContent()}
+ renderForm={() => renderFormContent()}
+ />
+
+ {/* 신용분석 모달 */}
+
+ >
);
}
diff --git a/src/components/accounting/VendorManagement/VendorDetailClient.tsx b/src/components/accounting/VendorManagement/VendorDetailClient.tsx
index 4be256e3..c12dd95d 100644
--- a/src/components/accounting/VendorManagement/VendorDetailClient.tsx
+++ b/src/components/accounting/VendorManagement/VendorDetailClient.tsx
@@ -20,6 +20,7 @@ import {
} from '@/components/ui/select';
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
import { vendorConfig } from './vendorConfig';
+import { CreditAnalysisModal, MOCK_CREDIT_DATA } from './CreditAnalysisModal';
import type { Vendor, VendorMemo } from './types';
import {
VENDOR_CATEGORY_SELECTOR_OPTIONS,
@@ -113,6 +114,9 @@ export function VendorDetailClient({ mode, vendorId, initialData }: VendorDetail
// 새 메모 입력
const [newMemo, setNewMemo] = useState('');
+ // 신용분석 모달
+ const [isCreditModalOpen, setIsCreditModalOpen] = useState(false);
+
// 상세/수정 모드에서 로고 목데이터 초기화
useEffect(() => {
if (initialData && !formData.logoUrl) {
@@ -428,8 +432,15 @@ export function VendorDetailClient({ mode, vendorId, initialData }: VendorDetail
{/* 신용/거래 정보 */}
-
+
신용/거래 정보
+
{renderSelectField('신용등급', 'creditRating', formData.creditRating, CREDIT_RATING_SELECTOR_OPTIONS)}
@@ -549,15 +560,24 @@ export function VendorDetailClient({ mode, vendorId, initialData }: VendorDetail
};
return (
- }
- itemId={vendorId}
- onSubmit={handleSubmit}
- onDelete={vendorId ? handleDelete : undefined}
- renderView={() => renderFormContent()}
- renderForm={() => renderFormContent()}
- />
+ <>
+ }
+ itemId={vendorId}
+ onSubmit={handleSubmit}
+ onDelete={vendorId ? handleDelete : undefined}
+ renderView={() => renderFormContent()}
+ renderForm={() => renderFormContent()}
+ />
+
+ {/* 신용분석 모달 */}
+
+ >
);
}
diff --git a/src/layouts/AuthenticatedLayout.tsx b/src/layouts/AuthenticatedLayout.tsx
index 246d5cbc..da33f9f8 100644
--- a/src/layouts/AuthenticatedLayout.tsx
+++ b/src/layouts/AuthenticatedLayout.tsx
@@ -4,6 +4,7 @@ import { useMenuStore } from '@/store/menuStore';
import type { SerializableMenuItem } from '@/store/menuStore';
import type { MenuItem } from '@/store/menuStore';
import { useRouter, usePathname } from 'next/navigation';
+import Image from 'next/image';
import { useEffect, useState, useMemo, useCallback } from 'react';
import {
Menu,
@@ -572,8 +573,8 @@ export default function AuthenticatedLayout({ children }: AuthenticatedLayoutPro
onClick={handleGoHome}
title="대시보드로 이동"
>
-
-
S
+
+
SAM
@@ -830,8 +831,8 @@ export default function AuthenticatedLayout({ children }: AuthenticatedLayoutPro
onClick={handleGoHome}
title="대시보드로 이동"
>
-