Files
Gnuboard7/config/attachment.php
T
HeuJung 7b56d5f23a feat(core,board,ecommerce,page,ckeditor5,kginicis): 업로드 이미지 축소·로그인 2단계 인증 도입 + 파생 결함 수정
인터뷰에서 방향만 정하고 남겨 뒀던 후속 5건을 구현하고, 커밋 전 종합 점검에서
발견한 결함 2건을 함께 고쳤다.

기능 도입:
- 업로드 이미지 축소 — `upload.image_max_width` / `image_max_height` / `image_quality`
 는 저장·검증만 되고 리사이즈 코드가 0건이었다. 비율 유지, 상한 이내면 재인코딩하지
 않음(불필요한 화질 손실 방지), 한계 미설정이면 무동작(기존 사이트 이미지 보호).
 PNG·GIF·WebP 투명도 보존. 실패해도 업로드는 계속되고 원본이 저장된다.
- 로그인 2단계 인증 — `security.two_factor_auth` 는 설정 항목만 있고 구현도 화면
 컨트롤도 없었다. 코어 IDV 인프라를 재사용해 purpose `login` 을 추가하고, 비밀번호
 확인 통과 후 challenge 만 발행한다(토큰 미발급 + logout). `POST /api/auth/login/two-factor`
 가 코드를 확인해야 토큰이 나가며, 로그인과 같은 요청 제한을 적용한다. challenge 의
 purpose 를 대조해 다른 흐름의 challenge 로 로그인하는 것을 막는다. 코드 발송이
 실패하면 실패로 알린다 — 2단계를 건너뛰고 로그인시키면 통제가 조용히 열린다.

결함 수정:
- 게시글 수정 시 사용자 경로가 `attachment_ids` 를 Service 로 넘기지 않아, 검증과
 권한은 통과하고 200 을 받는데 첨부만 조용히 연결되지 않았다. 관리자 경로는 넘기고
 있어 같은 요청이 화면에 따라 다르게 동작했다.
- 설정 화면 라디오가 `pointer-events-none` + Label click 으로만 상태를 바꿔, 키보드
 방향키(change) 조작 시 화면 표시와 저장될 값이 어긋났다. 동일 패턴 4개 레이아웃
 12개 라디오에 change 액션을 부여하고 params 를 click 과 동일하게 고정한다.
- 주문완료 화면이 결제수단 확인보다 영수증 조회를 앞세워, PG 를 거치지 않는 주문에서도
 매번 404 요청이 나갔다.
- 개별 게시판 폼의 숫자 항목에 경계값 바인딩이 없어 환경설정 화면과 안내가 달랐다.

커밋 전 점검에서 발견:
- 2단계 인증이 반쪽으로 들어가 있었다. enum 에 case 만 추가하고 코어 purpose
 레지스트리와 ko/en 라벨을 빠뜨려, 목적 목록 API 에서 통째로 빠지고 `hasPurpose`
 가 false 였으며 라벨 대신 i18n 키 원문이 반환됐다. 관리자가 이 목적의 메시지
 템플릿·정책을 만들 수 없는 상태였다. 세 곳을 enum 기준으로 전수 대조하는 회귀
 테스트를 함께 둔다.
- 업로드 이미지 축소가 적용되지 않은 8번째 서비스(레이아웃 편집기 첨부)가 있었다.
 열거형 커버리지 테스트는 내 조사 결과를 green 으로 고정할 뿐 전수를 증명하지
 못한다 — 같은 규약을 조건으로 표현한 audit 룰이 첫 실행에서 검출했다.

재발 방지:
- audit 룰 `upload-service-image-resize` (신규 업로드 서비스의 축소 누락 검출)
- 트러블슈팅 사례 20 (코어 설정이 일부 경로에만 적용되는 증상의 진단 절차)
- `sirsoft-ckeditor5` 의 코어 최소 요구 버전을 7.0.6 으로 상향 (신설 클래스 의존)

공개 이슈: gnuboard/g7
2026-07-30 07:57:06 +09:00

81 lines
3.4 KiB
PHP

<?php
return [
/*
|--------------------------------------------------------------------------
| 스토리지 디스크
|--------------------------------------------------------------------------
|
| 첨부파일 저장에 사용할 디스크를 지정합니다.
| config/filesystems.php에 정의된 디스크 이름을 사용합니다.
|
*/
'disk' => env('ATTACHMENT_DISK', 'attachments'),
/*
|--------------------------------------------------------------------------
| 기본 권한 정책
|--------------------------------------------------------------------------
|
| 역할이 지정되지 않은 첨부파일의 기본 권한 정책을 설정합니다.
|
| 옵션:
| - 'public': 모든 인증된 사용자에게 전체 권한 허용
| - 'owner_only': 업로더와 관리자만 접근 가능
| - 'read_only': 모든 인증된 사용자에게 read만 허용
|
*/
'default_permission_policy' => env('ATTACHMENT_DEFAULT_POLICY', 'public'),
/*
|--------------------------------------------------------------------------
| 최대 파일 크기
|--------------------------------------------------------------------------
|
| 업로드 가능한 최대 파일 크기 (KB 단위 — Laravel `max:` 규칙과 동일 단위).
|
| 단위 규약: config/attachment.* 는 KB, 관리자 환경설정 upload.* 는 MB 다.
| MB → KB 변환은 SettingsServiceProvider::applyUploadConfig() 단 한 곳에서만 수행하며,
| 소비처(FormRequest 등)는 이 값을 변환 없이 그대로 사용한다.
|
*/
'max_file_size' => env('ATTACHMENT_MAX_FILE_SIZE', 10240),
/*
|--------------------------------------------------------------------------
| 허용 확장자
|--------------------------------------------------------------------------
|
| 업로드를 허용할 파일 확장자 목록 (소문자, 점 없이).
| 관리자 환경설정의 `upload.allowed_extensions` 가 저장되면 그 값으로 대체된다.
|
| 빈 배열은 "확장자 제한 없음" 을 의미한다 — 운영 중 예상치 못한 확장자로 업로드가
| 막히는 상황의 탈출구다. 확장은 `core.attachment.allowed_extensions` 필터 훅으로
| 목록을 조정할 수 있다.
|
*/
'allowed_extensions' => [
'jpg', 'jpeg', 'png', 'gif', 'webp',
'pdf', 'doc', 'docx', 'xls', 'xlsx', 'zip',
],
/*
|--------------------------------------------------------------------------
| 이미지 축소
|--------------------------------------------------------------------------
|
| 업로드된 이미지가 이 크기(픽셀)를 넘으면 비율을 유지한 채 축소한다.
| 관리자 환경설정의 `upload.image_max_width` / `image_max_height` / `image_quality`
| 가 저장되면 그 값으로 대체된다.
|
| null = 축소하지 않음. 기본값을 null 로 두는 이유는, 이 기능이 도입됐다는 이유만으로
| 기존 사이트의 업로드 이미지가 갑자기 줄어들지 않게 하기 위함이다.
|
| image_quality 는 1~100 이며 JPEG/WebP 에 그대로, PNG 에는 압축 레벨로 환산해 쓴다.
|
*/
'image_max_width' => env('ATTACHMENT_IMAGE_MAX_WIDTH'),
'image_max_height' => env('ATTACHMENT_IMAGE_MAX_HEIGHT'),
'image_quality' => env('ATTACHMENT_IMAGE_QUALITY', 85),
];