users 스키마
사용자 문서의 전체 스키마. 회원가입, 로그인, 소셜 연동, 본인인증, 내 정보 조회 등 공통 파트의 핵심 컬렉션입니다.
저장 위치
uid는 Firebase Authentication의 UID를 그대로 사용합니다.
상태 흐름
(미등록) → authentication=False → authentication=True (이니시스 본인인증 완료)
↓
withdrawn=True (회원 탈퇴)
- 회원가입 완료 시
authentication=True로 기본 저장됩니다(이니시스 본인인증 별도).
- 이니시스 본인인증(
inicis_success)이 완료되어야 CI_hash가 채워져 완전한 본인인증 상태가 됩니다.
- 탈퇴 시 개인정보 필드는
None으로 마스킹되고 withdrawn=True, withdrawn_at이 기록됩니다. 문서는 삭제하지 않고 유지됩니다.
문서 필드
프로필 / 개인정보 (암호화 3종 패턴)
| 필드 |
타입 |
설명 |
name_enc |
string |
AES 암호화된 이름 |
name_hash |
string |
이름 SHA256 해시 (SALT 기반, 비교/검색용) |
phone_enc |
string |
AES 암호화된 전화번호 (010-XXXX-XXXX) |
phone_hash |
string |
전화번호 SHA256 해시 |
email_enc |
string |
AES 암호화된 이메일 |
email_hash |
string |
이메일 SHA256 해시 |
sub_address_enc |
string |
AES 암호화된 상세주소 |
프로필 / 평문 필드
| 필드 |
타입 |
설명 |
sex |
string |
"male" | "female" |
birth |
timestamp |
생년월일 (datetime 객체로 저장) |
telecom |
string |
통신사 (KT | SKT | LGT | KT(알뜰) | SKT(알뜰) | LGT(알뜰)) |
postalcode |
string? |
우편번호 (v1 registration에서는 없음, v2 이상) |
main_address |
string |
메인 주소 (도로명 주소 등) |
인증/상태
| 필드 |
타입 |
설명 |
authentication |
bool |
기본 본인인증 플래그 (가입 시 True, my_info에서는 CI_hash 존재 여부와 AND) |
CI_hash |
string? |
이니시스 본인인증 성공 시 저장되는 CI 값의 SHA256 해시 |
withdrawn |
bool? |
탈퇴 여부 (탈퇴 시 True) |
withdrawn_at |
timestamp? |
탈퇴 시각 |
created_at |
timestamp |
가입 시각 (SERVER_TIMESTAMP) |
updated_at |
timestamp? |
주소 변경 등 업데이트 시각 |
소셜 로그인 연동
| 필드 |
타입 |
설명 |
login_providers |
string[] |
연동된 로그인 수단 목록 (email, google, apple, kakao) |
google_sub |
string? |
Google 계정의 sub (고유 ID) |
apple_sub |
string? |
Apple 계정의 sub (고유 ID) |
kakao_id |
string? |
카카오 계정의 고유 ID (문자열) |
login_providers 배열과 각 {provider}_sub/{provider}_id 필드는 함께 관리됩니다. 해제 시 해당 필드는 firestore.DELETE_FIELD로 제거되고 배열에서도 빠집니다.
로그인 시도 (중첩 오브젝트)
| 필드 |
타입 |
설명 |
login_attempts |
object? |
로그인 실패 횟수/잠금 상태 — 아래 LoginAttempts 참조 |
본인인증 임시 상태 (이니시스 거래 진행 중)
| 필드 |
타입 |
설명 |
mTxId |
string? |
이니시스 거래번호 (본인인증/이메일찾기/전화번호변경 진행 중에만) |
pending_phone |
string? |
전화번호 변경 진행 중인 새 번호 (change_phone_num에서 임시 저장) |
이메일 변경 임시 상태 (5분 만료)
| 필드 |
타입 |
설명 |
email_change_code |
string? |
6자리 이메일 변경 인증 코드 |
email_change_target |
string? |
변경 대상 새 이메일 (평문) |
email_change_expires |
timestamp? |
인증 코드 만료시각 (KST 기준, 발급 후 5분) |
푸시 알림
| 필드 |
타입 |
설명 |
fcm_token |
string? |
Firebase Cloud Messaging 푸시 토큰. update_fcm_token으로 갱신 |
LoginAttempts
로그인 실패 횟수와 계정 잠금 상태를 관리하는 중첩 오브젝트입니다. login/login_guard.py에서 관리합니다.
{
"failed_count": 3,
"locked": false,
"locked_at": null,
"last_attempt_at": "timestamp"
}
| 필드 |
타입 |
설명 |
failed_count |
int |
누적 로그인 실패 횟수 (성공 시 0으로 초기화) |
locked |
bool |
계정 잠금 여부. MAX_FAILED_ATTEMPTS=15 도달 시 자동 True |
locked_at |
timestamp? |
잠금 시각. 잠금 해제 시 DELETE_FIELD |
last_attempt_at |
timestamp |
마지막 시도 시각 |
잠금 해제는 비밀번호 재설정 메일 발송(send_password_reset_email) 또는 로그인 성공 시 자동으로 이루어집니다.
서브컬렉션
users/{uid}/ 하위 서브컬렉션 목록.
탈퇴(withdraw) 시 equipments, certificates, resumes, requests, inquiries 서브컬렉션이 모두 삭제됩니다. membership이 있으면 탈퇴 자체가 거부됩니다.
예시 문서
{
"name_enc": "AES(홍길동)",
"name_hash": "sha256(홍길동 + SALT)",
"phone_enc": "AES(010-1234-5678)",
"phone_hash": "sha256(010-1234-5678 + SALT)",
"email_enc": "AES(user@example.com)",
"email_hash": "sha256(user@example.com + SALT)",
"sub_address_enc": "AES(101동 202호)",
"sex": "male",
"birth": "1998-02-02T00:00:00Z",
"telecom": "SKT",
"postalcode": "12345",
"main_address": "서울시 강남구 테헤란로 1",
"authentication": true,
"CI_hash": "sha256(userCi + SALT)",
"login_providers": ["email", "google"],
"google_sub": "1234567890",
"login_attempts": {
"failed_count": 0,
"locked": false,
"last_attempt_at": "2026-04-20T10:00:00Z"
},
"fcm_token": "fcm_xxx",
"created_at": "2026-04-01T00:00:00Z"
}