
프로젝트의 기술 스택은 이미 확정되었고, 디자인도 어느 정도 완성된 상태다. 이제 실제 구현을 위한 기반으로 페이지 구조와 라우팅을 정리해 본다.
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에 등록되어서 진행 될 예정이다!
├─ 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)
└─ 샘플 에러 수
┌─ 백엔드 세팅
├─ 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] → 로그인 없이 “읽기 전용”으로 보기만 가능
┌─ 🛠️ 벡엔드 기능 개발
├─ 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로 전 기능 시연 가능 상태
[공통 컴포넌트 개발 일정 — 리네이밍 반영] ✨
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
├─ 사용처: 디자인 선택 / 기능 배치 페이지
└─ 스타일: 아이콘(◀) + ‘이전’ 텍스트, 좌상단 고정
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)
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) 중앙 정렬로 반응형 조정.