공식 로고 앱 아이콘 적용 · 확정 정책에 맞춰 등급·POP 소멸 필드를 규칙·인덱스에서 제외
This commit is contained in:
@@ -43,7 +43,7 @@ afterAll(async () => {
|
||||
await testEnvironment.cleanup();
|
||||
});
|
||||
|
||||
describe('원칙 1 — POP·FPI·등급·원장은 클라이언트 쓰기 불가', () => {
|
||||
describe('원칙 1 — POP·FPI·원장은 클라이언트 쓰기 불가', () => {
|
||||
test('본인 지갑 잔액 직접 증액을 거부한다', async () => {
|
||||
await seedDocuments(testEnvironment, {
|
||||
'users/alice/wallet/main': { balance: 100 },
|
||||
@@ -61,14 +61,14 @@ describe('원칙 1 — POP·FPI·등급·원장은 클라이언트 쓰기 불가
|
||||
);
|
||||
});
|
||||
|
||||
test('POP Lot 만료일 연장을 거부한다', async () => {
|
||||
test('POP Lot 잔량 조작을 거부한다', async () => {
|
||||
await seedDocuments(testEnvironment, {
|
||||
'users/alice/popLots/lot-1': { remaining: 100, expiresAt: '2026-08-09T00:00:00Z' },
|
||||
'users/alice/popLots/lot-1': { remaining: 100 },
|
||||
});
|
||||
|
||||
await assertFails(
|
||||
updateDoc(doc(dbFor('alice'), 'users/alice/popLots/lot-1'), {
|
||||
expiresAt: '2099-12-31T00:00:00Z',
|
||||
remaining: 999_999,
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -82,12 +82,14 @@ describe('원칙 1 — POP·FPI·등급·원장은 클라이언트 쓰기 불가
|
||||
);
|
||||
});
|
||||
|
||||
test('사용자 등급 직접 승격을 거부한다', async () => {
|
||||
test('누적 기여 통계 직접 조작을 거부한다', async () => {
|
||||
await seedDocuments(testEnvironment, {
|
||||
'users/alice': userDocument('alice'),
|
||||
});
|
||||
|
||||
await assertFails(updateDoc(doc(dbFor('alice'), 'users/alice'), { grade: 'DIAMOND' }));
|
||||
await assertFails(
|
||||
updateDoc(doc(dbFor('alice'), 'users/alice'), { totalContributedPop: 999_999 }),
|
||||
);
|
||||
});
|
||||
|
||||
test('다른 사용자의 지갑 쓰기를 거부한다', async () => {
|
||||
@@ -125,11 +127,11 @@ describe('원칙 2 — 개인 리소스와 쓰기 필드 제한', () => {
|
||||
await assertFails(updateDoc(doc(dbFor('alice'), 'users/bob'), { displayName: 'Forged' }));
|
||||
});
|
||||
|
||||
test('허용 필드와 등급을 섞은 본인 업데이트를 전부 거부한다', async () => {
|
||||
test('허용 필드와 서버 통계를 섞은 본인 업데이트를 전부 거부한다', async () => {
|
||||
await assertFails(
|
||||
updateDoc(doc(dbFor('alice'), 'users/alice'), {
|
||||
displayName: 'New Alice',
|
||||
grade: 'DIAMOND',
|
||||
totalContributedPop: 999_999,
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -251,15 +253,13 @@ describe('F-02 — 캠페인 집계 필드 위조 회귀', () => {
|
||||
summary: 'Summary',
|
||||
body: 'Body',
|
||||
coverImageUrl: 'https://example.test/cover.png',
|
||||
campaignType: 'support',
|
||||
campaignType: 'other',
|
||||
targetPop: 1000,
|
||||
endsAt: '2026-09-01T00:00:00Z',
|
||||
status: 'draft',
|
||||
raisedPop: 0,
|
||||
achievedRate: 0,
|
||||
donorCount: 0,
|
||||
votedPop: 0,
|
||||
isAiDraft: false,
|
||||
refundState: 'none',
|
||||
createdAt: '2026-08-08T00:00:00Z',
|
||||
updatedAt: '2026-08-08T00:00:00Z',
|
||||
@@ -275,14 +275,12 @@ describe('F-02 — 캠페인 집계 필드 위조 회귀', () => {
|
||||
await assertSucceeds(setDoc(doc(dbFor('alice'), 'campaigns/valid'), validCampaign));
|
||||
});
|
||||
|
||||
test('집계·투표·AI 초안 필드 위조를 거부한다', async () => {
|
||||
test('집계 필드 위조를 거부한다', async () => {
|
||||
await assertFails(
|
||||
setDoc(doc(dbFor('alice'), 'campaigns/forged'), {
|
||||
...validCampaign,
|
||||
achievedRate: 1,
|
||||
donorCount: 99_999,
|
||||
votedPop: 999_999,
|
||||
isAiDraft: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -389,7 +387,10 @@ describe('F-14 — posts 허용 필드 회귀', () => {
|
||||
describe('F-06 — users 클라이언트 생성 경로 회귀', () => {
|
||||
test('일반 사용자의 users 문서 생성을 거부한다', async () => {
|
||||
await assertFails(
|
||||
setDoc(doc(dbFor('alice'), 'users/alice'), userDocument('alice', { grade: 'DIAMOND' })),
|
||||
setDoc(
|
||||
doc(dbFor('alice'), 'users/alice'),
|
||||
userDocument('alice', { totalContributedPop: 999_999 }),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user