Remove implicit first-visit heart grant from progress summary
All checks were successful
CI/CD Pipeline / Unit Tests (push) Successful in 18s
CI/CD Pipeline / Build & Deploy Test (push) Has been skipped
CI/CD Pipeline / Build & Deploy Production (push) Successful in 1m15s

This commit is contained in:
Wang Zhuoxuan 2026-06-09 18:18:17 +08:00
parent 3ab009e338
commit 6cb282147e
2 changed files with 1 additions and 6 deletions

View File

@ -306,7 +306,6 @@ describe('challenge-service', () => {
[freeUserRow], // deductDailyAttempt → getResourceUser [freeUserRow], // deductDailyAttempt → getResourceUser
[knowledgeCardRow], // getKnowledgeCard [knowledgeCardRow], // getKnowledgeCard
[{ groupId: 'week-2026-05-11-group-1' }], // addXp(first card): reuse weekly group [{ groupId: 'week-2026-05-11-group-1' }], // addXp(first card): reuse weekly group
[userAfterAttempt], // grantDailyFirstVisitHeart → getResourceUser
[userAfterAttempt], // getResourceUser (getProgressSummary) [userAfterAttempt], // getResourceUser (getProgressSummary)
[{ tier: 'free', heartsRemaining: 5, heartsLastRestore: null }], // getHearts [{ tier: 'free', heartsRemaining: 5, heartsLastRestore: null }], // getHearts
[{ checkInDays: 2, lastCheckInDate: new Date().toISOString() }], // calculateStreak [{ checkInDays: 2, lastCheckInDate: new Date().toISOString() }], // calculateStreak
@ -342,7 +341,6 @@ describe('challenge-service', () => {
[{ createdAt: new Date(Date.now() - 10 * 86_400_000).toISOString() }], // isNewUserProtected [{ createdAt: new Date(Date.now() - 10 * 86_400_000).toISOString() }], // isNewUserProtected
[freeUserRow], // deductDailyAttempt → getResourceUser [freeUserRow], // deductDailyAttempt → getResourceUser
[knowledgeCardRow], // getKnowledgeCard [knowledgeCardRow], // getKnowledgeCard
[userAfter], // grantDailyFirstVisitHeart → getResourceUser
[userAfter], // getResourceUser (getProgressSummary) [userAfter], // getResourceUser (getProgressSummary)
[{ tier: 'free', heartsRemaining: 2, heartsLastRestore: null }], // getHearts [{ tier: 'free', heartsRemaining: 2, heartsLastRestore: null }], // getHearts
[{ checkInDays: 0, lastCheckInDate: null }], // calculateStreak [{ checkInDays: 0, lastCheckInDate: null }], // calculateStreak
@ -357,6 +355,7 @@ describe('challenge-service', () => {
expect(result.answerState).toBe('wrong'); expect(result.answerState).toBe('wrong');
expect(result.xpDelta).toBe(0); expect(result.xpDelta).toBe(0);
expect(result.progress.hearts).toBe(2);
expect(db.update).toHaveBeenCalled(); expect(db.update).toHaveBeenCalled();
}); });
@ -386,7 +385,6 @@ describe('challenge-service', () => {
[{ tier: 'pro', heartsRemaining: 99 }], // deductHeart: pro user [{ tier: 'pro', heartsRemaining: 99 }], // deductHeart: pro user
[proUserRow], // deductDailyAttempt → getResourceUser [proUserRow], // deductDailyAttempt → getResourceUser
[knowledgeCardRow], // getKnowledgeCard [knowledgeCardRow], // getKnowledgeCard
[proUserAfter], // grantDailyFirstVisitHeart → getResourceUser
[proUserAfter], // getResourceUser (getProgressSummary) [proUserAfter], // getResourceUser (getProgressSummary)
[{ tier: 'pro', heartsRemaining: 99, heartsLastRestore: null }], // getHearts [{ tier: 'pro', heartsRemaining: 99, heartsLastRestore: null }], // getHearts
[{ checkInDays: 0, lastCheckInDate: null }], // calculateStreak [{ checkInDays: 0, lastCheckInDate: null }], // calculateStreak
@ -415,7 +413,6 @@ describe('challenge-service', () => {
[], // addXp(correct): no existing leaderboard group [], // addXp(correct): no existing leaderboard group
[freeUserRow], // deductDailyAttempt → getResourceUser [freeUserRow], // deductDailyAttempt → getResourceUser
// settleCompletedChallenge → getProgressSummary (before) // settleCompletedChallenge → getProgressSummary (before)
[userAfterAttempt], // grantDailyFirstVisitHeart → getResourceUser
[userAfterAttempt], // getResourceUser [userAfterAttempt], // getResourceUser
[{ tier: 'free', heartsRemaining: 5, heartsLastRestore: null }], // getHearts [{ tier: 'free', heartsRemaining: 5, heartsLastRestore: null }], // getHearts
[{ checkInDays: 2, lastCheckInDate: new Date().toISOString() }], // calculateStreak [{ checkInDays: 2, lastCheckInDate: new Date().toISOString() }], // calculateStreak

View File

@ -223,8 +223,6 @@ export async function protectStreak(userId: string, _source: RewardSource): Prom
} }
export async function getProgressSummary(userId: string): Promise<ProgressSummaryDto> { export async function getProgressSummary(userId: string): Promise<ProgressSummaryDto> {
await grantDailyFirstVisitHeart(userId);
const [user, hearts, streak, subscription, attempts] = await Promise.all([ const [user, hearts, streak, subscription, attempts] = await Promise.all([
getResourceUser(userId), getResourceUser(userId),
getHearts(userId), getHearts(userId),