사용자 지시 — "주석이 너무 많다, 주석은 TODO나 이슈사항만 적어줘".
이번 작업에서 내가 쓴 설명 주석을 지웠다(23개 파일, 633줄 삭제 / 14줄 추가). 파일·함수 설명,
동작 요약, 결정 근거, 시안 번호, 검증 방법은 전부 뺐다 — 코드·커밋 메시지·README가 할 일이다.
남긴 것은 없으면 다음 사람이 사고를 낼 자리 다섯 줄뿐이다.
- 등록은 form(@ParameterObject), 수정은 JSON(@RequestBody)로 갈려 있음
- 백엔드 totalCount가 전체가 아니라 현재 페이지 행 수
- 관리자별 메뉴 권한이 백엔드에 없어 저장되지 않음
- 파일 업로드 moduleId는 틀려도 실패하지 않고 기본 저장소로 폴백 (+ 모듈 조회 API TODO)
- `
**FoxPhoneNumber** — `unit` 모드에서 `prefixOptions`가 비면 앞자리를 셀렉트가 아니라 입력 칸으로
그린다. 항목 없는 셀렉트는 placeholder "010"이 이미 고른 값처럼 보이는데 실제 값은 비어 있어,
뒷자리만 채운 번호가 조용히 만들어졌다(관리자 등록이 막힌 원인). 세 칸을 한 map으로 돌게
정리하면서 combine 분기와 모양을 맞췄다.
**FoxEmail** — 시안(form-email 5543:9940)은 줄이 나뉜다: [아이디] @ [도메인] 한 줄, 그 아래
도메인 드롭다운, 그 아래 확인 버튼. 종전에는 넷을 한 줄에 두고 넘치면 접히게 했는데, 좁은 곳에서
드롭다운이 도메인 칸보다 먼저 접혀 순서가 어긋났다(320px 팝업에서 세 줄로 흩어졌다).
`__body`(4px 간격) 안에 form-group·select·btn을 쌓고, 칸의 `min-inline-size: 24rem`을 0으로 바꿔
좁은 폭에서도 두 칸이 나눠 갖게 했다. 라벨의 필수 표시(`requirement`)도 다른 폼 컴포넌트와 같은
규약으로 추가했다.
**관리자 등록 팝업** — 손으로 짜 두었던 이메일 칸(아이디·도메인·직접입력 상태 세 개)을 `FoxEmail`
하나로 바꿨다. 시안 5227:2036 그대로이고, 아이디 placeholder는 "ID"(종전 "1234-5678"은 전화번호
칸에서 복사된 값이었다), 도메인은 첫 항목이 골라진 채로 시작한다.
검증 — 시안 대조 실측: 아이디 149×40 · 도메인 149×40(readOnly, "naver.com") · 셀렉트 320×40 ·
그룹↔셀렉트 간격 4 · 라벨 "이메일*"(시안 149/149/320/4와 일치).
동작: 직접입력 고르면 도메인 칸의 readOnly가 풀린다. prefixOptions 없이 쓴 FoxPhoneNumber는
앞자리가 입력 칸이 되고 "02"를 적으면 값에 실린다(종전에는 아무리 눌러도 빈 값이었다).
Co-Authored-By: Claude Opus 5
기획 SYS_COD_001(1842:17507)과 팝업 4종(1842:16056·16122·16179·16262),
시안 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) 5402:13399.
한 화면에 목록이 둘이다. 좌측 공통코드를 행 전체로 눌러 고르면 우측 상세코드가 그 그룹으로
갱신된다(기획 ④). 선택·검색·두 목록의 페이지가 모두 URL에 실려, 갱신은 서버가 다시 그린다 —
공통코드를 바꾸면 상세 페이지가 1로 돌아가는 규칙은 buildCommonCodeHref가 강제한다(호출부가
잊어도 어긋나지 않게).
**검색·페이징을 서버(RSC)에서 한다.** 백엔드가 두 목록 모두 전체를 반환하고 그룹 검색도
LIKE가 아닌 완전일치라, 부분일치 필터와 페이지 자르기를 page.tsx가 맡는다(사용자 확정 사항).
전체를 받으므로 총건수는 정확해 다른 목록의 하한값 보정이 여기엔 필요 없다.
URL의 comCd가 목록에 없으면 첫 행으로 대체한다 — 검색으로 걸러졌거나 삭제된 코드가 주소에
남아 있으면 우측이 영영 비어 보인다.
분류코드(시안의 CMS 셀렉트)는 저장되지 않는다. TB_SYS_COM_CD에 해당 컬럼이 없어(관리자용·
공용 두 매퍼와 후보 컬럼명까지 확인), 코드ID 접두사를 채워 주는 입력 보조로만 쓴다 — 시안
목록이 전부 CMS+3자리라 그 작명 규칙을 화면이 거드는 것이다(사용자 확정 사항).
설명 열은 한 줄 말줄임이다. 시안 셀에는 말줄임 스타일이 없지만(전문 + word-break) 프레임이
44로 고정이라 Figma가 넘침을 잘라 보여준다 — CSS는 감싸므로 그대로 두면 자유 입력인 설명
때문에 행 높이가 제각각이 된다. 잘린 글자는 title로 남긴다.
@fox: FoxHeadingGroup 신설(시안 3002:7177). 화면에 여럿 설 수 있는 구역 제목이라
FoxPageHeader(h1·breadcrumb)와 역할이 다르고, 제목 태그를 고를 수 있다. 아이템 목록 시안에도
숨김으로 들어 있어 재사용된다.
백엔드 요청 2건(시안대로 두고 보고, 사용자 확정 사항)
- 상세 목록 조회 SQL이 DTL_CD_EXPLN을 select하지 않아 상세코드설명이 늘 비어 온다.
- 상세 등록 INSERT에도 없어 등록 시 입력한 설명이 저장되지 않는다(수정은 정상).
검증 — 시안 대조 실측: 패널 2단 gap 40, 열 폭 공통 80/120/160/156/120/120 · 상세
80/120/120/196/120/120, 행 높이 44(+테두리 1), 검색 320, 패널 제목 26px #1e2124 h2.
동작: 분류코드 SYS 선택 시 코드ID 004→SYS004, 다시 CMS 선택 시 CMS004(접두사 교체),
상세코드 등록 팝업의 코드ID는 읽기 전용·name 없음(제출 제외)에 hidden comCd로 전달,
정렬번호 기본값 11(기존 10개 다음).
Co-Authored-By: Claude Opus 5
목록 셀(80×80)과 등록·수정 팝업의 업로드 미리보기(120×120) 모두. 아이템은 생김새 자체가
정보라 잘라내면 어떤 아이템인지 알아볼 수 없고, 미리보기는 고른 그림을 확인하는 자리라
일부만 보이면 확인이 되지 않는다.
@fox: `.fox-file-upload__thumb-image`의 object-fit. FoxFileUpload의 image 모드를 쓰는 화면이
이 팝업뿐이라 영향 범위가 이 화면 안이다.
Co-Authored-By: Claude Opus 5
둘 다 시안 ADM_ADM_102_p(5227:2035)가 요구하는데 없던 것이다.
- `FoxInput`에 `requirement`를 열었다. 라벨을 FoxFormLabel로 그리면서 그 값을 넘기지 않아
`이름*`처럼 필수 별표가 붙은 시안을 그릴 수 없었다. 이미 같은 prop을 가진 `FoxSelect`와
같은 모양으로 맞췄다.
- `FoxChipArea`에 `wrap`을 열었다. 스타일 주석이 "칩이 여러 줄로 흘러야 하는 자리가 나오면
시안에 먼저 추가한다"고 적어 둔 그 자리다 — 시안의 "메뉴 선택"이 칩을 두 줄로 감는다.
기본값은 종전대로 한 줄이라 기존 호출부는 그대로다. `FoxButtonGroup`의 같은 prop과 맞췄다.
Co-Authored-By: Claude Opus 5
시안(관리자페이지 5199:9035의 search > btn, 노드 5199:9029)은 배경이 있는 secondary 계열
버튼인데 투명 배경에 radius 4로 그리고 있었다.
시안 bg button/secondary-surface(#ecf2fe) · radius form/radius/md(8) · 32×32 · 아이콘 20
종전 투명 · radius form/radius/xsm(4)
배경·radius·아이콘 색을 시안 토큰으로 맞추고, 배경이 생긴 만큼 hover·pressed·disabled도
button-secondary 계열로 함께 정의했다(종전에는 색만 흐려졌다). 크기 32와 아이콘 20은 이미
맞아서 그대로다.
검증 — PC 폭에서 배경 rgb(236,242,254)=#ecf2fe, radius 8px, 32×32, 아이콘 20×20,
아이콘색 rgb(11,80,208)=#0b50d0으로 시안과 일치한다.
Co-Authored-By: Claude Opus 5
충돌 2건은 양쪽이 같은 자리에 서로 다른 것을 **더하기만** 한 경우라 합집합으로 풀었다.
- styles/components.scss: hub의 파티셜 목록에 fox-status-indicator·fox-toast를 더했다.
- dev-test/component-registry.tsx: 데모 함수(hub의 ModalDemo·DemoThumb + origin/develop의
ToastDemo)와 카탈로그 항목(45 공통 + hub 5 + origin/develop 6 = 56)을 모두 남겼다.
git이 두 삽입의 공통 꼬리(`…}`)를 맞물려 놓아 마커 그대로는 함수가 끊긴다 — 그래서
마커를 고치지 않고 양쪽 원본에서 함수·항목 단위로 다시 세웠다.
검증: tsc·eslint 무오류, next build 성공(/dev-test/design이 빌드 시 프리렌더되므로 병합된
레지스트리가 실제로 렌더되는 것까지 확인).
Co-Authored-By: Claude Opus 5
FoxHelperText 커밋(83acf5b)에서 `_fox-helper-text.scss`는
`@include field.message($display: inline-flex)`로 부르는데, 믹스인 쪽 변경이
함께 올라가지 않아 인자를 받지 못하는 상태였다. 받은 트리에서 sass가
`No argument named $display`로 실패한다.
기본값이 `flex`라 이 믹스인을 부르는 폼 다섯 곳의 출력은 종전과 같다.
Co-Authored-By: Claude Opus 5 (1M context)
원인은 두 규칙이 부딪힌 것이었다.
- `.fox-modal`은 `max-block-size`와 짝으로 `overflow: auto`를 갖는다(내용이 길면 세로로
스크롤하라는 뜻이다).
- `.fox-modal__close`는 테두리 위를 덮으려고 `inset-inline-end: -1px`로 일부러 1px 밖에 나간다.
절대 배치의 기준이 padding box라 그 1px이 넘침으로 계산되고, `overflow-x: auto`가 그것 하나
때문에 가로 스크롤바를 띄웠다(실측 client 398 → scroll 399).
세로만 스크롤하도록 축을 나눴다. 닫기 버튼은 배경도 테두리도 없고 아이콘이 8px 안쪽이라
x축을 잘라도 보이는 변화가 없다 — 시안이 의도한 "테두리를 덮는 배치"도 그대로 남는다.
검증 — 가로 스크롤바가 사라졌고(overflow-x: hidden), 세로는 그대로다(내용 880 / 박스 378에서
0 → 200 이동 확인). 닫기 아이콘은 오른쪽에서 32px 안쪽이라 잘리지 않는다.
Co-Authored-By: Claude Opus 5
FoxModal의 `contents`가 `align-items: flex-start`인 flex 열이라, 그 안의 블록 요소가 내용
너비로 줄어들었다. 조회 목록은 줄마다 아래에 구분선을 긋기 때문에 폭이 줄면 선이 중간에서
끊긴 것처럼 보인다. 실측으로 contents 318에 폼과 목록이 169였다.
- FoxDescriptionList에 `align-self: stretch`를 줬다. flex 부모가 `flex-start`여도 스스로
가로를 채운다 — 컴포넌트가 어디에 놓이든 폭을 보장한다.
- 학생 조회 팝업의 폼 래퍼에도 폭을 줬다. 목록의 부모가 이 폼이라, 폼이 줄면 그 안에서
100%를 잡아도 소용이 없다.
검증 — 폼·목록·8줄 전부 318로 contents와 같아졌다(종전 169).
Co-Authored-By: Claude Opus 5