mmday-firebase/src/repositories/userRepository.ts
윤정민 c7e4ed8c22 Standardize game status values and make favorite team optional.
- `GameStatus` 타입을 `scheduled`, `live`, `completed`, `cancelled`로 변경하여 상태 관리의 일관성을 높였습니다.
- 사용자 프로필의 `favoriteTeamCode`를 선택 사항으로 변경하고, null 또는 undefined 입력에 대한 처리를 추가했습니다.
- KBO 데이터 병합 과정에 상세 로그를 도입하여 실시간 데이터 매칭 및 외부 API 호출 실패 상황에 대한 가시성을 확보했습니다.
- 상태 값 변경에 따라 영향받는 서비스 로직과 테스트 코드를 일괄 업데이트했습니다.
2026-04-14 23:08:45 +09:00

80 lines
2.3 KiB
TypeScript

import { FieldValue } from "firebase-admin/firestore";
import { firestore } from "../firebase";
import type {
KnowledgeLevel,
Provider,
TeamCode,
User,
} from "../types/panit";
const COLLECTION = "users";
export interface RegisterInput {
displayName: string;
email: string;
photoUrl?: string;
provider: Provider;
favoriteTeamCode?: TeamCode;
knowledgeLevel: KnowledgeLevel;
}
/**
* 특정 유저 문서를 조회한다.
*
* @param uid - Firebase Auth UID
* @returns 유저 문서. 존재하지 않으면 `null`.
*/
export async function getUser(uid: string): Promise<User | null> {
const snap = await firestore.collection(COLLECTION).doc(uid).get();
return snap.exists ? (snap.data() as User) : null;
}
/**
* displayName으로 유저의 uid를 조회한다. 없으면 `null`.
* 닉네임 유니크성 검증용 fallback.
*/
export async function findUidByDisplayName(
displayName: string
): Promise<string | null> {
const snap = await firestore
.collection(COLLECTION)
.where("displayName", "==", displayName)
.limit(1)
.get();
return snap.empty ? null : snap.docs[0].id;
}
/**
* 신규 유저 문서를 생성한다. `createdAt`은 서버 타임스탬프로 기록되며,
* 같은 UID가 있으면 전체 덮어쓴다(`merge: false`).
*/
export async function createUser(uid: string, input: RegisterInput): Promise<void> {
const doc: Record<string, unknown> = {
displayName: input.displayName,
email: input.email,
provider: input.provider,
knowledgeLevel: input.knowledgeLevel,
createdAt: FieldValue.serverTimestamp(),
};
if (input.photoUrl) doc.photoUrl = input.photoUrl;
if (input.favoriteTeamCode) doc.favoriteTeamCode = input.favoriteTeamCode;
await firestore.collection(COLLECTION).doc(uid).set(doc, { merge: false });
}
/**
* 유저 문서의 일부 필드를 병합 업데이트한다.
*/
export async function updateUser(
uid: string,
patch: Partial<Pick<User, "displayName" | "photoUrl" | "favoriteTeamCode" | "knowledgeLevel">>
): Promise<void> {
await firestore.collection(COLLECTION).doc(uid).set(patch, { merge: true });
}
/**
* 유저 문서 및 하위 컬렉션(voteHistory 등)을 모두 삭제한다.
*/
export async function deleteUser(uid: string): Promise<void> {
await firestore.recursiveDelete(firestore.collection(COLLECTION).doc(uid));
}