콘텐츠로 이동
✍️ 수정가능누구나 고쳐도 됩니다. 고치면 하단 frontmatter의 갱신일·작성자·변경요약을 남겨 주세요.작성 Claude · 2026-06-05 · 실제 코드(mvp-front/src) 정독 후 전면 정정 — 레이어·라우트 그룹·BFF·entity 구조·스택

프론트엔드 코드 아키텍처

코드/시스템 3문서백엔드 코드 아키텍처 · 프론트엔드 코드 아키텍처(이 문서) · 시스템·인프라 아키텍처(전체 지도 + 서버·배포·운영).

Next.js 15 / React 19 / App Router. 이 문서는 실제 코드(mvp-front/src)를 정독해 작성했다 — 경로·패턴은 코드에서 확인한 것이다. 백엔드 API 계약은 backend-architecture, 반응형 UI 토큰은 responsive·디자인 시스템.


1. 레이어 구조 (FSD 변형)

src/ 직하 레이어는 다음과 같다(코드 확인 — 과거 문서가 빠뜨린 shared·store·providers가 실제로는 핵심이다).

레이어 역할
app/ App Router 조립 — page.tsx/layout.tsx 라우팅 + BFF Route Handler. 비즈니스 로직은 두지 않음(단 (private)/layout.tsxfetchMemberRole() 후 리다이렉트하는 서버 가드 포함).
features/ 도메인 기능 묶음 (UI + 상태 + API)
entities/ 도메인 엔티티 (스키마·변환·타입·정책)
shared/ 가장 큰 레이어 — 공용 UI(에디터·드로잉·사이드바·다이얼로그·아이콘), API 클라이언트(shared/api/http/*), 상수·유틸
store/ Zustand 전역 스토어 (member.store.ts)
providers/ React 전역 Provider (query·interceptor·session·analytics·toast 등)
layout/ 공용 Header/Footer/ColumnLayout
config/ 사이트 메타(site.ts)
mocks/ MSW(Mock Service Worker) 핸들러
types/·styles/·assets/·stories/ 공유 타입·전역 CSS·정적 파일·Storybook
  • 의존성 방향: 원칙은 app → features → entities → shared, 그리고 entity 내부에서 infrastructure → core(역방향 금지). 단 이 방향 규칙은 ESLint로 강제돼 있지 않다eslint.config.mjsno-restricted-imports 같은 규칙이 없어 컨벤션 수준이다(강제는 후속 과제).

2. App Router 라우트 그룹 (5개)

src/app/의 라우트 그룹은 5개다(과거 문서의 3개는 틀렸음).

그룹 주요 라우트 layout 가드
(auth) /login · /register 이미 로그인 시 /dashboard·/select-role로 redirect
(home) /(홈) · /list/{study-rooms,teachers} · /community/column[/[id]] 공개 탐색·커뮤니티
(private) /dashboard[/connections|qna|study-consultation|study-news] · /study-rooms/new · /study-rooms/[id]/* · /study-note/{new,[id]} · /mypage · /settings · /admin/*(관리자) SessionGuard + 사이드바
(profile) /select-role 역할 미배정(ROLE_MEMBER) 전용 — 역할 있으면 redirect
(public) /inquiry/* · /invite/* · /open-challenge/* · /profile/{student,teacher}/[id] · /study-room-preview/[id]/[teacherId] 인증 불필요

(이외 dev 전용 src/app/test-drawing/. 화면 기획·IA 매핑은 §6.)

3. BFF (app/api) + axios 4-client

프론트는 백엔드를 BFF Route Handler로 감싼다 — 쿠키·CORS를 흡수하고 백엔드로 프록시.

  • catch-all: app/api/v1/[...path]/route.ts (GET/POST/PUT/DELETE/PATCH 전부). 쿠키(Authorization·refresh·sid) 필터링 + ROLE_TEACHER→teacher·ROLE_STUDENT→student path 정규화 후 프록시.
  • 전용 핸들러: auth/{login,logout,refresh,session,clear-session} · member/info · dashboard. 그리고 api/drawing-session-ingest(iPad 필기 캡처, dev).
  • axios 4 인스턴스(shared/api/http/http.transport.tshttp.client.tsapi.{public,private,bff.client,bff.server}):
  • privateHttp — 인증 필요. 클라=/api/v1(BFF 경유), 서버=직접 백엔드. 401 인터셉터로 refresh 자동 재시도(인터셉터는 이 인스턴스에만).
  • publicHttp — 비인증, 직접 백엔드.
  • clientToBffHttp / serverToBffHttp — 클라·서버에서 BFF 직접 호출(refresh·session).
  • 인증이 쿠키 기반인 이유·전송 계층(SameSite·도메인)은 backend-architecture §5 · infra §2-4.

4. 상태 · 스택 (package.json 확인)

  • Zustandstore/member.store.ts 1개({ member, isAuthenticated, setMember, clearMember }). 전역 세션 캐시.
  • TanStack Query ^5providers/query-provider.tsx 설정. 서버 상태는 각 feature hooks/(또는 services/query.ts)와 entity hooks/useQuery/useMutation.
  • Zod ^3 — entity core/*.domain.schema.ts·infrastructure/*.dto.schema.ts, feature 폼 스키마, types/sharedSchema(공통 response 래퍼).
  • Tiptap v3 (@tiptap/react ^3) — shared/components/editor/. 커스텀 익스텐션: CustomImage·FileAttachment·DrawingExtension·Embed·LinkPreview·SlashCommand·KeyboardShortcuts.
  • Tailwind v4 — 스타일. 토큰은 디자인 시스템에서.
  • providers: global · query · interceptor(axios 설치) · session(+session-guard) · analytics · toast · pen-select-guard.

5. entity 내부 구조 (변환 3단)

엔티티는 스키마·변환·타입·정책을 한 폴더에 모은다. 구성은 엔티티마다 다르며, member가 가장 완전한 예다.

entities/member/
├── schema.ts                     base Zod 스키마(raw)
├── core/  member.domain.schema.ts(도메인 변환·transform) · member.factory.ts
├── infrastructure/  member.dto.schema.ts(API DTO) · member.adapters.ts · member.repository.ts · member.keys.ts
├── mapper/  member.mapper.ts (getDisplayName: nickname>name>fallback>email)
├── policy/  ability.ts(buildAbility) · rules.ts(역할별 권한 매트릭스)
├── hooks/   use-member-query.ts
├── types/   MemberDTO · Role · FrontendMember …
└── index.ts (public entry)
  • DTO → Domain 변환은 3단: ① adapters가 응답 envelope(sharedSchema.response(dto))만 Zod 파싱 → ② factorydomain.schema.parse()로 도메인 스키마 적용(transform으로 displayName 등 파생) → ③ mapper의 순수 유틸을 transform 안에서 사용. 즉 adapter=검증, factory=변환, mapper=유틸.
  • 편차 인정: study-room 엔티티는 core+infrastructure+types만 있고 mapper/policy/hooks가 없다. 엔티티마다 필요한 폴더만 둔다.
  • 타입 네이밍은 MemberDTO(외부 비노출)와 도메인 타입 FrontendMember/FrontendTeacherBasicInfo처럼 Frontend prefix를 실제로 쓴다(과거 문서의 "prefix 제거"는 사실과 다름).

6. feature 내부 구조 + 화면/IA

feature는 api|services / hooks / components / model / index.ts 조합이나 구성이 통일돼 있지 않다(코드 기준).

  • features/study-rooms: api/(역할별 room.api.{base,student,teacher}.ts + query options) · components/{common,create,sidebar,student-invitation} · hooks/ · model/(Zod 폼) · data/. index.tsapi·model·hooks만 re-export(components는 의도적 제외). components/sidebar/는 자체 services/api.ts를 둠.
  • features/auth: api/가 아니라 services/(api.ts·query.ts) + schemas/·components/·hooks/·keys.ts·types.ts. index.ts 없음(public entry 미존재).

화면·라우팅 IA: 내부 IA/SEO 메타는 Notion IA/URL 구조도(메인페이지·스터디룸·연결·대시보드·질문모아보기·설정·수업노트…)에서 관리하고, 실제 라우트는 §2 그룹과 매핑된다. 로그인 후 역할별 흐름(보호자=자녀 연결·조회, 선생님=룸 생성·수업노트)으로 갈린다.

7. 에디터 ↔ 미디어 연동

Tiptap 이미지·첨부는 백엔드 미디어 규약(backend-architecture §7)을 따른다.

  • 업로드 성공 시 shared/components/editor/model/use-image-upload.tsmedia://${mediaId} 문자열을 만들어 노드에 심는다(CustomImage·FileAttachment 노드에 mediaId attribute). 저장 시 mediaIds 동봉, 조회 시 백엔드가 실제 presigned URL로 치환 — 프론트는 참조 토큰만 다루고 실제 S3 URL은 모른다.
  • DrawingExtension(iPad 필기)은 documentId/pdfUrl attribute + data-type="drawing" 직렬화, 수집은 app/api/drawing-session-ingest.

8. 반응형

브레이크포인트·반응형 UI 패턴의 SSOT는 responsive·디자인 시스템. 프론트 구현은 그 토큰을 Tailwind v4로 받아 쓴다.


관련

backend-architecture · infra · responsive · engineering-principles · 디자인 시스템