diff --git a/claudedocs/명함추출로직.md b/claudedocs/명함추출로직.md
new file mode 100644
index 00000000..8c7c4db1
--- /dev/null
+++ b/claudedocs/명함추출로직.md
@@ -0,0 +1,367 @@
+# 명함 OCR 추출 로직 기술 문서
+
+## 개요
+
+명함 이미지를 업로드하면 Google Gemini Vision API를 통해 자동으로 정보를 추출하여 영업권 등록 폼에 자동 입력하는 시스템입니다.
+
+---
+
+## 시스템 아키텍처
+
+```
+┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ 클라이언트 │ │ MNG 서버 │ │ Gemini API │
+│ (Blade View) │ │ (Laravel) │ │ (Google) │
+└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
+ │ │ │
+ │ 1. 이미지 업로드 │ │
+ │ (Base64) │ │
+ ├──────────────────────>│ │
+ │ │ 2. Vision API 호출 │
+ │ ├──────────────────────>│
+ │ │ │
+ │ │ 3. JSON 응답 │
+ │ │<──────────────────────┤
+ │ 4. 추출 데이터 반환 │ │
+ │<──────────────────────┤ │
+ │ │ │
+ │ 5. 폼 필드 자동 입력 │ │
+ │ │ │
+```
+
+---
+
+## 파일 구조
+
+```
+/home/aweso/sam/mng/
+├── app/
+│ ├── Http/Controllers/
+│ │ ├── Api/
+│ │ │ └── BusinessCardOcrController.php # OCR API 엔드포인트
+│ │ └── System/
+│ │ └── AiConfigController.php # AI 설정 관리
+│ ├── Models/System/
+│ │ └── AiConfig.php # AI API 설정 모델
+│ └── Services/
+│ └── BusinessCardOcrService.php # Gemini Vision API 호출 서비스
+├── resources/views/
+│ ├── sales/prospects/
+│ │ └── create.blade.php # 영업권 등록 (드래그앤드롭 UI)
+│ └── system/ai-config/
+│ └── index.blade.php # AI 설정 관리 페이지
+└── routes/
+ └── web.php # 라우트 정의
+
+/home/aweso/sam/api/
+└── database/migrations/
+ └── 2026_01_27_100000_create_ai_configs_table.php # AI 설정 테이블
+```
+
+---
+
+## 데이터베이스 스키마
+
+### ai_configs 테이블
+
+| 컬럼 | 타입 | 설명 |
+|------|------|------|
+| id | BIGINT | PK |
+| name | VARCHAR(50) | 설정 이름 |
+| provider | VARCHAR(30) | 제공자 (gemini, claude, openai) |
+| api_key | VARCHAR(255) | API 키 (암호화 저장 권장) |
+| model | VARCHAR(100) | 모델명 (예: gemini-2.0-flash) |
+| base_url | VARCHAR(255) | API Base URL (NULL이면 기본값 사용) |
+| description | TEXT | 설명 |
+| is_active | BOOLEAN | 활성화 여부 (provider당 1개만 활성) |
+| options | JSON | 추가 옵션 |
+| created_at | TIMESTAMP | 생성일시 |
+| updated_at | TIMESTAMP | 수정일시 |
+| deleted_at | TIMESTAMP | 삭제일시 (소프트삭제) |
+
+---
+
+## API 엔드포인트
+
+### POST /api/business-card-ocr
+
+명함 이미지에서 정보를 추출합니다.
+
+**Request:**
+```json
+{
+ "image": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
+}
+```
+
+**Response (성공):**
+```json
+{
+ "ok": true,
+ "data": {
+ "company_name": "주식회사 샘플",
+ "ceo_name": "홍길동",
+ "business_number": "123-45-67890",
+ "contact_phone": "02-1234-5678",
+ "contact_email": "hong@sample.com",
+ "address": "서울시 강남구 테헤란로 123",
+ "position": "대표이사",
+ "department": "경영지원팀"
+ },
+ "raw_response": "{...}"
+}
+```
+
+**Response (실패):**
+```json
+{
+ "ok": false,
+ "error": "Gemini API 설정이 없습니다."
+}
+```
+
+---
+
+## 핵심 로직
+
+### 1. BusinessCardOcrService.php
+
+```php
+class BusinessCardOcrService
+{
+ public function extractFromImage(string $base64Image): array
+ {
+ // 1. 활성화된 Gemini 설정 조회
+ $config = AiConfig::getActiveGemini();
+
+ // 2. Gemini Vision API 호출
+ return $this->callGeminiVisionApi($config, $base64Image);
+ }
+
+ private function callGeminiVisionApi(AiConfig $config, string $base64Image): array
+ {
+ // API URL 구성
+ $url = "{$config->base_url}/models/{$config->model}:generateContent?key={$config->api_key}";
+
+ // Base64 이미지 데이터 처리
+ // data:image/jpeg;base64, 접두사 제거
+
+ // API 호출
+ $response = Http::timeout(30)->post($url, [
+ 'contents' => [[
+ 'parts' => [
+ ['inline_data' => ['mime_type' => $mimeType, 'data' => $imageData]],
+ ['text' => $prompt]
+ ]
+ ]],
+ 'generationConfig' => [
+ 'temperature' => 0.1,
+ 'responseMimeType' => 'application/json'
+ ]
+ ]);
+
+ // 응답 파싱 및 정규화
+ return $this->normalizeData($parsed);
+ }
+}
+```
+
+### 2. Gemini Vision API 프롬프트
+
+```
+이 명함 이미지에서 다음 정보를 추출해주세요.
+
+## 추출 항목
+1. company_name: 회사명/상호
+2. ceo_name: 대표자명/담당자명
+3. business_number: 사업자등록번호 (000-00-00000 형식)
+4. contact_phone: 연락처/전화번호
+5. contact_email: 이메일
+6. address: 주소
+7. position: 직책
+8. department: 부서
+
+## 규칙
+1. 정보가 없으면 빈 문자열("")로 응답
+2. 사업자번호는 10자리 숫자를 000-00-00000 형식으로 변환
+3. 전화번호는 하이픈 포함 형식 유지
+4. 한국어로 된 정보를 우선 추출
+
+## 출력 형식 (JSON)
+{
+ "company_name": "",
+ "ceo_name": "",
+ "business_number": "",
+ ...
+}
+```
+
+### 3. 데이터 정규화
+
+```php
+private function normalizeData(array $data): array
+{
+ // 사업자번호 정규화 (10자리 → 000-00-00000)
+ if (!empty($data['business_number'])) {
+ $digits = preg_replace('/\D/', '', $data['business_number']);
+ if (strlen($digits) === 10) {
+ $data['business_number'] = substr($digits, 0, 3) . '-'
+ . substr($digits, 3, 2) . '-'
+ . substr($digits, 5);
+ }
+ }
+
+ return [
+ 'company_name' => trim($data['company_name'] ?? ''),
+ 'ceo_name' => trim($data['ceo_name'] ?? ''),
+ // ... 기타 필드
+ ];
+}
+```
+
+---
+
+## 프론트엔드 (create.blade.php)
+
+### 드래그앤드롭 영역
+
+```html
+
+
명함 이미지를 드래그하거나 클릭하여 업로드
+
+
+
+
![]()
+
+```
+
+### JavaScript 처리 로직
+
+```javascript
+// 파일 처리
+async function handleFile(file) {
+ // 1. 이미지 미리보기
+ const reader = new FileReader();
+ reader.onload = async (e) => {
+ // 미리보기 표시
+ document.getElementById('ocr-preview-image').src = e.target.result;
+
+ // 2. OCR API 호출
+ showOcrLoading(true);
+ const response = await fetch('/api/business-card-ocr', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken },
+ body: JSON.stringify({ image: e.target.result })
+ });
+
+ const result = await response.json();
+
+ // 3. 폼 필드 자동 입력
+ if (result.ok) {
+ fillFormFields(result.data);
+ }
+ };
+ reader.readAsDataURL(file);
+}
+
+// 폼 필드 자동 입력 (하이라이트 효과 포함)
+function fillFormFields(data) {
+ const fieldMap = {
+ 'company_name': 'name',
+ 'ceo_name': 'ceo_name',
+ 'business_number': 'business_number',
+ // ...
+ };
+
+ for (const [key, fieldName] of Object.entries(fieldMap)) {
+ if (data[key]) {
+ const input = document.querySelector(`[name="${fieldName}"]`);
+ if (input) {
+ input.value = data[key];
+ // 하이라이트 효과
+ input.classList.add('bg-yellow-100');
+ setTimeout(() => input.classList.remove('bg-yellow-100'), 2000);
+ }
+ }
+ }
+}
+```
+
+---
+
+## AI 설정 관리
+
+### 라우트
+
+```php
+// routes/web.php
+Route::prefix('system')->name('system.')->group(function () {
+ Route::get('ai-config', [AiConfigController::class, 'index'])->name('ai-config.index');
+ Route::post('ai-config', [AiConfigController::class, 'store'])->name('ai-config.store');
+ Route::put('ai-config/{id}', [AiConfigController::class, 'update'])->name('ai-config.update');
+ Route::delete('ai-config/{id}', [AiConfigController::class, 'destroy'])->name('ai-config.destroy');
+ Route::post('ai-config/{id}/toggle', [AiConfigController::class, 'toggle'])->name('ai-config.toggle');
+ Route::post('ai-config/test', [AiConfigController::class, 'test'])->name('ai-config.test');
+});
+
+Route::post('api/business-card-ocr', [BusinessCardOcrController::class, 'process']);
+```
+
+### Provider별 기본 설정
+
+```php
+// AiConfig.php
+public const DEFAULT_BASE_URLS = [
+ 'gemini' => 'https://generativelanguage.googleapis.com/v1beta',
+ 'claude' => 'https://api.anthropic.com/v1',
+ 'openai' => 'https://api.openai.com/v1',
+];
+
+public const DEFAULT_MODELS = [
+ 'gemini' => 'gemini-2.0-flash',
+ 'claude' => 'claude-sonnet-4-20250514',
+ 'openai' => 'gpt-4o',
+];
+```
+
+---
+
+## 에러 처리
+
+| 상황 | 에러 메시지 | 대응 |
+|------|------------|------|
+| Gemini 설정 없음 | "Gemini API 설정이 없습니다" | AI 설정 페이지에서 설정 추가 |
+| API 호출 실패 | "AI API 호출 실패: {status}" | API 키/모델 확인 |
+| 연결 실패 | "AI API 연결 실패" | 네트워크/Base URL 확인 |
+| 응답 파싱 실패 | "AI 응답 파싱 실패" | 프롬프트 조정 필요 |
+| Rate Limit | 429 에러 | 잠시 후 재시도 |
+
+---
+
+## 보안 고려사항
+
+1. **API 키 보호**: `api_key` 컬럼 암호화 저장 권장
+2. **마스킹**: UI에서 API 키 앞 8자리만 표시
+3. **CSRF 보호**: 모든 POST 요청에 CSRF 토큰 포함
+4. **파일 검증**: 이미지 파일만 허용 (accept="image/*")
+
+---
+
+## 향후 개선 사항
+
+1. **Claude/OpenAI Vision 지원**: 현재 Gemini만 지원, 타 provider 확장 가능
+2. **배치 처리**: 여러 명함 동시 처리
+3. **OCR 결과 캐싱**: 동일 이미지 재처리 방지
+4. **API 키 암호화**: Laravel Crypt 활용
+
+---
+
+## 참고 자료
+
+- [Gemini API 문서](https://ai.google.dev/gemini-api/docs)
+- [Gemini Vision API](https://ai.google.dev/gemini-api/docs/vision)
+- API 키 파일 위치: `/home/aweso/sam/sales/apikey/gemini_api_key.txt`
+
+---
+
+*문서 작성일: 2026-01-27*
diff --git a/resources/views/system/ai-config/index.blade.php b/resources/views/system/ai-config/index.blade.php
index 5cb90d05..6f0b2378 100644
--- a/resources/views/system/ai-config/index.blade.php
+++ b/resources/views/system/ai-config/index.blade.php
@@ -55,6 +55,9 @@
max-height: 90vh;
overflow-y: auto;
}
+ .modal-overlay.hidden {
+ display: none !important;
+ }
@endpush
@@ -104,7 +107,7 @@
-