디자인 시안이 나오면 다시 추가한다. Tailwind 제거 이후 퇴장 애니메이션(animate-fade-out)
클래스가 죽어 onAnimationEnd가 영영 발화하지 않았고, 그 결과 markSplashShown()도
setIsVisible(false)도 호출되지 않아 모든 화면 상단에 스플래시가 영구히 남아 있었다.
삭제: app/_components/splash-gate.tsx · components/ui/splash-screen.tsx ·
lib/constants/splash.ts. app/layout.tsx의 inline style/script와 도
함께 걷어냈다.
lib/constants/theme.ts의 주석이 삭제될 splash 상수 파일을 가리키고 있어 그 상호참조만
제거했다. public/images/logo-foxpay-white.svg는 재추가 시 다시 쓰므로 남겨둔다.
(public)/layout.tsx는 AuthCard를 더 이상 감싸지 않으므로 그 설명 주석을 제거한다.
Co-Authored-By: Claude Opus 5
5px에서는 밝은 회색 계열(#FFFFFF · #F4F5F6 · #E6E8EA)이 서로 구분되지 않았고
반투명 토큰의 알파 여부도 보이지 않았다.
16px는 icon-3(1.6rem)과 같은 값이라 리터럴 대신 토큰을 쓴다 — 5px일 때는 스케일에
맞는 값이 없어 리터럴이 불가피했던 예외가 사라졌다.
Co-Authored-By: Claude Opus 5
Figma 변수 페이지와 1:1로 대조하기 위한 감사 화면으로 바꾼다. 분류를 우리 CSS 그룹이
아니라 원본 컬렉션/모드로 두고 — Mode(Light/Dark) · Responsive(PC/Mobile) · Size ·
Theme · Primitive — 파일에 값이 적혀 있으면 그 값을, 다른 토큰을 가리키면 참조 토큰을
표시한다. 토큰 이름 아래에 Figma 변수 경로를 함께 적는다.
CSSOM 읽기로는 이 요구를 만족할 수 없어 걷어냈다. CSS는 alias를 var()로 흡수하고
light/dark를 light-dark() 한 줄로 합치므로 "원본이 값을 적었는지 토큰을 가리켰는지"를
되살릴 수 없다. 대신 변환기가 원본 구조 그대로를 담은 매니페스트를 함께 생성한다 —
여전히 자동 생성이라 목록을 손으로 관리하지 않는다.
미리보기도 CSS 변수가 아니라 매니페스트의 해석값을 쓴다. 변수를 쓰면 PC 섹션을 좁은
창에서 볼 때 모바일 값이, Light 섹션을 다크 테마에서 볼 때 다크 색이 그려진다.
⚠️ 매니페스트를 만들며 잡은 것: 이 export에는 `theme`이라는 이름의 컬렉션이 둘이고
(제공된 파랑 계열, 미제공 청록 계열) 변수 경로까지 같아, 이름만으로 매칭하면 chart-alt
18개가 엉뚱하게 해결된 것처럼 보인다. 값 대조를 넣어 "미제공 컬렉션"으로 표시한다.
SCSS 생성 쪽은 원래부터 값 대조를 하고 있어 영향이 없었다.
Co-Authored-By: Claude Opus 5
토큰 표기를 `fox.color(background-default)`에서 `color-background-default`로 바꾼다.
`--fox-` 접두사만 뗀 실제 CSS 변수 이름이라 devtools에서 보는 것과 1:1로 대응하고,
함수 표기처럼 그룹명이 괄호 밖으로 빠지지 않아 목록을 훑을 때 이름이 바로 읽힌다.
표기를 만드는 함수가 하나뿐이라 스와치·서체 목록·값 표가 갈릴 일이 없다.
그 결과 쓰이지 않게 된 fn prop을 제거한다.
사이드바의 "추가 방법"은 컴포넌트 등록 여부와 무관하게 목록 맨 아래에 고정한다 —
이전에는 컴포넌트가 하나라도 생기면 사라져 추가 절차를 찾을 수 없었다. 컴포넌트가
아니라 안내이므로 점선 테두리와 흐린 글자로 등록된 탭과 층위를 구분한다.
Co-Authored-By: Claude Opus 5
값만 보여주던 막대를 걷어내고 그룹별로 실제 적용 결과를 보인다 — 서체는 그 속성을
적용한 문장, 패딩·간격은 문단 두 개 사이의 공간, 반경·테두리는 실제 테두리를 가진
div, 아이콘은 브라우저 기본 체크박스, 그림자는 실제 box-shadow, 배경 흐림은 사진 위
절반에만 건 backdrop-filter다. 원시 수치는 값만 남긴다.
그림자는 Figma에 offset·blur 수치만 있고 조합과 색이 정의돼 있지 않다. 각 수치의
효과를 보이려고 location은 `0 값 0`, blur는 `0 0 값`으로 걸고 색은 실재 토큰인
alpha-default-inverse25를 쓴다 — 조합 자체는 토큰이 아니며 섹션 설명에도 적었다.
배경 흐림 예제 이미지는 next/image가 아니라 다. @fox가 Next에 의존하면 폴더째
복사되는 이식성이 깨지고 외부 호스트마다 remotePatterns 설정이 필요해진다.
Co-Authored-By: Claude Opus 5
크롬 없는 공개 레이아웃 (public)/(empty)를 신설하고 그 아래에 마운트한다 —
(public)/layout.tsx의 AuthCard는 로그인 화면용 껍데기라 이 페이지엔 맞지 않는다.
화면 구현은 @fox/dev-test가 전부 소유하므로 이 라우트는 마운트와 프로덕션 차단만
담당한다.
proxy의 개발 전용 공개 경로도 새 경로로 옮긴다 — 프로덕션에서는 페이지가
notFound()를 내고 이 목록도 평가되지 않아 fail-closed가 유지된다.
Co-Authored-By: Claude Opus 5
토큰 배치 확인과 컴포넌트 예제를 한 페이지에서 본다. 사이드바는 토큰/컴포넌트
두 대분류이며, 토큰 그룹은 CSSOM에서 읽으므로 목록을 코드에 두지 않는다.
컴포넌트는 component-registry의 배열에 항목 하나만 추가하면 사이드바와 본문이
함께 갱신된다 — 만들 때마다 다른 파일을 고칠 필요가 없다.
하니스를 앱이 아니라 @fox에 두는 이유는 폴더를 다른 프로젝트로 복사할 때 함께
따라가게 하기 위함이다. 그래서 앱 상수(테마 저장 키 등)를 import 하지 않고,
테마 전환은 @fox가 소유한 data-theme 계약만 건드린다(저장하지 않는다).
선택 상태는 URL 해시가 SSOT라 새로고침해도 보던 섹션이 유지된다.
같은 목적의 카탈로그를 두 벌 두면 갈라지므로 구 app/design은 함께 제거한다.
Co-Authored-By: Claude Opus 5
Figma 컬렉션 5개(primitive/theme/size/테마/반응형)·모드 7개를 옮겼다.
색상은 light/dark를 light-dark() 한 줄에 묶어 테마 드리프트를 구조적으로 막고,
반응형 크기는 모바일 우선으로 깔고 768px 이상에서 pc 값이 덮는다.
Figma의 alias를 CSS에서도 var() 참조로 보존했다 — 색상 표현 542개 중 476개가
primitive/theme를 참조하므로 바닥층을 바꾸면 시맨틱까지 전파된다. 참조 대상이
없거나 값이 어긋나는 것만 리터럴로 떨어뜨렸다.
알파 색상은 rgb(R G B / A)로 낸다. hex는 알파를 담지 못해 그대로 두면 반투명이
불투명이 된다.
루트에 소속 없이 들어 있던 29개는 두 번째 theme 컬렉션(미제공)을 참조하며
chart-alt로 명명했다 — 이름은 임시다.
Co-Authored-By: Claude Opus 5
토큰 531개를 손으로 옮기면 오타가 섞이고 Figma 재수출 때마다 반복해야 한다.
변환 규칙(1rem = 10px, 알파 색상의 rgb() 표기, alias의 var() 보존)을 코드로
고정해 재수출 시 재실행만으로 갱신되게 한다.
Co-Authored-By: Claude Opus 5
색상·타이포·간격·radius·그림자·모션·브레이크포인트 토큰은 실제 디자인 자료 없이
임의로 만들어진 값이었다. 디자인 시스템은 제공된 자료로만 구축한다는 원칙에 따라
값과 그에 딸린 함수·믹스인·리셋을 모두 제거한다.
자료를 받는 시점에 구조부터 다시 세운다.
Co-Authored-By: Claude Opus 5
디자인 시스템 기반을 Tailwind에서 @fox(SCSS + CSS Modules)로 교체한다.
⚠️ 기존 화면(꾸미기 아이템 포함)의 Tailwind 클래스는 이 시점부터 무효다 —
라우팅·로직은 정상이나 시각 스타일이 빠진 상태이며, 화면을 @fox 컴포넌트로
재작성하며 복구한다. components/ui/의 기존 22개는 소비처가 남아 있어 함께
교체될 때까지 유지한다.
Co-Authored-By: Claude Opus 5
토큰 목록을 코드에 두지 않고 CSSOM에서 읽는다 — tokens/에 값을 추가하면
카탈로그에 자동으로 나타난다. CSS Modules의 :export를 먼저 시도했으나
Turbopack의 Lightning CSS가 이를 인식하지 못해(빌드는 통과하되 값이 조용히
undefined가 된다) CSSOM 열거로 대체했다.
개발 전용 라우트이며 프로덕션에서는 notFound()로 차단된다. proxy는 개발
환경에서만 인증을 면제하므로 프로덕션 빌드에서는 fail-closed가 유지된다.
Co-Authored-By: Claude Opus 5
globals는 @fox 로드와 앱 셸 구조만 담당하고 디자인 값은 갖지 않는다.
폰트는 앱이 소유하고 @fox는 --app-font-sans/--app-font-mono를 참조만 하므로,
@fox 폴더를 다른 프로젝트로 복사해도 그쪽 서체를 그대로 따른다.
Co-Authored-By: Claude Opus 5
토큰 SSOT는 tokens/의 SCSS map 하나다. 여기서 --fox-* 커스텀 프로퍼티(_root)와
토큰 이름 검증 목록(_functions)이 함께 파생되므로 값과 이름이 어긋날 수 없다.
없는 토큰 이름은 @error로 빌드를 실패시켜 하드코딩 금지를 컴파일러가 강제한다.
모든 치수는 rem이며 1rem = 10px(html font-size 62.5%). 단 미디어 쿼리의 rem은
브라우저 기본 크기 기준이라 브레이크포인트만 예외이며, 각 값에 px 환산을 병기했다.
토큰 값은 파이프라인 검증용 임시 플레이스홀더이며 Figma 확정 시 교체한다.
Co-Authored-By: Claude Opus 5
admins/_actions.ts('use server')가 AdminMemberFormState 타입의 초깃값
INITIAL_ADMIN_MEMBER_FORM_STATE를 값으로 export하고 있어, 관리자 등록/수정/
삭제/ID 중복확인 Server Action을 호출할 때마다 "A 'use server' file can
only export async functions, found object" 런타임 에러로 500이 발생했다.
빌드·타입체크는 통과하고 실제로 폼을 제출해야만 드러나는 문제였다.
decoration-items가 이미 적용해 둔 동일 패턴을 따라 AdminMemberFormState
타입과 INITIAL_ADMIN_MEMBER_FORM_STATE 상수를 'use server'가 없는
lib/domain/admin-member-form.ts로 옮기고, _actions.ts는 타입만 다시
import하도록 정리했다. 두 소비처(admin-member-create-modal.tsx,
admin-member-edit-modal.tsx)의 import 경로도 함께 갱신했다.
Co-Authored-By: Claude Opus 5