가입 트리거 서울 리전 · 탈퇴 시 업로드 파일 삭제 · 위치 인증 위경도 미저장
This commit is contained in:
@@ -2,6 +2,8 @@ import * as functionsV1 from 'firebase-functions/v1';
|
||||
import { HttpsError, onCall } from 'firebase-functions/v2/https';
|
||||
import { getFirestore, FieldValue, Timestamp, type Transaction } from 'firebase-admin/firestore';
|
||||
import { getAuth } from 'firebase-admin/auth';
|
||||
import { getStorage } from 'firebase-admin/storage';
|
||||
import { logger } from 'firebase-functions/v2';
|
||||
|
||||
import { callerUid, str } from '../core/callable.js';
|
||||
import { dayKey } from '../core/time.js';
|
||||
@@ -15,9 +17,10 @@ import { ERR, fail } from '../core/errors.js';
|
||||
* 고정한 이유는 경합 때문이다 — 클라이언트가 먼저 만들면 서버 산출 필드가 빈
|
||||
* 사용자 문서가 남는다.
|
||||
*
|
||||
* v2 에는 사용자 생성 배경 트리거가 없어 v1 Auth 트리거를 쓴다.
|
||||
* v2 에는 사용자 생성 배경 트리거가 없어 v1 Auth 트리거를 쓴다. v1 은 `setGlobalOptions`(v2 전용)를
|
||||
* 따르지 않으므로 리전을 여기서 직접 서울로 고정한다.
|
||||
*/
|
||||
export const fnAuthOnCreate = functionsV1.auth.user().onCreate(async (user) => {
|
||||
export const fnAuthOnCreate = functionsV1.region('asia-northeast3').auth.user().onCreate(async (user) => {
|
||||
const db = getFirestore();
|
||||
const userRef = db.doc(`users/${user.uid}`);
|
||||
const walletRef = db.doc(`users/${user.uid}/wallet/main`);
|
||||
@@ -513,6 +516,10 @@ export const fnSignupConsent = onCall(async (req) => {
|
||||
* 않고 데이터 보존」 · 별첨 B 「원장 보존 5년」). 사용자 문서의 개인식별정보(닉네임 · 표시 이름 · 이메일 ·
|
||||
* 사진 · 푸시 토큰)는 지우고 `status: 'withdrawn'` · `withdrawnAt` 을 남긴다(별첨 B 「탈퇴 후 개인식별정보는
|
||||
* 파기/비식별」, Admin 사용자 일람의 탈퇴일 · 상태 `557:40942`).
|
||||
* - 본인이 올린 Storage 파일 중 **본인 전용 경로**를 지운다: `users/{uid}/profile/`(프로필 사진),
|
||||
* `questProofs/{uid}/`(Quest 인증 사진). 삭제 실패는 로그만 남기고 탈퇴를 막지 않는다.
|
||||
* **`users/{uid}/lounge/`(라운지 글 사진)는 지우지 않는다** — 글 처리 범위가 해석 확인 Q-E4 회신 대기라
|
||||
* 글과 함께 「회신 후」에 정한다(글 문서가 이 경로를 가리키므로 먼저 지우면 깨진 사진이 남는다).
|
||||
* - Auth 계정을 지운다. 같은 소셜 계정으로 다시 가입하면 새 계정이다.
|
||||
*/
|
||||
export const fnAccountWithdraw = onCall(async (req) => {
|
||||
@@ -539,6 +546,13 @@ export const fnAccountWithdraw = onCall(async (req) => {
|
||||
// 탈퇴한 사람의 추천 코드로 새 귀속이 생기지 않게 닫는다.
|
||||
if (typeof code === 'string' && code) batch.set(db.doc(`inviteCodes/${code}`), { active: false }, { merge: true });
|
||||
await batch.commit();
|
||||
for (const prefix of [`users/${uid}/profile/`, `questProofs/${uid}/`]) {
|
||||
try {
|
||||
await getStorage().bucket().deleteFiles({ prefix });
|
||||
} catch (e) {
|
||||
logger.error('withdraw: storage cleanup failed', { uid, prefix, error: String(e) });
|
||||
}
|
||||
}
|
||||
await auth.deleteUser(uid);
|
||||
return { withdrawn: true };
|
||||
});
|
||||
|
||||
@@ -273,9 +273,9 @@ export const fnQuestVerifyPlace = onCall(async (req) => {
|
||||
evidence: {
|
||||
place: {
|
||||
placeId,
|
||||
// 정확도와 모의 위치 여부를 함께 남긴다 — 설계서 §2.1 「위치 사진 경로·GPS
|
||||
// 좌표·정확도」와 §8 「mock location 차단」의 판정 입력이다.
|
||||
gps: { lat, lng, ...(typeof accuracyM === 'number' ? { accuracyM } : {}), mocked },
|
||||
// 사용자 위경도는 판정에만 쓰고 저장하지 않는다(10/6 발주사 개인정보 기준) —
|
||||
// 거리 · 정확도 · 모의 위치 여부만 남긴다(§8 「mock location 차단」 판정 입력).
|
||||
location: { distanceM: Math.round(gap), ...(typeof accuracyM === 'number' ? { accuracyM } : {}), mocked },
|
||||
// C-03 「GPS 와 QR 판정이 모두 기록」 — 추가 수단은 값과 판정을 함께 남긴다.
|
||||
...(qr ? { qr: { value: qr, ok: qrOk } } : {}),
|
||||
...(photo ? { photo: { path: photo, ok: photoOk } } : {}),
|
||||
|
||||
Reference in New Issue
Block a user