[사이드프로젝트] 커스텀 데일리 플래너 기획 3

이언덕·2026년 1월 23일
post-thumbnail

🗂 프로젝트 페이지 정리 (라우팅 포함)

프로젝트의 기술 스택은 이미 확정되었고, 디자인도 어느 정도 완성된 상태다. 이제 실제 구현을 위한 기반으로 페이지 구조와 라우팅을 정리해 본다.

1) 랜딩 페이지  (/)
├─ NavBar : 좌측 로고 / 우측 언어 토글(KO/EN), 로그인 버튼
├─ Hero 섹션 : 서비스 소개 문구, CTA 버튼, 데일리플래너 소개 애니메이션
├─ 기능 소개 섹션 1 : 6개 모듈(일간/주간/월간/투두/습관/메모) 하이라이트
├─ 기능 소개 섹션 2 : 모듈 자유배치 소개
├─ 특별한 기능 섹션 : 차별화된 기능 3개 카드
└─ Footer : 브랜드, 지원 & 정책 링크, 저작권 문구


2) 로그인 페이지 (/login)
├─ 헤더 : 상단 로고 / 서브타이틀("오늘도 만나서 반가워요!")
├─ 로그인 카드
│  ├─ 이메일 입력
│  ├─ 비밀번호 입력(가시성 토글)
│  ├─ 로그인 버튼
│  ├─ 링크 영역 
│  │   ├─ 비밀번호 찾기 (/forgot-password)
│  │   └─ 회원가입 (/signup)
│  ├─ 구분선 : "간편 로그인"
│  └─ AuthButtonGroup : 카카오 로그인 / 구글 로그인
└─ (옵션) 폼 검증 및 에러 표시

2-1) 비밀번호 찾기 페이지 (/forgot-password)
├─ 헤더 : 상단 로고 / 타이틀("비밀번호 찾기") / 서브타이틀("가입시 사용한 이메일을 입력해주세요")
├─ 입력 폼
│  ├─ 이메일 입력
│  └─ 인증번호 받기 버튼 (/forgot-password/verify)
└─ 링크 영역 : 로그인으로 돌아가기 (/login)

2-2) 비밀번호 찾기 - 이메일 인증 (/forgot-password/verify)
├─ 헤더 : 상단 로고 / 타이틀("비밀번호 찾기") / 서브타이틀("이메일로 전송된 인증번호를 입력해주세요")
├─ 인증 폼
│  ├─ 인증 메세지 박스 : "인증번호를 발송했습니다 (이메일 주소 표시)"
│  ├─ 인증번호 입력 (4자리)
│  ├─ 재발송 링크
│  └─ 인증하기 버튼
└─ 링크 영역 : 이전 단계로 돌아가기 (/forgot-password)

2-3) 비밀번호 찾기 - 비밀번호 재설정 (/forgot-password/reset)
├─ 헤더 : 상단 로고 / 타이틀("비밀번호 찾기") / 서브타이틀("새로운 비밀번호를 설정해주세요")
├─ 비밀번호 재설정 폼
│  ├─ 새 비밀번호 입력 (가시성 토글)
│  ├─ 새 비밀번호 확인 입력 (가시성 토글)
│  └─ 비밀번호 변경하기 버튼
└─ 링크 영역 : 이전 단계로 돌아가기 (/forgot-password/verify)


3) 회원가입 페이지 (/signup)
├─ 헤더 : 상단 로고 / 타이틀("회원가입") / 서브타이틀("PlanMate와 함께 시작해보세요")
├─ 회원가입 선택 카드
│  ├─ 일반 회원가입 버튼 (/signup)
│  ├─ 카카오톡 회원가입 버튼
│  └─ 구글 회원가입 버튼
└─ 링크 영역 : 이미 회원이신가요? 로그인하기 (/login)

3-1) 회원가입 - 이름 입력 (/signup/name)
├─ 헤더 : 상단 로고
├─ 회원가입 카드
│  ├─ 스텝 인디케이터 (1/4 단계 - 이름 입력)
│  ├─ 타이틀 : "이름을 알려주세요"
│  ├─ 서브타이틀 : "실명을 입력해주세요"
│  ├─ 입력 폼 : 이름 입력 필드
│  └─ 다음 버튼
└─ 링크 영역 : 이미 회원이신가요? 로그인하기 (/login)

3-2) 회원가입 - 이메일 입력 (/signup/email)
├─ 헤더 : 상단 로고
├─ 회원가입 카드
│  ├─ 스텝 인디케이터 (2/4 단계 - 이메일 입력)
│  ├─ 타이틀 : "이메일을 입력해주세요"
│  ├─ 서브타이틀 : "계정으로 사용할 이메일을 입력해주세요"
│  ├─ 입력 폼 : 이메일 입력 필드
│  ├─ 버튼 : 다음 / 이전
└─ 링크 영역 : 이미 회원이신가요? 로그인하기 (/login)

3-3) 회원가입 - 비밀번호 설정 (/signup/password)
├─ 헤더 : 상단 로고
├─ 회원가입 카드
│  ├─ 스텝 인디케이터 (3/4 단계 - 비밀번호 설정)
│  ├─ 타이틀 : "비밀번호를 설정해주세요"
│  ├─ 서브타이틀 : "8자 이상 / 특수문자 포함 권장"
│  ├─ 입력 폼 
│  │   ├─ 비밀번호 입력 (가시성 토글)
│  │   └─ 비밀번호 확인 입력 (가시성 토글)
│  ├─ 버튼 : 다음 / 이전
└─ 링크 영역 : 이미 회원이신가요? 로그인하기 (/login)

3-4) 회원가입 - 약관 동의 (/signup/terms)
├─ 헤더 : 상단 로고
├─ 회원가입 카드
│  ├─ 스텝 인디케이터 (4/4 단계 - 약관 동의)
│  ├─ 타이틀 : "약관에 동의해주세요"
│  ├─ 서브타이틀 : "서비스 이용을 위한 필수 약관입니다"
│  ├─ 체크박스 목록
│  │   ├─ [필수] 서비스 이용약관 동의 (상세보기 → 모달)
│  │   └─ [필수] 개인정보 처리방침 동의 (상세보기 → 모달)
│  ├─ 버튼 : 회원가입 완료 / 이전
└─ 링크 영역 : 이미 회원이신가요? 로그인하기 (/login)


4) 기능 선택 페이지 (/setup)
├─ 헤더 : 상단 로고 / 타이틀("필요한 기능만 골라 쓰는 맞춤형 플래너") / 서브타이틀("원하는 기능만 조합해 나만의 플래너를 완성하세요")
├─ 모듈 선택 영역 (캐러셀 구조)
│  ├─ 일간 플래너 모듈 카드
│  ├─ 주간 플래너 모듈 카드
│  ├─ 월간 플래너 모듈 카드
│  ├─ 투두리스트 모듈 카드
│  ├─ 습관 트래커 모듈 카드
│  └─ 메모 모듈 카드
│
│  ├─ 좌/우 화살표
│  │   ├─ 왼쪽 화살표 : 이전 카드가 있을 때만 표시
│  │   └─ 오른쪽 화살표 : 다음 카드가 있을 때만 표시
│
└─ 하단 CTA 버튼 : 시작하기


4-1) 기능 디자인 선택 페이지 (/setup/[module])
├─ 헤더 : 상단 "이전" 버튼 / 타이틀("일간 플래너 디자인을 선택하세요") / 서브타이틀("원하는 디자인 스타일로 나만의 일간 플래너를 설정하세요")
├─ 디자인 선택 카드 영역
│  ├─ 선택 안함 카드 (No Selection)
│  ├─ 리스트형 카드 (List Design)
│  ├─ 블록형 카드 (Block Design)
│  └─ 타임라인형 카드 (Timeline Design)
│    └─ (4-1) 플래너 모듈별 디자인 옵션
│        ├─ 일간 : 리스트 / 블록 / 타임라인
│        ├─ 주간 : 리스트 / 그리드 / 카드
│        ├─ 월간 : 달력 / 이벤트 리스트 / 주간 블록
│        ├─ 투두 : 체크리스트 / 칸반 / 우선순위
│        ├─ 습관 : 달력 체크 / 리스트 체크 / 진행률 바
│        └─ 메모 : 자유 텍스트 / 스티키 노트
└─ 하단 CTA 버튼 : 선택 완료 (모듈 디자인 선택 시 활성화)


5) 기능 배치 페이지 (/setup/layout)
├─ 헤더 : 이전 버튼 / 타이틀("기능을 배치하세요") / 서브타이틀("원하는 위치에 배치하고 크기를 조정하세요")
├─ 상단 선택 영역
│  ├─ 선택된 기능 목록 (드래그 가능)
│  └─ 남은 기능 표시 (예: "남은 기능 1개")
├─ 대시보드 영역
│  ├─ 빈 그리드 레이아웃 (배치 보드 : 12×6 그리드)
│  ├─ 기능 추가 슬롯 (+ 버튼)
│  └─ 드래그 & 드롭 / 리사이즈 핸들
└─ 하단 CTA 버튼 : 배치 완료


6) 완성 페이지 (나만의 플래너)  (/planner)
├─ 전체 요약 뷰 (첫 화면)
├─ 모듈별 전체 화면 뷰 (순서 자유 변경)
└─ 상태 저장 및 불러오기 지원



🗂 프로젝트 컴포넌트 정리

공통적으로 사용되는 공동 컴포넌트개별 컴포넌트를 분리해서 정리해보았다.

공통 컴포넌트

1) 랜딩 페이지 공통 컴포넌트
├─ HeroButton (Hero 섹션)
│  ├─ DesktopButton / MacButton / iOSButton
│  └─ 반응형 정렬 및 동일 스타일 유지
├─ FeatureButton (기능 소개1 섹션)
│  ├─ 6개 모듈 소개 버튼 공통 디자인
│  └─ 아이콘 + 타이틀 + 짧은 설명 구조
└─ SpecialFeatureCard (특별한 기능 섹션)
   ├─ 3개의 기능 카드
   └─ 카드형 레이아웃: 아이콘, 제목, 설명

   
2) 로그인 / 일반 회원가입 / 비밀번호 찾기 공통 컴포넌트
├─ AuthButton (버튼)
│  ├─ 로그인 페이지와 일반 회원가입 페이지에서 공통 사용
│  └─ 정렬 / 간격 / 호버 효과 동일 유지
└─ AuthInputField (인풋창)
   ├─ 기본 상태: 회색 테두리
   ├─ 활성화 상태: 검은색 테두리
   └─ 오류 상태: 빨간색 테두리 + 경고 메시지
   

3) 회원가입 메인 페이지 공통 컴포넌트
└─ SignupButtonGroup (버튼 레이아웃)
   ├─ 회원가입 메인(선택) 페이지의 버튼 (일반 / 구글 / 카카오) 공통 디자인
   └─ 동일한 크기 / 간격 / 색상 스타일 적용   


4) 기능 선택 공통 컴포넌트

📌 공통 카드 컴포넌트
├─ ModuleCard (기능 선택 페이지)
│  ├─ Icon + Title(ko/en) + ShortDesc + Thumbnail
│  ├─ 선택 상태 : default / hover / selected
│  └─ 동일한 카드 크기 / 간격 / 그림자 스타일
│
├─ DesignCard (기능 디자인 선택 페이지)
│  ├─ PreviewImage + Title(ko/en) + Desc
│  ├─ 선택 상태 : default / hover / selected
│  └─ 동일한 카드 크기 / 간격 / 선택 효과
│
└─ SpecialFeatureCard (랜딩 페이지 특별 기능 섹션)
   ├─ Icon + Title + Desc
   └─ 동일한 카드형 레이아웃 (3장)

📌 전역 공통 컴포넌트
├─ CTAButton
│  ├─ Label : "시작하기" / "선택 완료" / "배치 완료"
│  ├─ 상태 : disabled → enabled (조건 충족 시 활성화)
│  └─ 공통 스타일 : 크기 / 간격 / 컬러 / 고정 하단 정렬
│
└─ BackButton
   ├─ 기능 디자인 선택 페이지 / 기능 배치 페이지 공통 사용
   └─ 공통 스타일 : 아이콘(◀) + 텍스트 '이전' 형태, 좌측 상단 고정 위치

페이지별 개별 컴포넌트

랜딩 페이지

1) LandingPage (route: /)

├─ Header (LandingHeader)
│  └─ NavBar (LandingNavBar)
│     ├─ LogoLink (LandingLogoLink)
│     ├─ LangToggle (LandingLangToggle)
│     └─ LoginLink (LandingLoginLink)

├─ Main (LandingMainSection)
│  ├─ HeroSection (LandingHeroSection)
│  │  ├─ HeroHeadline (LandingHeroHeadline)
│  │  ├─ HeroCtas [공통: HeroButton]
│  │  └─ HeroAnimation (LandingHeroAnimation)
│  │
│  ├─ FeaturesSection1 (LandingFeaturesSection1)
│  │  └─ FeatureGrid (LandingFeatureGrid)
│  │     └─ FeatureButton [공통: FeatureButton]
│  │
│  ├─ FeaturesSection2 (LandingFeaturesSection2)
│  │  ├─ LayoutPreview (LandingLayoutPreview)
│  │  └─ CopyBlock (LandingCopyBlock)
│  │
│  └─ SpecialFeaturesSection (LandingSpecialFeaturesSection)
│     └─ SpecialFeatureGrid (LandingSpecialFeatureGrid)
│        └─ SpecialFeatureCard [공통: SpecialFeatureCard]

└─ Footer (LandingFooter)
   ├─ FooterColumn (LandingFooterColumn ×2: 제품 / 지원)
   └─ Copyright (LandingCopyright)

로그인 페이지

2) LoginPage (route: /login)

├─ Header (로고 섹션)
│  ├─ AppLogo
│  ├─ PageTitle ("PlanMate")
│  └─ Subtitle ("오늘도 만나서 반가워요!")

└─ Main (폼 섹션)
   ├─ AuthCard
   │  └─ LoginForm
   │     ├─ EmailField  [공통: Input]
   │     │  ├─ Label("이메일")
   │     │  └─ Input(type="email", placeholder="example@email.com")
   │     ├─ PasswordField  [공통: Input]
   │     │  ├─ Label("비밀번호")
   │     │  ├─ Input(type="password", placeholder="•••••••")
   │     │  └─ PasswordVisibilityToggle (아이콘 버튼)
   │     ├─ SubmitRow  [공통: Button(preset:auth)]
   │     │  └─ LoginButton (variant="bg")
   │     ├─ HelperLinks
   │     │  ├─ ForgotPasswordLink ("비밀번호 찾기") → /forgot-password
   │     │  └─ SignUpLink ("회원가입하기") → /signup
   │     ├─ SectionDivider ("간편 로그인")
   │     └─ SocialButtons  [공통: Button(preset:auth)]
   │        ├─ KakaoLoginButton (variant="outline", icon=Kakao)
   └─        └─ GoogleLoginButton (variant="outline", icon=Google)

비밀번호 찾기 페이지

3) ForgotPassword (routes)

A) /forgot-password  ─ 이메일 입력 → 인증번호 보내기
├─ Header (로고/타이틀/설명)
│  ├─ AppLogo
│  ├─ PageTitle("비밀번호 찾기")
│  └─ Subtitle("가입시 사용한 이메일을 입력해주세요")
└─ Main
   ├─ AuthCard
   │  └─ EmailRequestForm
   │     ├─ EmailField [공통: AuthInputField]
   │     │  ├─ Label("이메일")
   │     │  └─ Input(type="email", placeholder="example@email.com")
   │     ├─ SubmitRow [공통: AuthButton]
   │     │  └─ SendCodeButton("인증번호 받기", variant="primary")
   │     └─ BackToLoginLink("← 로그인으로 돌아가기", href="/login")
   └─ (상태) 로딩/성공 토스트는 전역 토스트 사용

B) /forgot-password/code  ─ 이메일로 온 인증번호 입력
├─ Header
│  ├─ AppLogo
│  ├─ PageTitle("비밀번호 찾기")
│  └─ Subtitle("이메일로 전송된 인증번호를 입력해주세요")
└─ Main
   ├─ AuthCard
   │  └─ CodeVerifyForm
   │     ├─ TargetEmailBadge(“인증번호를 발송했습니다”, 표시 이메일)
   │     ├─ CodeInput(4자리, single cells)
   │     ├─ ResendRow("인증번호를 받지 못하셨나요? 재발송")
   │     ├─ SubmitRow [공통: AuthButton]
   │     │  └─ VerifyButton("인증하기", variant="primary")
   │     └─ BackLink("← 이전 단계로", href="/forgot-password")
   └─ (상태) 잘못된 코드/만료 표시는 필드 하단 헬퍼 or 토스트

C) /forgot-password/reset  ─ 새 비밀번호 설정
├─ Header
│  ├─ AppLogo
│  ├─ PageTitle("비밀번호 찾기")
│  └─ Subtitle("새로운 비밀번호를 설정해주세요")
└─ Main
   ├─ AuthCard
   │  └─ PasswordResetForm
   │     ├─ NewPasswordField [공통: AuthInputField]
   │     │  └─ PasswordVisibilityToggle
   │     ├─ ConfirmPasswordField [공통: AuthInputField]
   │     │  └─ PasswordVisibilityToggle
   │     ├─ SubmitRow [공통: AuthButton]
   │     │  └─ ChangePasswordButton("비밀번호 변경하기", variant="primary")
   │     └─ BackLink("← 이전 단계로", href="/forgot-password/code")
   └─ (상태) 성공 시 /login 이동 또는 완료 토스트 후 이동

회원가입 선택 페이지

3) SignupSelectPage (route: /signup)

├─ Header (로고 섹션)
│  ├─ AppLogo
│  ├─ PageTitle("회원가입")
│  └─ Subtitle("PlanMate와 함께 시작해보세요")
│
└─ Main (선택 섹션)
   ├─ AuthCard
   │  └─ SignupChoiceButtons [공통]
   │     ├─ PrimaryButton("일반 회원가입", variant="primary") → /signup/basic
   │     ├─ OutlineButton("카카오톡으로 회원가입", variant="outline", icon=Kakao)
   │     └─ OutlineButton("구글로 회원가입", variant="outline", icon=Google)
   │
   └─ BottomLinks
      └─ LoginLink("이미 회원이신가요? 로그인하기") → /login

일반 회원가입 페이지

3-1) SignupBasicWizard (route: /signup/basic)

├─ Header (로고/타이틀)
│  ├─ AppLogo
│  └─ PageTitle("일반 회원가입")

└─ Main (마법사)
   ├─ AuthCard
   │  ├─ Stepper
   │  │  └─ StepIndicator (1/2/3/4 진행 표시)
   │  │
   │  └─ StepContainer (현재 단계 내용 스위치)
   │     ├─ Step1_Name
   │     │  ├─ StepTitle("이름을 알려주세요")
   │     │  ├─ StepSubtitle("실명을 입력해주세요")
   │     │  └─ NameField [공통: AuthInputField]
   │     │     ├─ Label("이름")
   │     │     └─ Input(type="text", placeholder="홍길동")
   │     │
   │     ├─ Step2_Email
   │     │  ├─ StepTitle("이메일을 입력해주세요")
   │     │  ├─ StepSubtitle("계정으로 사용할 이메일")
   │     │  └─ EmailField [공통: AuthInputField]
   │     │     ├─ Label("이메일")
   │     │     └─ Input(type="email", placeholder="example@email.com")
   │     │
   │     ├─ Step3_Password
   │     │  ├─ StepTitle("비밀번호를 설정해주세요")
   │     │  ├─ StepSubtitle("8자 이상 / 특수문자 포함 권장")
   │     │  ├─ PasswordField        [공통: AuthInputField] + PasswordVisibilityToggle
   │     │  └─ ConfirmPasswordField [공통: AuthInputField] + PasswordVisibilityToggle
   │     │
   │     └─ Step4_Terms
   │        ├─ StepTitle("약관에 동의해주세요")
   │        ├─ StepSubtitle("서비스 이용을 위한 필수 약관입니다")
   │        ├─ TermsList
   │        │  ├─ Checkbox("[필수] 서비스 이용약관에 동의합니다")  + Link("자세히보기")
   │        │  └─ Checkbox("[필수] 개인정보 처리방침에 동의합니다") + Link("자세히보기")
   │        └─ (선택) 전체동의 토글은 나중에
   │
   │  ├─ ActionRow  [공통: AuthButton]
   │  │  ├─ PrimaryAction
   │  │  │  ├─ Step1/2/3: "다음"
   │  │  │  └─ Step4: "회원가입 완료"
   │  │  └─ SecondaryAction
   │  │     └─ "이전" (Step2/3/4에서 표시)
   │  │
   │  └─ BottomLinks
   │     └─ LoginLink("이미 회원이신가요? 로그인하기") → /login
   │
   └─ (상태/검증)
      ├─ 각 필드 [공통: InputBase] 규칙 준수 (기본/포커스/에러)
      ├─ 이메일 형식 검증, 비밀번호 일치/복잡도 검증
      └─ Step4 버튼 활성화 조건: 필수 체크 2개 모두 체크

기능 선택 페이지

4) 🧭 SetupPage (route: /setup)

├─ Header
│  ├─ AppLogo
│  ├─ PageTitle("필요한 기능만 골라 쓰는 맞춤형 플래너")
│  └─ Subtitle("원하는 기능만 조합해 나만의 플래너를 완성하세요")

├─ ModuleCarousel  ← 캐러셀 영역
│  ├─ CarouselViewport
│  │  └─ CarouselTrack (가로 스크롤)
│  │     ├─ ModuleCard [공통] — 일간 플래너
│  │     ├─ ModuleCard [공통] — 주간 플래너
│  │     ├─ ModuleCard [공통] — 월간 플래너
│  │     ├─ ModuleCard [공통] — 투두리스트
│  │     ├─ ModuleCard [공통] — 습관 트래커
│  │     └─ ModuleCard [공통] — 메모
│  │
│  ├─ NavArrows
│  │  ├─ PrevArrow  (이전 카드가 있을 때만 표시)
│  │  └─ NextArrow  (다음 카드가 있을 때만 표시)
│  │
│  └─ (옵션) ProgressIndicator (현재 위치 x/6, 필요 시)
│
└─ StickyFooter
   └─ CTAButton [공통] ("시작하기")
      ├─ 상태: disabled → enabled (선택 1개 이상 시 활성)
      └─ 위치: 페이지 하단 고정, 모바일 100% 폭

기능 디자인 선택 페이지

4-1) SetupDesignPage (route: /setup/[module])

├─ Header
│  ├─ BackButton [공통] ("← 이전")
│  ├─ PageTitle("주간 플래너 디자인을 선택하세요")  ← 모듈별 동적 타이틀
│  └─ Subtitle("원하는 디자인 스타일로 나만의 주간 플래너를 설정하세요")

├─ DesignCardGrid  ← 디자인 카드 영역
│  ├─ NoSelectionCard
│  │  ├─ Title("선택안함")
│  │  ├─ Subtitle("No Selection")
│  │  └─ Desc("이 모듈을 사용하지 않습니다")
│  │
│  ├─ DesignCard [공통] — 리스트형
│  │  ├─ Title("리스트형")
│  │  ├─ Subtitle("List Style")
│  │  ├─ Desc("요일별 세로 리스트, 체크박스 포함")
│  │  └─ PreviewImage
│  │
│  ├─ DesignCard [공통] — 그리드형
│  │  ├─ Title("그리드형")
│  │  ├─ Subtitle("Grid Style")
│  │  ├─ Desc("Google Calendar 유사한 테이블형")
│  │  └─ PreviewImage
│  │
│  └─ DesignCard [공통] — 블록형
│     ├─ Title("블록형")
│     ├─ Subtitle("Block Style")
│     ├─ Desc("요일별 카드 형태, 메모칸 포함")
│     └─ PreviewImage

└─ StickyFooter
   └─ CTAButton [공통] ("선택 완료")
      ├─ 상태: disabled → enabled (디자인 카드 선택 시)
      └─ 위치: 하단 고정

기능 배치 페이지

5) 🧭 SetupLayoutPage (route: /setup/layout)

├─ Header
│  ├─ BackButton [공통] ("← 이전")
│  ├─ PageTitle("기능을 배치하세요")
│  └─ Subtitle("원하는 위치에 배치하고 크기를 조정하세요")

├─ TopBar  ← 상단 선택 영역
│  ├─ SelectedModuleList (드래그 가능 목록)
│  │  └─ SelectedModuleChip* (N)
│  │     ├─ Icon + Label(모듈명 / 선택 디자인)
│  │     └─ DraggableHandle
│  └─ RemainingCounter (예: "남은 기능 1개")
│     └─ Badge

├─ DashboardArea
│  ├─ BoardHeader
│  │  ├─ BoardTitle("대시보드 1")
│  │  └─ BoardActions (필요 시: 새 보드 추가, 보드 전환)
│  │
│  └─ GridBoard (12 × 6)  ← 배치 보드
│     ├─ GridLines (시각 가이드)
│     ├─ EmptyHint (초기: “상단에서 기능을 선택하세요”)
│     ├─ AddSlot (센터 + 버튼)
│     └─ WidgetLayer
│        └─ Widget* (드롭된 모듈 위젯)
│           ├─ WidgetHeader (아이콘/제목/옵션)
│           ├─ WidgetBody (미리보기 자리표시자)
│           ├─ DragHandle
│           └─ ResizeHandle (우하단)
│
└─ StickyFooter
   └─ CTAButton [공통] ("배치 완료")
      ├─ 상태: 빈 보드일 때 disabled, 위젯 ≥ 1개면 enabled
      └─ 위치: 하단 고정



🗓 개발 일정

프로젝트를 실제로 개발하기 위해 필요한 작업 일정을 정리한다.
큰 흐름은 프론트엔드 세팅 → 백엔드 세팅 → 벡엔드 기능 개발 → 공동 컴포넌트 개발 → 페이지 컴포넌트 & 기능 개발 순서로 진행된다.
해당 일정들은 Jira에 등록되어서 진행 될 예정이다!

1) 프론트엔드 세팅

├─ 0. 레포지토리 & 브랜치
│   ├─ GitHub 레포 생성
│   ├─ 기본 브랜치 구성 (MAIN, DEVELOP)
│   ├─ 로컬 레포 생성 & 초기화 & 원격 연결
│   ├─ 기본 설정 파일 추가 (.gitignore / .nvmrc / .editorconfig / .gitattributes / LICENSE / README)
│   ├─ 브랜치 보호 규칙 설정
│   └─ 커밋 & 최초 푸시 (CHORE/add-base-files → DEVELOP → MAIN)
│
├─ 1. 패키지 매니저
│   ├─ pnpm 전역 설치
│
├─ 2. Next.js + TypeScript
│   ├─ `pnpm create next-app`
│   ├─ 옵션: customDailyPlanner, TS/ESLint/Tailwind=Yes, src/App Router=Yes, import alias=No
│   ├─ 생성 직후 정리: 불필요 파일 삭제, 샘플 제거, README 정리
│   ├─ 에러/로딩/404 스켈레톤 추가 (app/error.tsx, loading.tsx, not-found.tsx)
│   └─ next.config.js: 이미지 도메인 허용, 보안 헤더 기본값
│
├─ 3. Global CSS & Tailwind Config
│   ├─ globals.css 생성 및 연결
│   ├─ PostCSS 설정 확인
│   ├─ 폰트 세팅
│   ├─ Tailwind 테마 커스터마이즈
│   ├─ 전역 접근성 & 유틸리티
│   └─ 점검
│
├─ 4. 배포 (Vercel + GitHub Actions)
│   ├─ Vercel 세팅
│   ├─ Vercel 빌드 설정
│   ├─ GitHub Actions (CI)
│   └─ PR 프리뷰
│
├─ 5. 코드 스타일 & 커밋 규칙
│   ├─ Prettier + ESLint 설정
│   ├─ Husky + lint-staged
│   ├─ commitlint + Conventional Commits
│   └─ 점검
│
├─ 6. 아이콘 라이브러리 — Lucide-react
│   ├─ 라이브러리 설치
│   ├─ 아이콘 사용 방식
│   ├─ props 제어
│   └─ 점검
│
├─ 7. UI 베이스 — shadcn/ui
│   ├─ 초기화 실행
│   ├─ 스타일 가이드 정리
│   ├─ 컴포넌트 추가 & 테스트
│   └─ 점검
│
├─ 8. 상태 & 데이터 패칭
│   ├─ Zustand 전역 스토어 세팅
│   ├─ TanStack React Query 클라이언트 세팅
│   ├─ 상태 & 데이터 연동 패턴
│   └─ 점검
│
├─ 9. SEO — next-seo
│   ├─ 라이브러리 설치
│   ├─ 기본 설정(DefaultSeo) 적용
│   ├─ 페이지별 SEO 설정(NextSeo)
│   ├─ 메타/OG/트위터/정규화 링크 관리
│   └─ 점검
│
├─ 10. 백엔드 세팅 (자세한 건 아래에 👇)
│   ├─ Supabase 프로젝트 생성
│   ├─ Auth 켜기 (Email/Password)
│   ├─ profiles 테이블 + 자동 생성 트리거
│   └─ RLS 기본 정책(user_id = auth.uid())
│
├─ 11. API 레이어 세팅
│   ├─ Supabase API 문서 수집
│   │   ├─ Base URL / 공통 헤더 / 인증 방식(쿠키·토큰)
│   │   └─ 엔드포인트 표 정리(메서드, 경로, 요청/응답 스펙)
│   ├─ axios 설치
│   │   └─ pnpm add axios
│   ├─ .env/.env.local 만들기 + .env.example 커밋
│   │   ├─ NEXT_PUBLIC_API_BASE_URL=...
│   │   └─ (필요 시) API_TIMEOUT=10000
│   ├─ 공통 클라이언트(axios)
│   │   ├─ baseURL, 기본 헤더, 타임아웃
│   │   └─ 응답/에러 인터셉터 공통 처리
│   ├─ 기능별 API 함수 파일
│   │   ├─ src/shared/api/auth.ts
│   │   ├─ src/shared/api/planner.ts
│   │   ├─ src/shared/api/modules.ts
│   │   └─ (공통 타입) src/shared/api/types.ts
│   ├─ 컴포넌트에서 직접 호출 (import 해서 사용)
│   │   └─ React Query 연동은 이후 단계에서 처리
│   └─ 스모크 테스트
│       ├─ GET/POST 1회씩 호출 확인
│       └─ CORS/에러 메시지 표출 확인
│
├─ 12. 사이트맵 — next-sitemap
│   ├─ 패키지 설치 (devDependencies)
│   ├─ 환경변수 정리 (SITE_URL: 로컬/프리뷰/프로덕션)
│   ├─ 기본 설정 파일 생성 (next-sitemap.config.mjs)
│   │   ├─ siteUrl / outDir / generateRobotsTxt
│   │   ├─ exclude 규칙(/api/*, /admin/*, /debug, /lab/* 등)
│   │   └─ transform 기본 정책(lastmod/priority/changefreq)
│   ├─ 빌드 연동 (package.json postbuild / 수동 생성 스크립트)
│   ├─ robots.txt 정책 설계 (크롤러 허용/차단, Sitemap 링크)
│   ├─ i18n & 멀티 도메인 (alternateRefs/hreflang)
│   ├─ 대규모 라우트 대비 (sitemapSize/분할 인덱스)
│   ├─ 동적 라우트 처리 전략 (App Router + pre-render 경로 수집)
│   ├─ 서버 생성 사이트맵 병합 (additionalSitemaps)
│   ├─ CI/CD 적용 (프리뷰/프로덕션 분기, Vercel 환경변수)
│   ├─ 캐노니컬/중복 방지 연결 (next-seo와 역할 분리 메모)
│   ├─ 생성물 점검 체크리스트 (public/sitemap.xml, robots.txt)
│   └─ 제출 & 모니터링 (Search Console/Bing Webmaster 제출)
│
├─ 13. 테스트 (단위/컴포넌트) — Vitest (⚠️ 여기서부터는 테스트이기 때문에 컴포넌트를 만들면서 할 예정)
│   ├─ Vitest + RTL 세팅
│   └─ 스모크 테스트 1개, CI 연동
│
├─ 14. E2E — Playwright
│   ├─ 기본 세팅(크로미움)
│   └─ 스모크 시나리오(/, /login, /signup)
│
└─ 15. 모니터링 — Sentry
    ├─ SDK 초기화(DSN)
    └─ 샘플 에러 수

2) 벡엔드 세팅

┌─ 백엔드 세팅
├─ 1) Supabase 프로젝트 생성
│   ├─ 이메일/비번 로그인 켜기 (Auth ON)
│   ├─ 프로젝트 주소(URL) / 키(anon key) 확인
│   └─ Redirect URL 등록 (http://localhost:3000 과 배포 주소 등록)
│
├─ 2) DB 스키마(테이블) 만들기
│   ├─ profiles (내정보/프로필, 회원가입 시 자동 생성 트리거 붙임)
│   ├─ todos (투두 = 할일)
│   ├─ events (일정 = 일/주/월 공통)
│   ├─ habits (습관)
│   ├─ habit_checks (습관 체크 기록)
│   ├─ notes (메모)
│   └─ dashboard_layouts (대시보드 배치 저장)
│
├─ 3) 자동 프로필 생성
│   └─ 회원가입하면 profiles에 한 줄 자동 생성되게
│
├─ 4) 권한 관리 (RLS 정책)
│   ├─ 기본: user_id = auth.uid() 인 경우만 읽기/쓰기
│   └─ profiles: id = auth.uid() 인 경우만 읽기/수정
│
└─ 5) 공유 보기 (선택 기능)
    ├─ shares 테이블: owner_id, resource, resource_id, slug
    └─ /share/[slug] → 로그인 없이 “읽기 전용”으로 보기만 가능

3) 벡엔드 기능 개발

┌─ 🛠️ 벡엔드 기능 개발
├─ 1) 🔑 인증·프로필
│ ├─ 로그인/회원가입, 세션 유지/로그아웃
│ ├─ profiles 읽기·수정(닉네임 등), 최초 로그인 시 기본값 생성
│ └─ 계정 탈퇴(내 데이터 정리 후 auth 사용자 삭제)
│
├─ 2) 📝 투두
│ ├─ 목록/추가/수정/삭제, 완료 토글
│ ├─ 정렬/필터(완료여부, 마감 임박), 페이지네이션
│ └─ RLS로 A/B 교차 접근 차단, 기본 인덱스(user_id, created_at)
│
├─ 3) 📅 일정(일간/주간/월간)
│ ├─ 기간 조회(시작/끝), 생성/수정/삭제
│ ├─ 겹침 허용 정책 정의, note(메모) 필드 옵션
│ └─ 조회 성능 확보(user_id, start_at 인덱스)
│
├─ 4) 📊 습관 & ✅ 체크
│ ├─ 습관 생성/수정/삭제, 날짜별 체크 ON/OFF
│ ├─ 주/월 합계는 우선 프론트 계산(추후 RPC 집계 가능)
│ └─ 체크 중복 방지(같은 날 한 번만)
│
├─ 5) 🗒️ 메모
│ ├─ 메모 작성/수정/삭제, 최신순 조회
│ ├─ 간단 키워드 검색(선택)
│ └─ 길이 제한 등 기본 유효성
│
├─ 6) 🖼️ 대시보드 레이아웃
│ ├─ 최초 1건 생성 규칙, layout_json 저장/불러오기
│ ├─ 버전 필드로 스키마 변경 대비(version)
│ └─ 새로고침/재로그인 시 복원 확인
│
├─ 7) 🔗 공유(읽기 전용)
│ ├─ 공유 링크 발급(slug 난수), 만료/폐기(선택)
│ ├─ /share/[slug] 읽기 전용 페이지(민감 필드 제외)
│ └─ 수정 API 차단(보기만 가능)
│
└─ 8) 🛡️ 안정화
├─ RLS 스모크 테스트(A/B 교차 차단), 에러 포맷 통일(JSON)
├─ 기본 인덱스 점검 및 쿼리 확인
└─ Postman/Insomnia로 전 기능 시연 가능 상태

4) 공동 컴포넌트 개발

[공통 컴포넌트 개발 일정 — 리네이밍 반영] ✨

0) 🚧 선행(아이콘/레이아웃)
├─ 0-0) AppRoute 파일 추가 및 정리 (페이지 파일 생성)
├─ 0-1) 이미지/아이콘 저장
│  ├─ 경로: public/images/{landing,modules,planner,og}
│  ├─ 포맷: 사진=webp(필요시 jpg), 로고/일러스트/아이콘=svg
│  ├─ 네이밍: section-role-variant@2x.webp (예: hero-mac-mock@2x.webp)
│  └─ 기타: next.config.js 이미지 도메인 허용 / ASSETS_LICENSES.md 기록
├─ 0-2) 아이콘 컴포넌트화
│  ├─ 라이브러리: lucide-react
│  ├─ 래퍼: src/shared/Icon.tsx (props 기본값 size=24, strokeWidth=1.5)
│  └─ 커스텀: src/shared/icons/ (svg→React 변환, Icon 래퍼로 통일)
└─ 0-3) 공통 레이아웃
   └─ 각 페이지마다 확인해야함 (공통 컴포넌트 집어넣을거 있는지)

1) 🏠 랜딩 공통
├─ HeroButton
│  ├─ DesktopButton / MacButton / iOSButton (동일 pill 레이아웃)
│  ├─ 상태: selected=검정/흰텍스트, default=흰배경/연회색 테두리
│  └─ 반응형: 모바일 1열 → 태블릿 2열 → 데스크톱 가로 정렬
├─ FeatureButton (기능 소개1 섹션)
│  ├─ 6개 모듈 버튼 공통 디자인
│  └─ 아이콘 + 타이틀 + 짧은 설명 = 단일 버튼 타일, 높이/패딩/간격 균일
└─ SpecialFeatureCard (특별한 기능 섹션)
   ├─ 3장 동일 카드형 레이아웃(큰 라운드/연한 테두리/미세 그림자)
   └─ 아이콘 배지 + 제목 + 설명 정렬 고정

2) 🔐 인증 공통 (로그인 / 일반 회원가입 / 비밀번호 찾기)
├─ AuthButton
│  ├─ 정렬/간격/호버 동일 (primary/outline 등 variant로 분기)
│  └─ 로그인/회원가입/비번찾기 모든 페이지에서 공통 사용
└─ AuthInputField
   ├─ 기본=회색 테두리 / 포커스=검정 / 오류=빨강 + 헬퍼 메시지
   └─ aria-describedby로 오류 텍스트 연결

3) 🎯 회원가입 메인 공통
└─ SignupButton
   ├─ 버튼 3종(일반/구글/카카오) 동일 크기/간격/색상
   └─ 아이콘+텍스트 정렬 통일, 최소 탭 영역 44px+

4) 🧭 기능 선택 공통
├─ ModuleCard (기능 선택 페이지)
│  ├─ Icon + Title(ko/en) + ShortDesc + Thumbnail
│  ├─ 상태: default / hover / selected (selected 시 테두리·그림자 강화)
│  └─ 카드 크기/간격/그림자 스타일 통일
├─ DesignCard (기능 디자인 선택 페이지)
│  ├─ PreviewImage + Title(ko/en) + Desc
│  ├─ 상태: default / hover / selected
│  └─ 카드 크기/간격/선택 효과 통일
└─ SpecialFeatureCard (랜딩 특별 기능 섹션 재사용)
   ├─ Icon + Title + Desc
   └─ 동일 카드형 레이아웃(3장)

5) 🧩 기능 선택 전역 공통
├─ CTAButton
│  ├─ Label: "시작하기" / "선택 완료" / "배치 완료"
│  ├─ 상태: disabled → enabled (조건 충족 시 활성)
│  └─ 위치: 하단 고정(모바일 100% 폭), 크기/간격/컬러 공통
└─ BackButton
   ├─ 사용처: 디자인 선택 / 기능 배치 페이지
   └─ 스타일: 아이콘(◀) + ‘이전’ 텍스트, 좌상단 고정

5) 페이지 개발

5 - 1 랜딩페이지

0) App Router 골격 — (Landing-Layout-Skeleton)
└─ src/app/(marketing)/(landing)/
   ├─ layout.tsx           // 랜딩 전용 라우트 그룹만 만든 상태. 헤더/푸터는 아직 안 넣음. 메타데이터 틀만 잡는 수준.
   └─ page.tsx             // 랜딩 엔트리. 여기서 섹션을 순서대로 배치할 예정이라는 ‘자리’만 만들어둠.

1) 헤더 + 푸터 제작 → layout.tsx에 실제로 넣기 — (Landing-Chrome)
└─ src/components/landing/
   ├─ LandingHeader.tsx          // 상단 헤더. 로고/언어 토글/로그인 버튼 들어올 자리.
   ├─ LandingNavBar.tsx          // 헤더 내부 네비게이션 구조.
   ├─ LandingFooter.tsx          // 하단 푸터 래퍼.
   ├─ LandingFooterLinks.tsx     // 브랜드/지원/정책 등 링크 모음.
   ├─ LandingCopyright.tsx       // © 문구, 연도 자동화 가능.
   └─ LandingWrapper.tsx         // 메인페이지의 레이아웃 구조
└─ src/app/(marketing)/(landing)/layout.tsx
   └─ 위 컴포넌트들을 실제로 import해서 `<header></header> + {children} + <footer></footer>` 구조를 완성
      // 이 시점부터 layout은 ‘비어 있는 상태’가 아니고, 랜딩 공통 크롬이 고정된 상태가 됨.

2) 공통 프리젠테이션 조각 — (Landing-SectionBase)
└─ src/components/landing/
   └─ LandingMainSection.tsx         // 모든 섹션이 공통으로 쓰는 래퍼. 패딩, container, max-width 같은 레이아웃 좌표계 통일.

3) Hero 섹션 — (Landing-Hero)
└─ src/components/landing/
   ├─ LandingHeroSection.tsx     // 랜딩 첫 화면. LCP 대상. H1은 여기서 1회만.
   ├─ LandingHeroTitle.tsx    // 메인 카피/서브카피.
   ├─ LandingHeroCtas.tsx        // shared/HeroButton 3종 정렬.
   └─ LandingHeroAnimation.tsx   // 필요 시 client. 시각적 요소는 지연로딩.

4) 기능 소개 섹션 1 — (Landing-Features1)
└─ src/components/landing/
   ├─ LandingFeaturesSection1.tsx // “일간/주간/월간/투두/습관/메모” 6모듈 하이라이트
   └─ LandingFeatureGrid.tsx      // shared/FeatureButton 6개를 그리드로 배치

5) 기능 소개 섹션 2 — (Landing-Features2)
└─ src/components/landing/
   ├─ LandingFeaturesSection2.tsx // “모듈 자유배치” 설명하는 2열 섹션(모바일 1열)
   ├─ LandingLayoutPreview.tsx    // 배치 데모/이미지. next/image 권장.
   └─ LandingCopyBlock.tsx        // 제목/설명/핵심 포인트 리스트

6) 특별한 기능 섹션 — (Landing-SpecialFeatures)
└─ src/components/landing/
   ├─ LandingSpecialFeaturesSection.tsx // 차별화 포인트 인트로(H2)
   └─ LandingSpecialFeatureGrid.tsx     // shared/SpecialFeatureCard 3장 동일 레이아웃

7) 페이지 조립(최종 배치) — (Landing-Compose)
└─ src/app/(marketing)/(landing)/page.tsx
   ├─ LandingHeroSection
   ├─ LandingFeaturesSection1
   ├─ LandingFeaturesSection2
   └─ LandingSpecialFeaturesSection

8) SSG/ISR 마감 — (Landing-SEO)
└─ src/app/(marketing)/(landing)/page.tsx
   ├─ export const revalidate = ...           // 전역 ISR 주기(예: 21600=6h) 한 번만 선언
   └─ 섹션 내부 fetch가 있다면 next: { revalidate }로 섹션별 주기 분리  // 없음
   // metadata는 고정이면 layout에서, 동적이면 page에서 generateMetadata로

9) 접근성·반응형·성능 — (Landing-Accessibility)
└─ 각 컴포넌트
   ├─ 페이지당 H1 1회(히어로)
   ├─ aria-label / role 지정
   ├─ 모바일 그리드/여백 재점검
   └─ 이미지 alt + CLS 방지(width/height 지정)
   
10) 애니메이션 — (Landing-Animation)
└─ src/components/landing/
   ├─ Hero 섹션                        // Desktop CTA 버튼 bounse
   ├─ Feature1 섹션                    // Fade-in 애니메이션 (Inview 커스텀 hook)
   ├─ Feature2 섹션                    // Fade-in 애니메이션 (Inview 커스텀 hook)
   ├─ SpecialFeature 섹션              // Fade-in 애니메이션 (Inview 커스텀 hook)
   └─ FullPage                        // 섹션간 이동 scroll 애니메이션 (FullPageScroll 커스텀 hook) 

5 - 2 로그인페이지

0) App Router 골격 — (Auth-Layout-Skeleton)
└─ src/app/(auth)/
   ├─ layout.tsx           // Auth 전용 라우트 그룹만 만든 상태. 배경색·중앙 정렬 등 기본 틀만.
   └─ login/
      └─ page.tsx          // /login 엔트리. Header(로고 섹션) + Main(폼 섹션) 배치 예정.

1) 헤더 섹션 — (Auth-Header)
└─ src/components/auth/
   ├─ AuthHeader.tsx          // 상단 Header 래퍼. 로고 + children(타이틀/서브타이틀) 세로 정렬.
   └─ login/
      ├─ LoginPageTitle.tsx   // "로그인" 페이지 타이틀 (h1/h2 레벨 관리).
      └─ LoginSubtitle.tsx    // "오늘도 만나서 반가워요!" 서브 카피.
└─ src/shared/AppLogo.tsx     // 서비스 공통 로고 컴포넌트. Header 상단에 배치.

2) 메인/카드 섹션 — (Auth-LoginMain)
└─ src/components/auth/login/
   ├─ LoginMain.tsx            // <main> 래퍼. 헤더 아래 폼 섹션 중앙 정렬/레이아웃.
   └─ AuthCard.tsx             // 로그인 폼을 감싸는 카드 UI (bg-white, radius, shadow 등).

3) 로그인 폼 베이스 — (Auth-LoginForm)
└─ src/components/auth/login/
   ├─ LoginForm.tsx               // <form> 래퍼. submit 핸들러/validation 자리.
   ├─ EmailField.tsx              // Label("이메일") + Input(type="email", placeholder="example@email.com").
   ├─ PasswordField.tsx           // Label("비밀번호") + Input(type="password") + PasswordVisibilityToggle.
   ├─ PasswordVisibilityToggle.tsx// 비밀번호 표시 토글 아이콘 버튼.
   └─ SubmitRow.tsx               // LoginButton(preset:auth, variant:bg) 정렬/로딩 상태 관리.

4) 헬퍼 링크 & 구분선 — (Auth-Helpers)
└─ src/components/auth/login/
   ├─ HelperLinks.tsx             // 비밀번호 찾기/회원가입 링크 묶음.
   ├─ ForgotPasswordLink.tsx      // "비밀번호 찾기" → /forgot-password.
   ├─ SignUpLink.tsx              // "회원가입하기" → /signup.
   └─ SectionDivider.tsx          // "간편 로그인" 구분선 (좌우 선 + 텍스트).

5) 소셜 로그인 섹션 — (Auth-SocialLogin)
└─ src/components/auth/login/
   ├─ SocialButtons.tsx           // 소셜 로그인 버튼 그룹.
   ├─ KakaoLoginButton.tsx        // 카카오 로그인 버튼 (variant:outline, icon=Kakao).
   └─ GoogleLoginButton.tsx       // 구글 로그인 버튼 (variant:outline, icon=Google).
└─ src/shared/icons/
   ├─ KakaoIcon.tsx               // 카카오 로고 아이콘.
   └─ GoogleIcon.tsx              // 구글 로고 아이콘.

6) 페이지 조립(최종 배치) — (Auth-LoginCompose)
└─ src/app/(auth)/login/page.tsx
   ├─ LoginHeader
   │  ├─ AppLogo
   │  ├─ LoginPageTitle       // "PlanMate"
   │  └─ LoginSubtitle        // "오늘도 만나서 반가워요!"
   └─ LoginMain
      └─ AuthCard
         └─ LoginForm
            ├─ EmailField
            ├─ PasswordField
            ├─ SubmitRow
            ├─ HelperLinks
            ├─ SectionDivider
            └─ SocialButtons

7) SEO/메타데이터 — (Auth-SEO)
└─ src/app/(auth)/layout.tsx
   ├─ export const metadata = { title: "로그인 | PlanMate", description: "PlanMate에 로그인하고 오늘의 플랜을 시작하세요." }
   └─ Auth 전용 공통 메타데이터. 페이지별 generateMetadata 필요 시 page.tsx에서 오버라이드 가능.

8) 접근성·반응형·성능 — (Auth-Accessibility)
└─ 각 컴포넌트
   ├─ 페이지당 H1 1회 (LoginPageTitle)
   ├─ form aria-label="로그인 폼", 에러 영역 aria-live 적용
   ├─ Input: autoComplete="email" / "current-password"
   ├─ 토글 버튼: aria-label="비밀번호 표시" / aria-pressed
   ├─ 소셜 버튼: "카카오로 로그인", "구글로 로그인" 텍스트 명시
   └─ 모바일 전체폭, 데스크탑 max-w(400~480px) 중앙 정렬로 반응형 조정.

0개의 댓글