🧑‍💻 바이브 코딩

[바이브 코딩 #3] 데이트 코스 추천 서비스 개발기

수구리 2025. 6. 25. 10:12
반응형

코스모스 (Course-More-Us) - 3일차 개발 기록

개발 기간: 2025년 06월 17일
개발자: yangsuyoung
프로젝트: 데이트 코스 추천 서비스 "코스모스"

📋 개발 개요

3일차는 관리자 페이지 리팩터링, UI/UX 개선, 그리고 소셜 로그인 공통 로직 리팩터링에 집중했습니다. 기존 코드의 일관성을 높이고 재사용 가능한 컴포넌트 체계를 구축하여 유지보수성을 크게 향상시켰습니다.

🚀 주요 구현 사항

1. 관리자 페이지 리팩터링 ✅

관리자 페이지

공통 컴포넌트 적극 활용

기존의 분산된 UI 요소들을 표준화된 공통 컴포넌트로 통일했습니다.

수정된 파일들:

  • app/routes/admin.users._index.tsx
  • app/routes/admin.places._index.tsx
  • app/routes/admin.places.new.tsx

적용된 개선사항:

  • Button 컴포넌트 적용: 일관된 버튼 스타일 및 상호작용
  • ROUTES 상수 활용: 하드코딩된 경로를 상수로 대체
  • formatDate 유틸리티 적용: 날짜 표시 일관성 확보
  • Rating null 체크 추가: 안전한 데이터 렌더링
// 수정 전
<button className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
  수정
</button>

// 수정 후  
<Button variant="primary" size="sm">
  수정
</Button>

2. 메인 페이지 로그인 버튼 스타일 개선 ✅

문제 상황

메인 페이지의 보라색-핑크 그래디언트 배경에서 기존 로그인 버튼이 잘 보이지 않는 가시성 문제가 발생했습니다.

해결 방안

Button 컴포넌트 확장:

  • white variant 추가: bg-white text-purple-600 hover:bg-gray-100
  • purple variant 추가: 추후 확장성을 위한 준비
  • 메인 페이지에서 variant="white" 적용
// app/components/ui/Button.tsx에 추가
const variants = {
  // ... 기존 variants
  white: 'bg-white text-purple-600 hover:bg-gray-100 focus:ring-purple-500 shadow-md',
  purple: 'bg-purple-600 text-white hover:bg-purple-700 focus:ring-purple-500'
}

3. 인증 페이지 배경 스타일 통일화 ✅

브랜드 일관성 확보

메인 페이지와 동일한 그래디언트 배경을 로그인/회원가입 페이지에도 적용하여 브랜드 일관성을 확보했습니다.

적용된 스타일:

  • 통일된 배경: bg-gradient-to-br from-purple-400 via-pink-500 to-red-500
  • 반투명 카드: bg-white/95 backdrop-blur-sm rounded-2xl p-8 shadow-2xl
  • 텍스트 색상: 흰색 기반으로 변경하여 가독성 향상

4. 로그인 폼 UI 세부 개선 ✅

사용자 피드백 반영

실제 사용자 스크린샷을 바탕으로 세부적인 UI 문제들을 해결했습니다.

개선된 요소들:

  • Input 필드 테두리: border-gray-300 hover:border-gray-400 추가
  • Focus 상태: focus:border-purple-300 명확한 포커스 표시
  • 비활성화 버튼: bg-gray-500 border border-gray-600 text-gray-300으로 가시성 향상

5. 소셜 로그인 공통 로직 리팩터링 🔥

문제 분석

기존 소셜 로그인 구현에서 발견된 문제점들:

  • 중복된 핸들러 함수: handleKakaoLogin, handleGoogleLogin 등 반복적인 코드
  • 개별 상태 관리: 각 제공자별로 별도의 로딩 상태 관리
  • 확장성 부족: 새로운 소셜 제공자 추가 시 많은 코드 중복
  • 유지보수 어려움: 로직 변경 시 여러 곳 수정 필요

해결 방안: 공통 훅 및 컴포넌트 구조

1) useSocialLogin 훅 생성

파일: app/hooks/useSocialLogin.ts

export type SocialProvider = 'google' | 'kakao' | 'apple' | 'facebook';

interface UseSocialLoginOptions {
  flow?: 'login' | 'signup';
  onSuccess?: () => void;
  onError?: (error: string) => void;
}

export function useSocialLogin(options: UseSocialLoginOptions = {}) {
  const [loadingStates, setLoadingStates] = useState<Record<SocialProvider, boolean>>({
    google: false, kakao: false, apple: false, facebook: false
  });

  const handleSocialLogin = async (provider: SocialProvider) => {
    // 통합된 소셜 로그인 로직
    // 중복 클릭 방지, 에러 처리, 로딩 상태 관리 등
  };

  return {
    loadingStates,
    handleSocialLogin,
    isLoading: (provider: SocialProvider) => loadingStates[provider]
  };
}

주요 특징:

  • 타입 안전성: TypeScript로 모든 제공자 타입 정의
  • 통합 상태 관리: 모든 소셜 제공자의 로딩 상태를 하나의 객체로 관리
  • 유연한 설정: flow, onSuccess, onError 콜백 지원
  • 에러 처리: 제공자별 한국어 에러 메시지 제공
2) SocialLoginButton 컴포넌트 생성

파일: app/components/common/SocialLoginButton.tsx

interface SocialLoginButtonProps {
  provider: SocialProvider;
  isLoading: boolean;
  onClick: () => void;
  disabled?: boolean;
  className?: string;
}

// 제공자별 브랜드 설정
const socialProviderConfig = {
  google: {
    name: '구글',
    className: 'bg-white border border-gray-300 text-gray-700',
    icon: <GoogleIcon />
  },
  kakao: {
    name: '카카오', 
    className: 'bg-yellow-400 text-gray-900',
    icon: <KakaoIcon />
  }
  // ... Apple, Facebook 등
}

주요 특징:

  • 브랜드 일관성: 각 제공자의 공식 색상 및 아이콘 사용
  • 자동 텍스트: mode에 따라 "로그인" vs "시작하기" 자동 변경
  • 완전 재사용: 모든 페이지에서 동일한 컴포넌트 사용
  • 확장성: 새 제공자 추가 시 설정만 업데이트
3) 기존 페이지 리팩터링

로그인/회원가입 페이지 변화:

// 수정 전 (60+ 줄의 중복 코드)
const [isKakaoLoading, setIsKakaoLoading] = useState(false);
const [isGoogleLoading, setIsGoogleLoading] = useState(false);

const handleKakaoLogin = async () => {
  if (isKakaoLoading) return;
  setIsKakaoLoading(true);
  try {
    const supabase = createSupabaseClient();
    const { error } = await supabase.auth.signInWithOAuth({
      provider: 'kakao',
      options: { redirectTo: `${window.location.origin}/auth/callback?flow=login` }
    });
    // ... 에러 처리
  } catch (error) {
    // ... 예외 처리
  }
};

// 수정 후 (3줄로 단순화)
const { handleSocialLogin, isLoading: isSocialLoading } = useSocialLogin({
  flow: 'login'
});

// JSX도 대폭 단순화
<SocialLoginButton
  provider="kakao"
  isLoading={isSocialLoading('kakao')}
  onClick={() => handleSocialLogin('kakao')}
  mode="login"
/>

리팩터링 결과

정량적 개선:

  • 중복 코드 제거: 60+ 줄의 중복 코드 제거
  • 파일 수: 4개 파일 추가, 기존 2개 파일 대폭 수정
  • 코드 라인: +244 추가, -211 삭제 (순증 +33줄로 기능 확장)

정성적 개선:

  • 확장성: 새 소셜 제공자 추가 시 설정만 변경
  • 일관성: 모든 페이지에서 동일한 UI/UX
  • 타입 안전성: TypeScript 기반 완전한 타입 체크
  • 유지보수성: 로직 변경 시 한 곳만 수정

6. 컴포넌트 활용 철학 확립 ✅

새로운 개발 원칙

사용자 요청에 따라 향후 모든 컴포넌트 개발에 적용할 원칙들을 확립했습니다:

  1. 기존 컴포넌트 우선 활용
    • Button, Input, Modal 등 검증된 컴포넌트 사용
    • 새 컴포넌트 생성 전 기존 컴포넌트 확장 검토
  2. 확장 가능한 설계
    • variant, size 등의 props로 다양한 스타일 지원
    • 옵션 추가 시 기존 사용처에 영향 없도록 설계
  3. 일관된 디자인 시스템
    • 색상, 타이포그래피, 간격 등 디자인 토큰 활용
    • 브랜드 가이드라인 준수
  4. 시스템 통합 활용
    • ROUTES 상수 활용
    • 유틸리티 함수 적극 사용
    • 타입 정의 재사용

📊 기술적 개선 사항

1. TypeScript 타입 안전성 강화

SocialProvider 타입 정의

export type SocialProvider = 'google' | 'kakao' | 'apple' | 'facebook';
  • 모든 소셜 제공자를 타입으로 제한
  • 컴파일 타임에 오타 및 잘못된 제공자 사용 방지

인터페이스 표준화

interface UseSocialLoginOptions {
  flow?: 'login' | 'signup';
  onSuccess?: () => void;
  onError?: (error: string) => void;
}

2. 상태 관리 최적화

통합된 로딩 상태

const [loadingStates, setLoadingStates] = useState<Record<SocialProvider, boolean>>({
  google: false, kakao: false, apple: false, facebook: false
});
  • 개별 useState 대신 객체 기반 통합 관리
  • 메모리 효율성 및 일관성 향상

3. 에러 처리 표준화

제공자별 한국어 메시지

const providerNames = {
  google: '구글', kakao: '카카오', 
  apple: 'Apple', facebook: '페이스북'
};

const errorMessage = `${providerNames[provider]} 로그인 중 오류가 발생했습니다: ${error.message}`;

4. 컴포넌트 설계 패턴

Composition Pattern 적용

// 설정과 컴포넌트 분리
const socialProviderConfig = { /* 설정 */ };

export default function SocialLoginButton({ provider, ...props }) {
  const config = socialProviderConfig[provider];
  // 설정 기반 렌더링
}

🎯 Git 커밋 히스토리

관리자 페이지 리팩터링

refactor: 남은 관리자 페이지들 리팩터링 완료
- Button 컴포넌트 및 ROUTES 상수 적용
- rating null 체크 추가

UI/UX 개선

fix: 메인 페이지 로그인 버튼 스타일 개선
design: 로그인/회원가입 페이지 배경 스타일 통일  
fix: 로그인 폼 UI 개선
fix: 로그인 버튼 비활성화 상태 색상 개선

Google 로그인 구현

feat: Google 로그인 기능 추가
- 로그인/회원가입 페이지에 Google OAuth 버튼 추가
- 카카오와 동일한 플로우로 구현

소셜 로그인 리팩터링

refactor: 소셜 로그인 공통 로직 리팩터링
- useSocialLogin 훅 및 SocialLoginButton 컴포넌트 생성으로 중복 코드 제거
- 모든 소셜 제공자 지원

💡 배운 점 및 통찰

1. 리팩터링의 가치

문제: 중복된 코드로 인한 유지보수 어려움
해결: 공통 로직 추출 및 재사용 가능한 컴포넌트 설계
결과: 60+ 줄의 중복 코드 제거, 확장성 대폭 향상

2. 점진적 개선의 중요성

  • 1단계: 기본 기능 구현 (카카오 로그인)
  • 2단계: 기능 확장 (구글 로그인 추가)
  • 3단계: 리팩터링 (공통 로직 추출)
  • 결과: 안정적이고 확장 가능한 구조

3. 사용자 피드백의 중요성

실제 사용자의 스크린샷과 피드백을 통해:

  • 로그인 버튼 가시성 문제 발견
  • Input 필드 구분선 부재 인식
  • 비활성화 상태 색상 개선 필요성 확인

4. 타입 안전성과 개발 효율성

TypeScript의 적극 활용으로:

  • 컴파일 타임 오류 방지
  • IDE 자동완성 지원 향상
  • 리팩터링 시 안전성 보장

🔮 다음 단계 계획

1. C 단계: 고급 추천 시스템 구현

  • 거리 기반 추천 로직: 사용자 위치 기반 데이트 코스 추천
  • 카카오 맵 API 연동: 실시간 위치 정보 및 경로 안내
  • 개인화 추천 알고리즘: 사용자 선호도 학습 기반 추천

2. 추가 소셜 로그인 확장

이제 새로운 소셜 로그인 추가가 매우 쉬워졌습니다:

  • Apple 로그인: 설정 활성화만으로 즉시 사용 가능
  • Facebook 로그인: 동일한 구조로 빠른 추가 가능
  • 네이버 로그인: 한국 사용자를 위한 추가 옵션

3. 성능 최적화

  • 컴포넌트 지연 로딩: 소셜 로그인 버튼 lazy loading
  • 상태 최적화: React.memo 및 useMemo 적용
  • 번들 최적화: 소셜 제공자별 코드 분할

4. 테스트 코드 작성

  • 단위 테스트: useSocialLogin 훅 테스트
  • 컴포넌트 테스트: SocialLoginButton 렌더링 테스트
  • 통합 테스트: 전체 로그인 플로우 테스트

📈 개발 통계

코드 변경 통계

  • 생성된 파일: 4개
    • app/hooks/useSocialLogin.ts
    • app/components/common/SocialLoginButton.tsx
    • app/components/common/index.ts
    • app/hooks/index.ts
  • 수정된 파일: 2개
    • app/routes/auth.login.tsx
    • app/routes/auth.signup.tsx
  • 총 라인 수: +244 추가, -211 삭제

컴포넌트 재사용성 지표

  • 재사용되는 컴포넌트: SocialLoginButton (4개소에서 사용)
  • 재사용되는 훅: useSocialLogin (2개 페이지에서 사용)
  • 중복 제거율: 약 85% (60줄 → 9줄)

타입 안전성 개선

  • 새로운 타입 정의: 2개 (SocialProvider, UseSocialLoginOptions)
  • 타입 체크 추가: 모든 소셜 제공자 관련 함수에 타입 적용
  • 런타임 에러 방지: 컴파일 타임 타입 체크로 사전 방지

🏆 핵심 성과

1. 코드 품질 향상

  • 중복 제거: 60+ 줄의 중복 코드 완전 제거
  • 재사용성: 모든 소셜 로그인이 공통 컴포넌트 사용
  • 일관성: 통일된 UI/UX 및 에러 처리

2. 개발 효율성 증대

  • 새 제공자 추가: 5분 내 새로운 소셜 로그인 추가 가능
  • 유지보수: 로직 변경 시 한 곳만 수정
  • 확장성: 미래 요구사항에 유연하게 대응

3. 사용자 경험 개선

  • 일관된 브랜딩: 모든 페이지에서 통일된 디자인
  • 명확한 피드백: 로딩 상태 및 에러 메시지 개선
  • 접근성: 색상 대비 및 포커스 상태 개선

개발 완료: 소셜 로그인 공통 로직 리팩터링 및 UI/UX 개선 완료
다음 목표: C 단계 고급 추천 시스템 구현 준비

반응형