📘 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에는 경로만 저장합니다.
'챗봇 공부 노트' 카테고리의 다른 글
| [19편] part 2 배포 프론트/프록시 구조 변경 상세 정리 (0) | 2026.02.13 |
|---|---|
| [19편] part 1 배포 전체 흐름 + 장애 대응 + 서버 유지 (0) | 2026.02.13 |
| [18편] Part1 마이페이지 CRUD + OAuth 통합 + 이미지 업로드 (0) | 2026.02.06 |
| [17편] Part 3 MySQL 세션/메시지 + 오류정리 및 해결 (0) | 2026.02.05 |
| [17편] Part 2 GPT 컨텍스트 엔지니어링 (0) | 2026.02.05 |