# 절곡품 관리 MNG→API 연동 오류 수정 **날짜:** 2026-03-21 **작업자:** Claude Code (R&D실) ## 변경 개요 다른 개발자가 작성한 절곡품(Bending) 관련 컨트롤러에서 3가지 문제를 수정했다: 1. Docker 환경에서 `API_INTERNAL_URL` 미적용으로 500 에러 발생 2. API 화이트리스트 미등록으로 Bearer 토큰 없이 호출 시 401 에러 발생 3. API 연결 실패 시 사용자에게 안내 메시지 없이 "데이터가 없습니다"만 표시 ## 수정 1: internal_url 미적용 (MNG) ### 원인 MNG에서 API 호출 시 `config('services.api.base_url')` (`https://api.sam.kr`)만 사용하고, Docker 내부 통신용 `internal_url` 분기 처리가 없었다. | 환경 | 사용할 URL | 이유 | |------|-----------|------| | Docker (로컬) | `API_INTERNAL_URL` (`https://nginx`) | 컨테이너 간 내부 통신, `api.sam.kr` DNS 해석 불가 | | 서버 (개발/운영) | `API_BASE_URL` | 직접 도메인 접근 가능 | ### 수정 파일 (MNG) | 파일 | 변경 내용 | |------|----------| | `app/Http/Controllers/BendingBaseController.php` | `api()` 메서드에 `internal_url` + `Host` 헤더 분기 추가 | | `app/Http/Controllers/BendingProductController.php` | `api()` 메서드에 `internal_url` + `Host` 헤더 분기 추가 | | `app/Http/Controllers/FileViewController.php` | `show()` 메서드에 `internal_url` 분기 추가 | | `app/Http/Controllers/DocumentTemplateController.php` | `getPresignedUrlFromApi()`, `getPresignedUrlByPath()` 분기 추가 | ### 수정 패턴 기존 `FormulaApiService::resolveApiConnection()` 패턴을 참고: ```php $baseUrl = config('services.api.base_url', 'https://api.sam.kr'); $internalUrl = config('services.api.internal_url'); $headers = [...]; if ($internalUrl) { $headers['Host'] = parse_url($baseUrl, PHP_URL_HOST) ?: 'api.sam.kr'; $baseUrl = $internalUrl; } ``` --- ## 수정 2: API 화이트리스트 미등록 (API) ### 원인 `ApiKeyMiddleware`의 `allowWithoutAuth` 화이트리스트에 절곡품 관련 라우트가 없어서, MNG에서 Bearer 토큰 없이 호출하면 401 Unauthorized가 반환되었다. ### 수정 파일 (API) | 파일 | 변경 내용 | |------|----------| | `app/Http/Middleware/ApiKeyMiddleware.php` | `bending-items/*`, `guiderail-models/*`, `items/*/files`, `files/*/presigned-url` 화이트리스트 추가 | | `app/Http/Resources/Api/V1/BendingItemResource.php` | `presignedUrl()` 호출 시 S3 미설정 환경 에러 try-catch 처리 | --- ## 수정 3: API 오류 시 안내 메시지 (MNG) ### 원인 API 호출 실패 시 빈 데이터를 반환하여 "데이터가 없습니다"만 표시되었고, 사용자가 원인을 알 수 없었다. ### 수정 파일 (MNG) | 파일 | 변경 내용 | |------|----------| | `app/Http/Controllers/BendingBaseController.php` | API 응답 상태별 에러 메시지 분기 | | `app/Http/Controllers/BendingProductController.php` | 동일 패턴 적용 | | `resources/views/bending/base/partials/table.blade.php` | 에러 안내 UI 추가 | | `resources/views/bending/products/partials/table.blade.php` | 에러 안내 UI 추가 | ### 안내 메시지 분기 | API 응답 | 표시 메시지 | |----------|-----------| | 연결 불가 (timeout/connection error) | "API 서버에 연결할 수 없습니다. API 서비스 상태를 확인해 주세요." | | 401 Unauthorized | "API 인증이 필요합니다. SAM 서비스에 로그인하여 API를 연결해 주세요." | | 403 Forbidden | "API 접근 권한이 없습니다. 관리자에게 문의해 주세요." | | 기타 HTTP 에러 | "API 오류가 발생했습니다. (HTTP {상태코드})" | | 정상 200 + 데이터 없음 | "데이터가 없습니다." | --- ## 수정 4: Canvas 편집기 R2 이미지 CORS 에러 (MNG) ### 원인 절곡품 전개도 편집기(Canvas Editor)에서 이미지를 로드할 때: 1. `fabric.Image.fromURL`에 `crossOrigin: 'anonymous'` 설정 2. `/files/{id}/view`가 R2 presigned URL로 redirect 3. R2 버킷에 CORS 허용 설정이 없어 브라우저가 차단 4. Canvas가 "tainted" 상태가 되어 `toDataURL()` 실패 ### 수정 파일 (MNG) | 파일 | 변경 내용 | |------|----------| | `app/Http/Controllers/FileViewController.php` | `proxy()` 메서드 추가 — R2 이미지를 서버에서 다운로드 후 같은 도메인으로 스트리밍 | | `routes/web.php` | `/files/{id}/proxy` 라우트 추가 | | `public/js/canvas-editor.js` | `fabric.Image.fromURL`에 `crossOrigin: 'anonymous'` 옵션 추가 | | `resources/views/bending/base/form.blade.php` | `` 태그에 `data-proxy-url` 속성 추가, Canvas 편집기에서 프록시 URL 사용 | | `resources/views/bending/products/form.blade.php` | 동일 패턴 적용 | ### 동작 원리 - 일반 `` 표시: `/files/{id}/view` → R2 redirect (CORS 불필요, 빠름) - Canvas 편집기: `/files/{id}/proxy` → MNG 서버가 R2에서 다운로드 후 스트리밍 (같은 도메인, CORS 무관) ### 로컬 `.env` 변경 API `.env`에 Cloudflare R2 접속 정보 추가 (개발서버와 동일): ``` R2_ACCESS_KEY_ID=cecd4d4c... R2_SECRET_ACCESS_KEY=f20136ec... R2_BUCKET=sam R2_ENDPOINT=https://caf8dcb2c4ea443018ee5e7a7421db0e.r2.cloudflarestorage.com R2_REGION=auto ``` --- ## 신규 API 호출 코드 작성 시 필수 규칙 MNG에서 API를 호출하는 코드를 새로 작성할 때: ``` 필수 config('services.api.internal_url') 확인 후 분기 처리 필수 internal_url 사용 시 Host 헤더에 base_url의 도메인 전달 필수 MNG에서 Bearer 없이 호출하려면 API 화이트리스트에 라우트 추가 권장 FormulaApiService::resolveApiConnection() 참조 권장 API 실패 시 사용자에게 구체적인 안내 메시지 표시 권장 Canvas에서 외부 이미지 사용 시 프록시(/files/{id}/proxy) 경유 ``` ## 테스트 체크리스트 - [x] 로컬 Docker에서 `/bending/base` 페이지 정상 로드 (266건) - [x] 로컬 Docker에서 `/bending/products` 페이지 정상 로드 - [x] API 미인증 시 안내 메시지 표시 확인 - [x] Canvas 편집기 이미지 로드 및 toDataURL 정상 동작 - [x] pint 코드 스타일 검사 통과 ## 관련 문서 - `api/app/Http/Middleware/ApiKeyMiddleware.php` — 화이트리스트 관리 - `mng/config/services.php` — `services.api.base_url`, `services.api.internal_url` 설정 - `mng/app/Services/FormulaApiService.php` — `resolveApiConnection()` 참조 구현