# AI 및 스토리지 설정 기술문서

> 최종 업데이트: 2026-03-03

## 개요

SAM MNG 시스템의 AI API 및 클라우드 스토리지(GCS) 설정을 관리하는 기능입니다.
관리자 UI에서 설정하거나, `.env` 환경변수로 설정할 수 있습니다.

**접근 경로**: 시스템 관리 > AI 설정 (`/system/ai-config`)

---

## 지원 Provider

### AI Provider
| Provider | 용도 | 기본 모델 |
|----------|------|----------|
| `gemini` | Google Gemini (명함 OCR, AI 어시스턴트) | gemini-2.5-flash |
| `claude` | Anthropic Claude | claude-sonnet-4-20250514 |
| `openai` | OpenAI GPT | gpt-4o |

### Storage Provider
| Provider | 용도 |
|----------|------|
| `gcs` | Google Cloud Storage (음성 녹음 백업) |

---

## 데이터베이스 구조

### 테이블: `ai_configs`

```sql
CREATE TABLE ai_configs (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,           -- 설정 이름 (예: "Production Gemini")
    provider VARCHAR(20) NOT NULL,       -- gemini, claude, openai, gcs
    api_key VARCHAR(255) NOT NULL,       -- API 키 (GCS는 'gcs_service_account')
    model VARCHAR(100) NOT NULL,         -- 모델명 (GCS는 '-')
    base_url VARCHAR(255) NULL,          -- 커스텀 Base URL
    description TEXT NULL,               -- 설명
    is_active BOOLEAN DEFAULT FALSE,     -- 활성화 여부 (provider당 1개만)
    options JSON NULL,                   -- 추가 옵션 (아래 참조)
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    deleted_at TIMESTAMP NULL            -- Soft Delete
);
```

### options JSON 구조

**AI Provider (Gemini Vertex AI)**:
```json
{
    "auth_type": "vertex_ai",
    "project_id": "my-gcp-project",
    "region": "us-central1",
    "service_account_path": "/var/www/sales/apikey/google_service_account.json"
}
```

**AI Provider (API Key)**:
```json
{
    "auth_type": "api_key"
}
```

**GCS Provider**:
```json
{
    "bucket_name": "my-bucket-name",
    "service_account_path": "/var/www/sales/apikey/google_service_account.json",
    "service_account_json": { ... }  // 또는 JSON 직접 입력
}
```

---

## 설정 우선순위

### GCS 설정 우선순위

```
1. DB 설정 (ai_configs 테이블의 활성화된 gcs provider)
   ↓ 없으면
2. 환경변수 (.env의 GCS_BUCKET_NAME, GCS_SERVICE_ACCOUNT_PATH)
   ↓ 없으면
3. 레거시 파일 (/sales/apikey/gcs_config.txt, google_service_account.json)
```

### AI 설정 우선순위

```
1. DB 설정 (ai_configs 테이블의 활성화된 provider)
   ↓ 없으면
2. 환경변수 (.env의 GEMINI_API_KEY 등)
   ↓ 없으면
3. 레거시 파일
```

---

## 환경변수 설정 (.env)

### GCS 설정
```env
# Google Cloud Storage (음성 녹음 백업)
GCS_BUCKET_NAME=your-bucket-name
GCS_SERVICE_ACCOUNT_PATH=/var/www/sales/apikey/google_service_account.json
GCS_USE_DB_CONFIG=true  # false면 DB 설정 무시, .env만 사용
```

### AI 설정 (참고)
```env
# Google Gemini API
GEMINI_API_KEY=your-api-key
GEMINI_PROJECT_ID=your-project-id
```

---

## 관련 파일 목록

### 모델
| 파일 | 설명 |
|------|------|
| `app/Models/System/AiConfig.php` | AI 설정 Eloquent 모델 |

### 컨트롤러
| 파일 | 설명 |
|------|------|
| `app/Http/Controllers/System/AiConfigController.php` | CRUD + 연결 테스트 |

### 서비스
| 파일 | 설명 |
|------|------|
| `app/Services/GoogleCloudStorageService.php` | GCS 업로드/다운로드/삭제 |
| `app/Services/GeminiService.php` | Gemini API 호출 (명함 OCR 등) |

### 설정
| 파일 | 설명 |
|------|------|
| `config/gcs.php` | GCS 환경변수 설정 |

### 뷰
| 파일 | 설명 |
|------|------|
| `resources/views/system/ai-config/index.blade.php` | AI 설정 관리 페이지 |

### 라우트
```php
// routes/web.php
Route::prefix('system')->name('system.')->group(function () {
    Route::resource('ai-config', AiConfigController::class)->except(['show', 'create', 'edit']);
    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('ai-config/test-gcs', [AiConfigController::class, 'testGcs'])->name('ai-config.test-gcs');
});
```

---

## 주요 메서드

### AiConfig 모델

```php
// Provider별 활성 설정 조회
AiConfig::getActiveGemini();   // ?AiConfig
AiConfig::getActiveClaude();   // ?AiConfig
AiConfig::getActiveGcs();      // ?AiConfig
AiConfig::getActive('openai'); // ?AiConfig

// GCS 전용 메서드
$config->getBucketName();           // ?string
$config->getServiceAccountJson();   // ?array
$config->getServiceAccountPath();   // ?string
$config->isGcs();                   // bool

// Vertex AI 전용 메서드
$config->isVertexAi();      // bool
$config->getProjectId();    // ?string
$config->getRegion();       // string (기본: us-central1)
```

### GoogleCloudStorageService

```php
$gcs = new GoogleCloudStorageService();

// 사용 가능 여부
$gcs->isAvailable();  // bool

// 설정 소스 확인
$gcs->getConfigSource();  // 'db' | 'env' | 'legacy' | 'none'

// 파일 업로드
$gcsUri = $gcs->upload($localPath, $objectName);  // 'gs://bucket/object' | null

// 서명된 다운로드 URL (60분 유효)
$url = $gcs->getSignedUrl($objectName, 60);  // string | null

// 파일 삭제
$gcs->delete($objectName);  // bool
```

---

## UI 구조

### 탭 구성
- **AI 설정 탭**: Gemini, Claude, OpenAI 설정 관리
- **스토리지 설정 탭**: GCS 설정 관리

### 기능
- 설정 추가/수정/삭제
- 활성화/비활성화 토글 (provider당 1개만 활성화)
- 연결 테스트

---

## 사용 예시

### GCS 업로드 (ConsultationController)

```php
use App\Services\GoogleCloudStorageService;

public function uploadAudio(Request $request)
{
    // 파일 저장
    $path = $file->store("tenant/consultations/{$tenantId}");
    $fullPath = storage_path('app/' . $path);

    // 10MB 이상이면 GCS에도 업로드
    if ($file->getSize() > 10 * 1024 * 1024) {
        $gcs = new GoogleCloudStorageService();
        if ($gcs->isAvailable()) {
            $gcsUri = $gcs->upload($fullPath, "consultations/{$tenantId}/" . basename($path));
        }
    }
}
```

### 명함 OCR (GeminiService)

```php
use App\Services\GeminiService;

$gemini = new GeminiService();
$result = $gemini->extractBusinessCard($imagePath);
```

---

## 배포 가이드

### 서버 최초 설정

1. `.env` 파일에 GCS 설정 추가:
   ```env
   GCS_BUCKET_NAME=production-bucket
   GCS_SERVICE_ACCOUNT_PATH=/var/www/sales/apikey/google_service_account.json
   ```

2. 서비스 계정 JSON 파일 배치:
   ```
   /var/www/sales/apikey/google_service_account.json
   ```

3. 설정 캐시 갱신:
   ```bash
   docker exec sam-mng-1 php artisan config:cache
   ```

### 이후 배포
- 코드 push만으로 동작 (설정 변경 불필요)
- UI에서 오버라이드하고 싶을 때만 DB 설정 사용

---

## 트러블슈팅

### GCS 업로드 실패

1. **설정 확인**:
   ```php
   $gcs = new GoogleCloudStorageService();
   dd($gcs->isAvailable(), $gcs->getConfigSource(), $gcs->getBucketName());
   ```

2. **로그 확인**:
   ```bash
   docker exec sam-mng-1 tail -f storage/logs/laravel.log | grep GCS
   ```

3. **일반적인 원인**:
   - 서비스 계정 파일 경로 오류
   - 서비스 계정에 Storage 권한 없음
   - 버킷 이름 오타

### AI API 연결 실패

1. **API 키 확인**: UI에서 "테스트" 버튼 클릭
2. **모델명 확인**: provider별 지원 모델 확인
3. **할당량 확인**: Google Cloud Console에서 API 할당량 확인

---

## 레거시 파일 위치 (참고)

Docker 컨테이너 내부 경로:
```
/var/www/sales/apikey/
├── gcs_config.txt              # bucket_name=xxx
├── google_service_account.json # GCP 서비스 계정 키
└── gemini_api_key.txt          # Gemini API 키 (레거시)
```

호스트 경로 (mng 기준):
```
../sales/apikey/
```
