[작업내용] : - 임포트 파이프라인(모달→Gemini API→usePdfImport)과 '수동 확정과 동일 상태' 불변식, 좌표 스케일 금지·viewport 줌 규칙을 Floor Plan 섹션에 문서화 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9.3 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
루트
AGENTS.md는@CLAUDE.md한 줄짜리 alias. Codex 등 다른 코딩 에이전트도 이 문서를 그대로 따른다.
README.md는 사실상create-next-app보일러플레이트 그대로다 — 신뢰하지 말 것. 스택·디렉토리·env·라우팅·트러블슈팅의 단일 진실 공급원은 이 파일과docs/PDF 들이다.
Project at a glance
Q.CAST Front — a Next.js 14 (App Router) frontend for solar-panel layout planning, quoting, and management, targeted at the Japanese (Q.CELLS) market with ja/ko i18n. JavaScript + TypeScript (allowJs, strict: false). Path alias @/* → ./src/*.
Common commands
All scripts use env-cmd to inject the right .env.<mode> file. There is no test runner wired into package.json.
yarn dev # local dev (.env.localhost)
yarn dev:local-api # local dev pinned to http://localhost:8080 API
yarn local:dev # .env.local.dev mode
yarn build # production build (.env.production)
yarn build:dev # development build (.env.development)
yarn start:cluster1 # next start -p 5000 (.env.production) — used by PM2
yarn start:dev # next start -p 5010 (.env.development)
yarn serve # custom HTTP:3000 + HTTPS:3001 (needs ./certificates/*.pem)
yarn lint # next lint
PM2 entrypoints (ecosystem.config.js, prd1/prd2/dev/dev.local.ecosystem.config.js) wrap startscript*.js, which child_process.exec the yarn scripts above.
Architecture — the parts that span many files
Mode routing through src/config/
Runtime config is selected at module load by src/config/config.export.js, which switches on process.env.NEXT_PUBLIC_RUN_MODE between config.local.js, config.local.dev.js, config.development.js, config.production.js. Never read env values directly in feature code — import from here so mode switches stay in one place.
Session / auth gate
iron-session cookies are the session source of truth (src/lib/session.js, src/lib/authActions.js). src/app/layout.js checks the session at the root and redirects every non-login route to /login when missing. SESSION_SECRET must be set (≥32 bytes). The session also carries storeLvl (1차/2차 판매점) which drives quote-render branches, builder number, and group ID. Q-Order / Q-Musubi support autoLogin flows via NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL / NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL.
src/middleware.js injects x-pathname into request headers so the root layout can branch on the active route.
Floor Plan canvas (the heart of the app)
src/app/floor-plan/** is built on Fabric.js 5.5.2. The model has three layered concerns:
- Roof covering (
hooks/roofcover,components/floor-plan/modal/roofShape/outerlinesetting/eavesGable…): outer wall lines, auto/manual roof-shape detection, guides, eaves & kerabs, flow up/down, outer-line edit & offset, roof-face assignment. - Placement surface (
hooks/surface,components/floor-plan/modal/placementShape…): slope, placement/shape drawing, object placement, bulk delete. - Module / circuit (
hooks/module,components/floor-plan/modal/panelBatch…): basic settings, circuit & rack config, orientation.
A modal under components/floor-plan/modal/<feature> pairs with a hook under hooks/<roofcover|surface|module|object|option|...>. Keep that pairing when adding new tools.
Fabric extensions live in src/components/fabric/QLine.js, QPolygon.js and src/util/fabric-extensions.js. Prototype patches must be defined in one place and loaded together — patching elsewhere causes hard-to-debug shape issues.
Context menus are unified through useContextMenu + the contextMenu Recoil atom. The per-target menu inventory is documented in docs/Canvas Status.md — match that list when changing menu wiring.
Plan persistence (serialize/restore) is in src/lib/canvas.js and src/util/canvas-util.js. Recent commits (a5e794b3, 2aef32e0) added a three-layer guard (entry / cache / save) and SizeSetting input guards against 0-area apertures/shadows/dormers — when touching plan load/save or size inputs, do not weaken or remove these guards without understanding the failure mode (InvalidStateError from corrupted plans).
PDF 도면 임포트 — 배치면 초기설정 모달의 PDF 입력 모드 → src/app/api/gemini/floor-plan/route.js(Gemini 분석, 세션 인증 + 사용자별 분당 5회 레이트리밋) → src/hooks/pdf-import/usePdfImport.js. 임포트는 수동 외벽선 확정(useOuterLineWall.handleFix) 직후와 동일한 상태를 만들어야 한다: useLine.addLine 경유 outerLine 생성(attributes/planeSize/fontSize), outerLinePoint 정점 circle, canvas.outerLineFix = true + outerLineFixState, 이후 지붕형상 설정 메뉴 직행. 좌표에 축소 scale 을 곱하지 말 것 — 'QLine 길이×10 = 표시 mm' 불변식이 깨진다. 화면맞춤은 viewportTransform 줌 + canvasZoomState 동기화로만 처리한다.
State — Recoil, split by domain
Atoms live under src/store/ and are split by domain (canvasAtom, roofAtom, estimateAtom, modalAtom, menuAtom, settingAtom, …). When adding state, find the existing domain atom rather than introducing a new global. RecoilWrapper.js mounts the root; QcastProvider.js composes the rest of the global providers (session, global data, global loading) for the App Router root layout.
Build / runtime quirks
next.config.mjssetsresolve.fallback = { fs: false }and externalizescanvas,utf-8-validate,bufferutilas commonjs. Adding a node-only dep usually means adding it to that externals list.experimental.staleTimesare all 0 on purpose — App Router cache is disabled so plan/estimate pages always refetch. Don't re-enable without checking the plan-stale failure mode.reactStrictMode: false. Don't assume double-render semantics.- HTTPS local dev via
yarn serveneeds./certificates/key.pemandcert.pem(gitignored).
Conventions that are easy to violate
-
Prettier: single quote, no semicolons, tabWidth 2, printWidth 150, trailingComma all (
.prettierrc). Runyarn lintbefore declaring done. -
No raw
alert()— always go throughuseSwal/useMessage+sweetalert2. Seedocs/메세지 처리 가이드.pdf. -
Path alias — prefer
@/...over relative../../..chains. -
Logging — never
console.logdirectly in shipped code. Usesrc/util/logger.js, which no-ops unlessNEXT_PUBLIC_ENABLE_LOGGING=true.src/util/debugCapture.jsPOSTs to/api/debugfor server-side capture (also gated by the same flag). -
Commit messages follow
.gitmessage.txt:[일감번호] : [제목] [작업내용] :Recent commits use a slightly tighter
[2204] <subject> — <detail>form; mirror neighboring commits on the branch. -
.env.*can contain real secrets — never paste contents into PR bodies, issues, or chat..env.*.localis gitignored for machine-local overrides.
Reference docs in docs/
Canvas Status.md— canvas feature status and right-click menu inventory per target type.Qcast coding convention.pdf,Qcast development guilde.pdf— full conventions / dev guide.메세지 처리 가이드.pdf— modal & alert message rules.git commit message Convention.pdf— commit format.Nextjs 14 컴포넌트에 대해서….pdf— App Router server/client component notes.dictionary.txt— domain vocabulary (roof / panel terms in JP/KR).
Always Do
- All answers and reasoning processes must be written in Korean.
- Once the task is complete, use a sub-agent to perform lint checks, and build checks.
- When performing a lint check, ensure that any errors are resolved before proceeding, and make an effort to resolve any warnings that arise.
- When committing, write the prefix in English, while the rest of the title and content in Korean.
- Upon task completion, update the CLAUDE.md and README.md documents if necessary.
- When working, commit in meaningful units that can be explained in a single sentence.
.agents/ skill 문서
.agents/skills/{next-best-practices,vercel-react-best-practices}/** 에 Vercel·Next.js 모범사례 룰북이 들어 있음(총 95개 .md). Next/React 패턴 관련 결정을 내릴 때(렌더링 최적화, RSC 경계, 번들 분할, hydration 이슈, 서버/클라이언트 캐싱 등) 우선 참조.
- Skill 진입점: 각 디렉토리의
SKILL.md가 인덱스, 룰은rules/하위 토픽별 파일. - 이 문서들은 git 추적 대상이므로 변경하면 PR 에 함께 올릴 것.
graphify (선택)
src/ 지식 그래프를 graphify-out/ 에 캐싱해두면 cross-module 질문(A 가 B 에 어떻게 연결되는가, X 의 의존성 등)을 grep 보다 빠르게 답할 수 있다. 캐시는 로컬 전용이며 git 추적 대상이 아니다.
- 부재 시(현재 워크트리 포함):
/graphify src로 풀 빌드, 이후엔graphify update .로 incremental. src/편집 후 architectural 질문에 답하기 전에graphify update .1회 실행 (AST-only, 수 초).- JS import-기반
callsedge 는 INFERRED 로 마크됨 — 호출 의미가 답의 핵심이면 소스로 한 번 더 확인.