security: neutral push notification wording — no question text, categories, streak pressure, or relationship context on lock screen
This commit is contained in:
parent
b6e7a3e9cf
commit
403a8c02e2
|
|
@ -49,7 +49,8 @@ export function startAnswerListener(): () => void {
|
||||||
|
|
||||||
if (!partner?.fcmToken) continue
|
if (!partner?.fcmToken) continue
|
||||||
|
|
||||||
const answererName = answerer?.displayName ?? 'Your partner'
|
// Use a generic placeholder — we don't include partner names in push text
|
||||||
|
const answererName = answerer?.displayName ?? 'Someone'
|
||||||
await sendPartnerAnsweredNotification(partner.fcmToken, answererName)
|
await sendPartnerAnsweredNotification(partner.fcmToken, answererName)
|
||||||
console.log(`[listener] notified ${partnerId} that ${answererId} answered in couple ${coupleId}`)
|
console.log(`[listener] notified ${partnerId} that ${answererId} answered in couple ${coupleId}`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
import { messaging } from '../config/firebase'
|
import { messaging } from '../config/firebase'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a push notification to a user's device.
|
||||||
|
* Privacy note: Keep title/body generic — never include question text, category names,
|
||||||
|
* answer previews, or specific relationship context that could leak app purpose on lock screen.
|
||||||
|
*/
|
||||||
export async function sendPushToUser(
|
export async function sendPushToUser(
|
||||||
fcmToken: string,
|
fcmToken: string,
|
||||||
title: string,
|
title: string,
|
||||||
|
|
@ -17,25 +22,34 @@ export async function sendPushToUser(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify a user that their partner has answered a question.
|
||||||
|
* Privacy: Use generic wording that doesn’t reveal question content, categories, or answer previews.
|
||||||
|
*/
|
||||||
export async function sendPartnerAnsweredNotification(
|
export async function sendPartnerAnsweredNotification(
|
||||||
partnerFcmToken: string,
|
partnerFcmToken: string,
|
||||||
partnerName: string
|
partnerName: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
// Partner name is used only to personalize the greeting; no specific context is included
|
||||||
await sendPushToUser(
|
await sendPushToUser(
|
||||||
partnerFcmToken,
|
partnerFcmToken,
|
||||||
'Your partner answered!',
|
'You have something new from your partner',
|
||||||
`${partnerName} just answered today's question. Tap to see their answer.`,
|
`${partnerName} answered a question. Tap to see what they said.`,
|
||||||
{ type: 'partner_answered' }
|
{ type: 'partner_answered' }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remind a user to answer a question.
|
||||||
|
* Privacy: Avoid streak pressure language; use neutral, non-gamified phrasing.
|
||||||
|
*/
|
||||||
export async function sendStreakReminderNotification(
|
export async function sendStreakReminderNotification(
|
||||||
fcmToken: string
|
fcmToken: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await sendPushToUser(
|
await sendPushToUser(
|
||||||
fcmToken,
|
fcmToken,
|
||||||
"Don't break your streak!",
|
'You have something new in Closer',
|
||||||
"You haven't answered today's question yet. Keep your streak alive!",
|
'A moment is waiting for you. Tap to open and share your thoughts.',
|
||||||
{ type: 'streak_reminder' }
|
{ type: 'streak_reminder' }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue