포그라운드 Push 표시 · 퀘스트 알림 다국어 제목 · 약관 미동의 계정의 행성 가입·성운 생성 차단

This commit is contained in:
Sn-Kinos
2026-10-06 01:18:50 +09:00
parent dce2f64362
commit cf3dd06774
6 changed files with 66 additions and 5 deletions
@@ -147,6 +147,14 @@ function primaryPatch(user: Data, fandomId: string, cooldownDays: number, now: n
* - `users/{uid}/memberships/{id}` — 「가입 또는 생성한 행성/성운」 목록(명세 §2.58)의 원천.
* - `memberCount` 는 같은 트랜잭션에서 올린다 — 전환 조건(B-10)이 이 값을 읽는다.
*/
/**
* 가입 약관(`termsAgreedAt`, [fnSignupConsent]) 없이 행성 · 성운 멤버가 되지 않게 막는다.
* 앱은 약관 화면부터 보내지만(app_router 게이트) 서버도 같은 기준을 지킨다 — 10/6 실기기 판정.
*/
function requireTerms(user: Data): void {
if (!user?.termsAgreedAt) fail(ERR.permissionDenied, '이용 약관에 동의한 뒤 가입할 수 있습니다.');
}
function writeJoin(tx: Transaction, uid: string, fandomId: string, fandom: Data): void {
const db = getFirestore();
const memberNo = Number(fandom?.memberSeq ?? fandom?.memberCount ?? 0) + 1;
@@ -199,6 +207,7 @@ export const fnNebulaCreate = onCall(async (req) => {
const [todaySnap, nameSnap, userSnap] = await Promise.all([
tx.get(todayRef), tx.get(nameRef), tx.get(userRef),
]);
requireTerms(userSnap.data());
if (todaySnap.exists) fail(ERR.nebulaDailyLimit, '이미 오늘 성운을 생성하셨습니다.');
if (nameSnap.exists) fail(ERR.fandomNameTaken, '이미 사용중인 이름입니다.');
const { patch } = primaryPatch(userSnap.data(), fandom.id, policy.primaryCooldownDays, now);
@@ -243,6 +252,7 @@ export const fnFandomJoin = onCall(async (req) => {
]);
if (!fandomSnap.exists) fail(ERR.permissionDenied, '행성을 찾을 수 없습니다.');
if (memberSnap.exists) return { fandomId, joined: false };
requireTerms(userSnap.data());
writeJoin(tx, uid, fandomId, fandomSnap.data());
// 원장 S20(확인 전 유지 기준) — 창립자가 혼자 떠나 탄생 권한자가 빈 성운은 다음 가입자가 이어받는다.
if (fandomSnap.get('stage') === 0 && !fandomSnap.get('founderUid')) {