Skip to content

[회의록] #6

@yoorli

Description

@yoorli

회의 개요

  • 날짜: 2025.12.02(화)
  • 회의 안건
    • SVG 아이콘 처리 방식(SVGR, Turbopack) 정리
    • TanStack Form + Zod 기반 폼·밸리데이션 패턴 논의
    • 재사용 가능한 FormInput 컴포넌트 구조 합의
    • 하단 GNB 탭·URL 네이밍 확정
    • 타이포그래피 유틸·CSS 네이밍 컨벤션 공유
    • Git 머지/배럴 파일, Figma 권한 등 협업 방식 논의

회의 내용 요약

  1. SVG 아이콘 처리
    • 현재 프로젝트는 @svgr/webpack 기반 설정이 이미 들어가 있으며, src 경로 SVG는 컴포넌트로 바로 import하는 방식 유지.
    • public 경로 자산, 스프라이트 사용 여부는 Turbopack·Next 16 환경을 고려해 추가로 조사.
  2. TanStack Form 폼 구조·재사용 전략
    • form 스키마 안에 종속된 필드 컴포넌트는 다른 폼에서 재사용이 사실상 불가하다는 점을 확인.
    • 최종 패턴: 폼별로 form.Field를 사용하고, 공통 UI는 FormInput 같은 프리젠테이셔널 컴포넌트 한 개로 통일해 field만 props로 넘겨 재사용.
  3. Zod + TanStack Form 밸리데이션 & 리렌더링 이슈
    • validators.onChangez.object(...) 스키마를 직접 넘기면, 한 필드에서 에러가 나도 다른 필드까지 불필요하게 리렌더링되는 문제 확인.
    • 해결책: Zod는 각 필드용 함수로만 쓰고, 일반 객체 형태의 validators를 만들어 onChange에 넘기되 z.object는 사용하지 않기로 합의.
  4. 라우팅·GNB 네이밍 정리
    • 하단 네비 탭 이름 및 경로 논의:
      • 2번째 탭: 기존 “캘린더” 대신 Schedule/Schedules 명명으로 정리.
      • 모임 생성: Post 계열 명칭 사용 (/post, /post-meetup 등), 상세는 /meetup/[id] 형태 히든 경로.
      • 채팅: 라우트는 chat보다 messages가 더 자연스럽다고 보고 /messages, /messages/[id] 방향으로 합의.
      • 마지막 탭: GNB는 /mypage (내 정보·설정), 타인 프로필은 /profile/[id] 히든 경로로 분리.
  5. 협업·툴 관련 논의
    • Figma: 여러 사람이 수정하면서 프레임이 틀어질 수 있어, 락·권한 설정 방법 추가로 확인하기로 함.
    • Git/배럴 파일: index.ts 배럴에서 충돌은 피하기 어렵다고 보고, 실제 머지/컴플릭트 경험을 쌓는 방향으로 수용.
    • Storybook: w-full 버튼 컴포넌트는 스토리에서 부모 컨테이너 width를 지정해 미리보기 폭을 제어하는 방식으로 사용.

회의 내용 상세

1. SVG 아이콘 처리 방식

  • 현재:
    • @svgr/webpack을 활용해 src 하위 .svgReact 컴포넌트처럼 import해서 사용하는 구조.
    • 예: import TwitterIcon from '@/assets/twitter.svg' 형태로 바로 JSX에서 <TwitterIcon /> 사용.
  • 논의 내용:
    • public 경로 SVG는 정적 자산이라 동일 방식으로 사용하기 어렵고, 스프라이트 기법 적용 시 Turbopack 환경에서 설정 복잡도가 상승.
    • Next 16부터 Turbopack이 기본 빌드로 승격된 만큼, Webpack 기반 예제 설정을 그대로 가져오기엔 한계가 있어 추가 조사 필요.
  • 결론:
    • 단기: 이미 적용된 SVGR 설정을 유지, src 기준 컴포넌트 import 방식 사용.
    • 중기: Turbopack 공식 SVG/스프라이트 지원 여부·베스트 프랙티스 리서치 후 필요 시 마이그레이션.

2. TanStack Form 구조 및 필드 재사용

  • 문제 인식:
    • TanStack Form에서 스키마를 폼 레벨에 정의하면, 그 안에서 선언한 필드 컴포넌트가 해당 폼 타입에 종속되어 다른 폼에서 재사용이 안 됨.
    • 우리가 원하던 구조는 “NicknameField 하나 만들어서 로그인·회원가입·프로필 수정 등에서 공통으로 쓰기”였으나, 폼에 타입이 갇혀 실패.
  • 검토한 대안:
    • 제네릭 폼 컴포넌트, props 드릴링으로 form 전달 등 여러 패턴을 시도했으나, TanStack Form 타입 지원 한계로 인해 form 객체를 외부로 깔끔하게 빼기 어려움.
  • 최종 패턴:
    • UI와 폼 로직 분리:
      • form.Field name='email' 안에서 render-props로 field를 받고,
      • FormInput 같은 공통 컴포넌트에 fieldlabel, placeholder 등만 넘겨서 사용.
    • 즉, 폼별 필드 선언은 각 페이지에 두되, 시각적 인풋·레이블·에러 UI는 전역 공유 컴포넌트로 재사용하는 구조를 채택.

3. Zod 밸리데이션 & 리렌더링 제어

  • 발견된 이슈:
    • validators.onChange: zodSchema처럼 z.object(...) 스키마를 통째로 넘기면,
      • A 필드에서 에러가 나도 연관 없는 B 필드 컴포넌트까지 함께 리렌더링되는 현상 발생.
    • 동일 이슈가 TanStack Form GitHub 이슈에도 보고되어 있음.
  • 해결책:
    • Zod는 계속 사용하되,
      • const schema = { title: z.string().min(3), ... } 같이 일반 객체 안에 Zod 규칙만 담고,
      • validators.onChange = schema 형태로 넘김. (단 z.object({ ... })는 사용하지 않음).
    • 이 방식이면 해당 필드에서 에러가 발생한 컴포넌트만 리렌더되고, 나머지 필드는 그대로 유지되는 것을 확인.
  • 추가 대안:
    • 각 필드에 validate를 직접 거는 field-level validation도 가능하지만, 모든 필드에 개별로 작성해야 해 관리성이 떨어져 공통 validators 객체 패턴을 우선 사용.

4. 라우팅·GNB 구조 및 네이밍

  • 하단 GNB 탭 구성·네이밍:
    1. 홈: /
    2. 모임 스케줄: Schedule/Schedules (경로 예: /schedule)
    3. 모임 생성: Post 또는 Post meetup (경로 예: /post, /post-meetup)
    4. 채팅: Messages (경로 예: /messages, 상세는 /messages/[id])
    5. 내 정보: My page (경로 예: /mypage)
  • 히든 경로:
    • 모임 상세: /meetup/[id] (목록에는 노출되지 않는 상세 전용 경로).
    • 타인 프로필: /profile/[id] (GNB에는 없고, 리스트/카드에서 링크로 진입).
  • My page vs Profile:
    • *GNB의 마지막 탭은 My page*로, 내 정보·설정·테마 등 편집 기능 포함.
    • /profile/[id]는 누구의 프로필이든 “읽기 전용 뷰”로,
      • 내 아이디로 직접 접근하는 경우에는
        • 리다이렉트로 /mypage로 보내거나,
        • 동일 정보라도 수정 버튼 없는 리드온리 뷰만 제공하는 방향 중 택일.

5. 협업·툴 운영

  • Figma 권한·락:
    • 여러 사람이 동시에 작업하면서 프레임·컴포넌트가 1px씩 어긋나는 등의 문제가 발생할 수 있어,
      • 오너/팀 관리자 권한에서 락·권한 설정 방법을 추가로 찾아보기로 함.
  • Git & 배럴 파일:
    • index.ts에서 barrel export를 여러 명이 만지는 구조라 merge conflict는 필연이라고 보고,
      • 실제 충돌을 겪어 보며 해결 경험을 쌓는 것을 학습 기회로 삼기로 함.
  • Storybook:
    • 버튼이 w-full인 구조로 바뀌면서 스토리 상에서는 폭이 너무 좁게 보이는 이슈 발생.
    • 해결: 스토리에서 부모 컨테이너에 적절한 width를 지정하고, 버튼은 그 안에서 w-full로 채우도록 구성.

정리된 결론 / 후속 액션

  1. SVG 아이콘
    • 현 SVGR 설정 유지, src 기준 컴포넌트 import 사용.
    • Turbopack 환경에서의 스프라이트/아이콘 관리 베스트 프랙티스는 추후 별도 리서치.
  2. 폼·밸리데이션 구조
    • 공통 FormInput 컴포넌트를 shared 단에서 한 번만 정의하고, 모든 페이지 폼에서 재사용.
    • validators.onChange에는 일반 객체 + Zod 함수 조합만 사용하고, z.object 기반 스키마는 사용하지 않도록 컨벤션 확정.
  3. 라우팅 & GNB
    • GNB 탭과 경로를
      • Home(/), Schedules(/schedules), Post(/post or /post-meetup), Messages(/messages), My page(/mypage)로 정리.
    • 모임 상세(/meetup/[id]), 프로필(/profile/[id])은 히든 경로로 운용.
  4. 디자인 시스템·협업
    • 타이포그래피 클래스는 text-display-*, text-text-* 패턴으로 사용.
    • Figma 권한·락 설정, barrel 파일 merge 전략 등은 실제 작업 중 생기는 이슈를 기반으로 추가 룰을 보완해 나가기로 함.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions