전환 중 뜨는 표시가 Tailwind 클래스(animate-spin·border-t-transparent·size-8)로만
그려져 있었는데, Tailwind가 제거된 뒤로 그 클래스들이 정의되지 않아 아무것도 보이지
않는 상태였다. 감싸던 배치 클래스(flex·flex-1·items-center)도 마찬가지였다.
- components/ui/spinner.tsx가 FoxSpinner를 그리도록 바꿨다. size·tone 축은 그대로 둬서
호출부 다섯 곳을 건드리지 않는다(loading.tsx 넷 + 전역 오버레이 하나).
- 계열 색은 CSS 모듈로 옮겼다. FoxSpinner 기본이 테마색이라 inverse·muted만 덮는다.
- 화면 넷의 loading.tsx가 같은 내용이라 PageLoading 공용 컴포넌트로 모으고, 죽어 있던
배치를 CSS 모듈로 되살렸다.
확인한 것: 두 CSS 모듈이 토큰 var()로 컴파일되고, FoxSpinner가 32px에서 시안대로
그려지며, tsc·eslint가 통과한다.
확인하지 못한 것: 전환 화면 자체는 로그인이 필요한 라우트라 눈으로 보지 못했다.
Co-Authored-By: Claude Opus 5
아이콘이 없어 텍스트로 대체돼 있던 자리를 시안대로 되돌린다. `@fox`에 Phosphor 전량이
들어왔으므로 더 이상 막힐 이유가 없다.
- students: 돋보기(FoxMagnifyingGlassIcon) — "조회" 텍스트 버튼을 대체
- admins · boards · decoration-items: 연필(FoxPencilSimpleIcon)·휴지통(FoxTrashIcon)
- 테마 토글: 손으로 그린 monitor/moon/sun 3종을 @fox 아이콘으로 교체하고
components/ui/icons/ 디렉터리를 제거했다(다른 사용처 없음)
버튼을 `components/ui/button`이 아니라 `FoxIconButton`으로 쓴 이유 — @fox 아이콘은 스스로
크기를 갖지 않고 감싼 슬롯이 정하는 규약인데, 그 슬롯 크기를 실제로 정의하는 CSS가 있는 건
@fox 쪽뿐이다. Tailwind 제거(e3d3133)가 빌드 설정만 바꾸고 components/ui 19개 파일은 그대로
둔 탓에 `size-9`·`inline-flex` 같은 클래스가 전부 무효라, 그쪽에 아이콘을 넣으면 SVG가 기본
300×150으로 그려진다.
테마 토글은 같은 이유로 실제 버그였다 — 표시 전환을 Tailwind의 `hidden theme-*:contents`에
기대고 있어서 세 아이콘이 한꺼번에 보이고 있었다. 같은 동작을 CSS 모듈로 다시 세웠고,
`aria-label` 대신 `sr-only` 텍스트로 현재 선택을 읽히는 기존 접근성 설계는 그대로 유지했다
(IconButton에 label을 넘기면 aria-label이 내용을 덮어쓴다).
검증 — 컴파일된 CSS를 주입해 `` 3상태를 실제로 전환했다. 속성 없음→system,
light→light, dark→dark로 **매번 하나만** 표시되고 20×20px(--fox-icon-4)로 그려진다.
FoxIconButton은 sm/ghost에서 28px 버튼에 24×24 아이콘이다.
남은 것 — sidebar-group.tsx의 셰브론은 손으로 그린 채로 뒀다. 회전(`rotate-90`)과
크기(`size-4`)를 Tailwind 클래스에 기대고 있어 그 둘을 실재하는 CSS로 옮기기 전에는 글리프만
바꿔도 나아지지 않는다. components/ui 전체 리스타일과 함께 처리한다.
Co-Authored-By: Claude Opus 5
mock 저장소를 제거하고 /api/v1/mngr/item CRUD와 파일 업로드 API에 연결한다. 기존 구현은
"이 도메인에는 백엔드 API가 전혀 없다"는 전제로 만들어져 있었으나, 백엔드에 등록·수정·삭제까지
갖춘 API가 존재해 스키마에 맞춰 도메인 타입부터 다시 맞췄다.
- 아이템ID는 사용자 입력이 아니라 백엔드 자동 채번(itemSn)이다. 시안도 "등록 후 자동발급
(Read Only)"이라 등록 폼의 입력 필드를 없애고 목록·수정 팝업에는 itemSn을 그대로 노출한다.
- 유형은 개별=N, 셋트=S로 매핑한다. 목록 조회는 searchItemType이 필수라 값이 없으면 아무것도
조회되지 않는다.
- 카테고리는 공통코드가 정비되기 전까지 프론트 임시 코드로 개발한다(사용자 지시). 표기는
백엔드가 조인해 준 이름을 우선 쓰고 없으면 임시 목록에서 찾는다.
- 이미지는 파일 하나만 받아 atchFileId에만 저장한다(썸네일은 추후 백엔드 자동생성 예정).
브라우저가 백엔드에 직접 올리지 않도록 Server Action이 File을 받아 중계한다. 목록 썸네일은
인증이 필요 없는 이미지 GET 주소를 서버에서 만들어 내려준다.
- 총건수 보정은 학생 목록과 동일하다(백엔드 PaginationUtil에 count 쿼리가 없다).
lib/http/backend-fetch.ts에 PUT/DELETE와 form·multipart 본문을 추가했다. 아이템 쓰기 API는
@RequestBody가 아니라 @ParameterObject로 받으므로 JSON을 보내면 전 필드가 null인 채 저장된다.
Next.js 16의 'use server' 파일은 async 함수 외의 값을 export할 수 없어(런타임 전용 제약),
폼 상태 초깃값(INITIAL_DECORATION_ITEM_FORM_STATE)을 domain 계층으로 옮겼다.
Co-Authored-By: Claude Opus 5