챗봇 공부 노트

[18편] Part 2 마이페이지 코드 + 설계의도

frontend-diary-log 2026. 2. 6. 01:58

 

📘 Aura_AI Day 18 — Part 2 통합본

코드 심화 설명 + 오류 해결 기록 (실무 관점)

안녕하세요.
Aura AI 프로젝트 Day 18 – Part 2 기록입니다.

Part 1에서 마이페이지 CRUD + OAuth 통합 구조의 전체 흐름을 설명드렸다면,
이번 글에서는 다음 내용을 더 깊이 다룹니다.

  • 왜 이런 구조를 선택했는지
  • 각 코드/문법이 무엇을 의미하는지
  • 다른 방식과 비교했을 때 왜 더 효율적인지
  • 실제 개발 중 발생했던 오류와 해결 과정

단순 구현 기록이 아니라,
👉 “실서비스 기준 설계 이유” 중심으로 정리한 심화편입니다.


✅ 오늘 다룰 핵심 주제

  • get_user() 통합 조회 설계
  • PATCH 기반 부분 업데이트 전략
  • 이미지 업로드 실무 처리 방식
  • OAuth/IDPW 통합 user_id 체계
  • UX 분기 처리 설계
  • TypeScript/NextAuth 타입 오류 해결 기록

1️⃣ get_user()가 여러 키를 받는 이유

✅ 핵심 코드

def get_user(user_id: str) -> Optional[dict]:
    try:
        uid = int(user_id)
        ... WHERE id = %s
    except ValueError:
        pass

    ... WHERE user_id = %s
    ... WHERE email = %s
    ... WHERE provider_user_id = %s

✅ 문법 설명

try / except

문자열이 숫자로 변환 가능한지 검사합니다.
변환 실패 시 예외를 처리하고 다음 로직으로 넘어갑니다.

Optional[dict]

반환값이 dict 또는 None일 수 있음을 명시하는 타입입니다.
→ 타입 안정성 확보


✅ 설계 이유

OAuth + ID/PW 로그인이 섞이면 user_id 형태가 통일되지 않습니다.

  • 일반 로그인 → DB id
  • OAuth → provider_user_id
  • 일부 상황 → email

따라서 하나의 함수에서 모든 케이스를 처리하는 구조가 가장 효율적입니다.


❌ 다른 방법

로그인 방식마다 API 분리

→ 코드 중복
→ 유지보수 비용 증가
→ 확장성 낮음


✅ 현재 방식 장점

✔ 단일 진입점
✔ 재사용성 증가
✔ 유지보수 비용 감소
✔ 실서비스 표준 구조


2️⃣ PATCH 방식 업데이트를 사용한 이유

✅ 핵심 코드

payload = {
  "name": body.name,
  "phone": body.phone,
}

for key, value in payload.items():
  if value is not None:
    fields.append(f"{key} = %s")
    values.append(value)

✅ 문법 설명

  • .items() → 딕셔너리 key/value 반복
  • if value is not None → 변경된 값만 업데이트

✅ 왜 PATCH인가요?

PUT은 전체 필드를 전송해야 합니다.
→ 불필요한 데이터 + 덮어쓰기 위험

PATCH는 변경된 값만 전송합니다.
네트워크 효율 + 안정성 상승


✅ 장점

✔ 부분 업데이트 가능
✔ 서버 부하 감소
✔ 실서비스 표준 방식
✔ 유지보수 용이


3️⃣ 이미지 업로드 처리 전략 (핵심 ⭐)

✅ 핵심 코드

ALLOWED_EXTS = {".jpg", ".jpeg", ".png", ".webp"}
MAX_IMAGE_BYTES = 5 * 1024 * 1024

filename = f"user_{user['id']}_{uuid4().hex}{ext}"

✅ 문법 설명

  • uuid4().hex → 고유 랜덤 문자열 생성
  • 확장자 제한 → 보안 강화
  • 파일 크기 제한 → 서버 보호

❌ 흔한 방식

1) user_id.png

→ 파일 충돌 위험

2) Base64 DB 저장

→ DB 용량 폭발 + 성능 저하


✅ 현재 방식 (실무 표준)

파일 저장 + DB 경로 저장

→ 빠름
→ 관리 쉬움
→ 비용 절감
→ 확장성 우수


4️⃣ 이미지 삭제까지 처리하는 이유

✅ 코드

profile_image = user.get("profile_image")
if profile_image:
    filepath = Path(... / profile_image.lstrip("/"))
    if filepath.exists():
        filepath.unlink()

✅ 이유

DB 값만 삭제하면 실제 파일은 서버에 계속 남습니다.

→ 스토리지 낭비
→ 비용 증가
→ 관리 어려움


✅ 해결

DB 삭제 + 파일 삭제

→ 완전한 clean-up
→ 실무 필수 처리


5️⃣ 이메일 수정 막은 이유

✅ 코드

<input value={form.email} readOnly disabled />

✅ 이유

이메일은 로그인 식별자입니다.
특히 OAuth에서는 이메일이 ID 역할을 합니다.

수정 허용 시:

  • 세션 깨짐
  • 인증 불일치
  • 계정 충돌 위험

✅ 장점

✔ 계정 안정성 확보
✔ 실서비스 UX 표준
✔ 보안 강화


6️⃣ 사이드바 비밀번호 메뉴 분기

✅ 코드

const isCredentials = user?.provider === "credentials";

✅ 이유

OAuth 사용자는 비밀번호가 없습니다.
따라서 “비밀번호 변경” 메뉴는 UX 오류입니다.


✅ 장점

✔ 사용자 혼란 방지
✔ 논리적 UI
✔ 실무형 UX 설계


7️⃣ 캘린더 주말 색상 분기

✅ 코드

if (date.getDay() === 0) return "cal-sun";
if (date.getDay() === 6) return "cal-sat";

✅ 이유

React Calendar 기본 스타일이 다크모드에서 가독성이 떨어졌습니다.


✅ 해결

직접 클래스 지정 → 강제 색상 적용

✔ 가독성 향상
✔ UI 완성도 상승


✅ 오늘 발생했던 오류 & 해결 기록


(1) MyPageSidebar 타입 오류

🔴 증상

조건 스프레드 구문에서 빨간줄 발생

...(isCredentials ? [...] : [])

🔴 원인

TypeScript가 조건 스프레드 타입 추론을
IDE 환경에서 불안정하게 처리하는 경우 존재


✅ 해결

스프레드 대신 명시적 삽입 방식

수정 후

const menuItems = [
  { id: "profile", label: "프로필 설정" },
  { id: "address", label: "주소 관리" },
];

if (isCredentials) {
  menuItems.splice(1, 0, { id: "password", label: "비밀번호 변경" });
}

✅ 장점

✔ 타입 안정성 확보
✔ IDE 오류 제거
✔ 실무에서 많이 쓰는 안전한 패턴


(2) NextAuth provider 타입 오류

🔴 증상

session.user.provider = token.provider

빨간줄 발생


🔴 원인

타입 정의에 google/credentials만 존재
naver/kakao 누락


✅ 해결

타입 확장

provider?: "google" | "naver" | "kakao" | "credentials";

✅ 장점

✔ 타입과 실제 로직 일치
✔ 런타임 오류 예방
✔ 안정성 향상


✅ Part 2 핵심 요약

이번 작업은 단순 기능 구현이 아닙니다.

👉 실서비스 구조를 만드는 과정이었습니다.

✔ OAuth/IDPW 통합 user_id 체계
✔ PATCH 기반 CRUD
✔ 파일 저장 방식 이미지 처리
✔ Router/Service 레이어 분리
✔ UX 분기 처리
✔ 타입 안정성 확보
✔ 오류 해결 기록 정리


🎯 면접 30초 요약

“OAuth와 일반 로그인을 내부 user_id 체계로 통합하고, Service 레이어 분리와 PATCH 기반 CRUD, 파일 저장 방식 이미지 업로드까지 실서비스 구조로 설계했습니다.”


🎯 면접 1분 설명

“Google/Naver/Kakao OAuth와 ID/PW 로그인을 하나의 user_id 체계로 통합했습니다.
JWT 콜백에서 DB 내부 id를 토큰에 저장해 로그인 방식이 달라도 동일 사용자로 인식하도록 했습니다.
마이페이지는 PATCH 기반 부분 업데이트 구조로 설계했고 Router/Service를 분리해 유지보수성을 높였습니다.
이미지는 Base64 대신 파일 저장 + 경로 저장 방식으로 처리해 실서비스 수준의 성능과 안정성을 확보했습니다.”


✅ README / 아키텍처 정리

인증 흐름

OAuth/IDPW 로그인
→ JWT 콜백
→ DB id 통합
→ session.user.id 고정
→ Zustand 전역 상태 동기화


마이페이지 API

  • GET /users/me
  • PATCH /users/me
  • POST /users/me/image
  • DELETE /users/me/image

레이어 구조

Router (HTTP)
   ↓
Service (Business Logic)
   ↓
DB / File System

이미지 저장 구조

/backend/uploads/profile/user_{id}_{uuid}.png

DB에는 경로만 저장합니다.