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
사용자 지시 — "주석이 너무 많다, 주석은 TODO나 이슈사항만 적어줘".
이번 작업에서 내가 쓴 설명 주석을 지웠다(23개 파일, 633줄 삭제 / 14줄 추가). 파일·함수 설명,
동작 요약, 결정 근거, 시안 번호, 검증 방법은 전부 뺐다 — 코드·커밋 메시지·README가 할 일이다.
남긴 것은 없으면 다음 사람이 사고를 낼 자리 다섯 줄뿐이다.
- 등록은 form(@ParameterObject), 수정은 JSON(@RequestBody)로 갈려 있음
- 백엔드 totalCount가 전체가 아니라 현재 페이지 행 수
- 관리자별 메뉴 권한이 백엔드에 없어 저장되지 않음
- 파일 업로드 moduleId는 틀려도 실패하지 않고 기본 저장소로 폴백 (+ 모듈 조회 API TODO)
- `
**React는 폼 액션이 끝나면 성공·실패를 가리지 않고 폼을 리셋한다.** 그래서 검증 오류가 하나만
나도 사용자가 채운 값이 전부 사라졌다. 특히 `type="file"`은 프로그램으로 되채울 수 없어, 한 번
실패하면 그 뒤로는 **"썸네일 이미지를 등록해 주세요."만 반복되는 상태에 갇힌다** — 꾸미기 아이템
등록에서 실제로 그랬다(다른 항목이 틀려 한 번 실패 → 파일 선택까지 지워짐 → 이후 계속 이미지
오류). 즉 사용자에게는 "고칠수록 더 안 되는" 화면이었다.
확인: 같은 Server Action을 두 방식으로 제출해 비교했다. `action={formAction}`은 입력값이 빈
문자열이 됐고, `onSubmit` + `startTransition(() => formAction(fd))`은 값이 그대로 남았다.
실제 로그인 폼으로도 검증 — 백엔드가 "아이디 또는 비밀번호가 올바르지 않습니다."를 돌려준
뒤에도 입력값이 유지된다(종전에는 다시 타이핑해야 했다).
같은 결함이 있던 폼 7개를 한 번에 바꿨다(관리자 등록·수정, 게시글, 문의 답변, 아이템 등록·수정,
로그인). 학생 조회 팝업은 hidden id 하나뿐이라 잃을 값이 없어 그대로 뒀다.
이유를 한곳에 적어 두려고 `submitFormAction`으로 뽑았다 — 세 줄짜리라 각자 쓰면 왜 `action`을
안 쓰는지가 사라진다.
Co-Authored-By: Claude Opus 5