feat: CSP 다음/카카오 도메인 허용 + 입고 성적서 파일 백엔드 연동 + 팝업 이미지 중앙정렬

- middleware CSP: *.kakao.com, *.kakaocdn.net 추가 (다음 주소찾기 차단 해결)
- frame-src에 'self' 추가
- 공지 팝업 이미지 중앙정렬 ([&_img]:mx-auto)
- HR 사원관리, 결재, 품목, 생산 등 다수 개선
- API 에러 핸들링 및 JSON 파싱 안정화
This commit is contained in:
유병철
2026-03-11 22:32:58 +09:00
parent e9ac2470e1
commit ea6ca335f1
24 changed files with 625 additions and 139 deletions

View File

@@ -7,8 +7,9 @@ import type { AccountInfo, TermsAgreement, MarketingConsent } from './types';
const API_URL = process.env.NEXT_PUBLIC_API_URL;
/**
* 상대 경로를 절대 URL로 변환
* /storage/... 또는 1/temp/... → https://api.example.com/storage/tenants/...
* 상대 경로를 표시 가능한 URL로 변환
* R2 전환 후: /api/proxy/files/{id}/view 사용
* 레거시 경로는 그대로 반환 (표시 불가할 수 있음)
*/
function toAbsoluteUrl(path: string | undefined): string | undefined {
if (!path) return undefined;
@@ -16,12 +17,12 @@ function toAbsoluteUrl(path: string | undefined): string | undefined {
if (path.startsWith('http://') || path.startsWith('https://')) {
return path;
}
const apiUrl = process.env.NEXT_PUBLIC_API_URL || '';
// /storage/로 시작하면 그대로, 아니면 /storage/tenants/ 붙이기
if (path.startsWith('/storage/')) {
return `${apiUrl}${path}`;
// 프록시 경로면 그대로 반환
if (path.startsWith('/api/proxy/')) {
return path;
}
return `${apiUrl}/storage/tenants/${path}`;
// R2 전환 후 /storage/ 직접 접근 불가 — 경로만 보존
return path;
}
// ===== 계정 정보 조회 =====
@@ -142,12 +143,14 @@ export async function uploadProfileImage(formData: FormData): Promise<{
if (updateResult.__authError) return { success: false, __authError: true };
if (!updateResult.success) return { success: false, error: updateResult.error };
const storagePath = uploadedPath.startsWith('/storage/')
? uploadedPath
: `/storage/tenants/${uploadedPath}`;
// R2 전환: file_id 기반 프록시 경로 사용
const fileId = uploadResult.data.id;
const viewUrl = fileId
? `/api/proxy/files/${fileId}/view`
: uploadedPath;
return {
success: true,
data: { imageUrl: toAbsoluteUrl(storagePath) || '' },
data: { imageUrl: viewUrl },
};
}