Tailwind가 프로젝트에서 빠진 뒤에도 클래스만 남아 아무 스타일도 받지 못하던 자리들이
있었고, 전역 스피너는 만들어만 두고 어디서도 호출하지 않았다. 두 손질이 같은 파일들을
건드려 한 커밋으로 둔다.
Tailwind 제거:
- components/ui의 옛 Tailwind 레이어 16개 삭제. 그중 field·icon-button만 실제로 쓰여
각각 FoxTextArea·FoxFormLabel과 @fox 아이콘 버튼 마크업으로 옮기고 지웠다.
- error.tsx 다섯 곳이 같은 모양이라 PageError로 모은다(PageLoading과 같은 이유).
- 홈·Empty 레이아웃·게시판 첨부 링크는 module.scss로, 행 관리 버튼 묶음은 FoxButtonGroup로.
- 테마 토글은 FoxIconButton을 쓰지 못한다 — label이 필수라 aria-label이 늘 붙고, 그러면
테마별로 바뀌는 안쪽 글자를 스크린리더가 읽지 못한다. @fox 아이콘 버튼의 마크업 계약을
그대로 따라 같은 스타일을 받게 했다.
스피너 호출:
- useBlockingAction — 스피너를 켠 채 도는 transition. 삭제처럼 확인 얼럿이 닫힌 뒤
진행돼 표시가 행 아이콘 하나뿐이던 자리 11곳에 붙였다. 버튼이 스스로 "저장 중"을
보여주는 자리(중복확인·주소검색·엑셀 업로드)는 그대로 뒀다.
- 스피너 막도 토스트와 같은 이유로 popover(top layer)에 얹는다 — 모달 안에서 시작한
동작도 덮어야 한다.
- loading.tsx를 (basic) 한 곳으로 모은다. 다섯 화면에만 있던 것을 모든 하위 화면이
받도록 하고, 새 화면을 추가해도 자동으로 따라오게 한다.
Co-Authored-By: Claude Opus 5
폼 맨 아래 FoxHelperText에 있던 문구를 토스트로 올린다 — 등록 폼이 길어서 스크롤 밖에
있으면 저장이 왜 안 됐는지 보이지 않았다. 칸별 오류는 해당 입력칸에 그대로 둔다.
메시지도 백엔드 사유를 그대로 쓴다(형제 화면의 failureMessage와 같은 방식) — 고정 문구는
"저장하지 못했습니다"밖에 알려 주지 못했다.
Co-Authored-By: Claude Opus 5
백엔드가 중복 로그인 감지를 넣으면서, 내 토큰이 밀리면 이후 모든 요청이
403 + code 905(만료된 토큰입니다)로 떨어진다(JwtAuthenticationFilter).
어느 화면·어느 API에서 걸리든 같은 결말이어야 해서 backendFetch 한 곳에서
처리한다.
- 905/904를 받으면 /logout/revoked로 보낸다. 렌더 중에는 쿠키를 지울 수 없어
라우트 핸들러에서 세션을 파기하고 /login으로 안내와 함께 되돌린다.
- redirect()는 예외로 던져지므로 Server Action의 catch가 삼키면 안 된다.
저장소를 호출하는 catch에 unstable_rethrow를 넣어 통과시킨다.
- 그 경로는 쿠키가 이미 없어도 지나가야 안내가 유지돼 proxy 공개 경로에 넣는다.
Co-Authored-By: Claude Opus 5
기획 MCH_002_p ③. 버튼을 누른 순간 스크립트를 한 번만 받아 창을 연다 — 자주 열리는
화면이 아니라 모든 페이지가 이 30KB를 지고 다닐 이유가 없다. 도로명/지번은 사용자가
고른 표기를 그대로 쓰고, 우편번호(frcsPostZip)까지 함께 채운다.
좌표는 이 서비스가 주지 않는다. 카카오 지도 지오코더가 필요하고 앱 키가 아직 없어,
NEXT_PUBLIC_KAKAO_MAP_KEY가 설정되면 자동으로 동작하고 없으면 비운 채 진행한다.
Co-Authored-By: Claude Opus 5
기획 시안과 틀어져 지우면 안 되는 항목이었다(사용자 확정). 브랜드명·메모·등록일·
최종수정일을 목록·팝업·엑셀에 되살리고, 값이 없을 때 '-'가 나오게 한다.
등록 시 브랜드명·메모도 함께 보낸다 — 요청 VO에 없어 지금은 버려지지만 컬럼이
생기면 프론트 수정 없이 저장된다.
Co-Authored-By: Claude Opus 5
mock을 걷어내고 TB_COM_VOUCHER를 보는 실제 API에 붙였다. 필드 이름이 화면 용어와
달라 Repository가 옮긴다 — frcsNo=코드, frcsNm=가맹점명, brno=사업자번호,
rprsvNm/rprsvTelno=대표자/전화, frcsPostAddr/frcsDaddr/frcsPostZip=주소 3종.
백엔드에 자리가 없는 것은 화면에서 뺐다 — 브랜드명·메모·등록일 컬럼이 없고,
수정·삭제·단건조회 API가 없다(목록과 등록 둘뿐). 행의 수정·삭제 버튼은 시안 자리를
두되 누르면 준비 중임을 알린다.
우편번호(frcsPostZip)를 새로 싣는다 — 주소 검색이 함께 채우는 값이다.
Co-Authored-By: Claude Opus 5
기획 MCH_001 목록 / MCH_002_p 등록 / MCH_003_p 수정. 관리자용 가맹점 API가 없어
(mngr 도메인에 컨트롤러가 없고 common/qrauth의 결제 조회용 VO는 5개 필드뿐)
Repository를 mock으로 둔다 — 화면·검증·액션은 실제 구조다.
목록은 업종·사용여부 필터와 가맹점명/사업자번호/주소 검색, 최근등록순 정렬,
엑셀다운로드(CSV)까지. 가맹점코드는 저장 시 서버가 만들고 수정에서는 읽기 전용이다.
시안에 있으나 정할 것이 남은 두 가지는 자리를 두고 표시해 둔다 — 주소 검색은 연동할
서비스가 없어 직접 입력으로 받고, 엑셀등록은 양식·검증 규칙이 없어 비활성이다.
Co-Authored-By: Claude Opus 5