Move push notification to client instead of db trigger

This commit is contained in:
2026-02-28 16:19:08 +08:00
parent dab43a7f30
commit 0a8e388757
8 changed files with 698 additions and 226 deletions
+22 -22
View File
@@ -59,15 +59,22 @@ class NotificationsController {
);
await _client.from('notifications').insert(rows);
// push notifications are now handled by a database trigger that
// calls the `send_fcm` edge function. We keep the client-side
// `sendPush` method around for manual/integration use, but avoid
// invoking it here to prevent CORS issues on web.
// If target user IDs are provided, invoke client-side push
// flow by calling `sendPush`. We no longer rely on the DB trigger
// to call the edge function.
if (targetUserIds == null || targetUserIds.isEmpty) return;
debugPrint(
'notification rows inserted; server trigger will perform pushes',
);
debugPrint('notification rows inserted; invoking client push');
try {
await sendPush(
userIds: targetUserIds,
title: pushTitle ?? '',
body: pushBody ?? '',
data: pushData,
);
} catch (e) {
debugPrint('sendPush failed: $e');
}
}
/// Create a typed notification in the database. This method handles
@@ -167,6 +174,10 @@ class NotificationsController {
final userId = _client.auth.currentUser?.id;
if (userId == null) return;
final deviceId = await DeviceId.getId();
if (deviceId.isEmpty) {
debugPrint('registerFcmToken: device id missing; skipping');
return;
}
// upsert using a unique constraint on (user_id, device_id) so a single
// device keeps its token updated without overwriting other devices.
final payload = {
@@ -176,13 +187,6 @@ class NotificationsController {
'created_at': DateTime.now().toUtc().toIso8601String(),
};
final res = await _client.from('fcm_tokens').upsert(payload);
if (res == null) {
debugPrint(
'registerFcmToken: null response for user=$userId token=$token',
);
return;
}
final dyn = res as dynamic;
if (dyn.error != null) {
// duplicate key or RLS issue - just log it
@@ -204,12 +208,6 @@ class NotificationsController {
.eq('user_id', userId)
.eq('device_id', deviceId)
.or('token.eq.$token');
if (res == null) {
debugPrint(
'unregisterFcmToken: null response for user=$userId token=$token',
);
return;
}
final uDyn = res as dynamic;
if (uDyn.error != null) {
debugPrint(
@@ -227,11 +225,11 @@ class NotificationsController {
Map<String, dynamic>? data,
}) async {
try {
if (tokens != null) {
if (tokens != null && tokens.isNotEmpty) {
debugPrint(
'invoking send_fcm with ${tokens.length} tokens, title="$title"',
);
} else if (userIds != null) {
} else if (userIds != null && userIds.isNotEmpty) {
debugPrint(
'invoking send_fcm with userIds=${userIds.length}, title="$title"',
);
@@ -239,6 +237,7 @@ class NotificationsController {
debugPrint('sendPush called with neither tokens nor userIds');
return;
}
final bodyPayload = <String, dynamic>{
'tokens': tokens ?? [],
'user_ids': userIds ?? [],
@@ -246,6 +245,7 @@ class NotificationsController {
'body': body,
'data': data ?? {},
};
await _client.functions.invoke('send_fcm', body: bodyPayload);
} catch (err) {
debugPrint('sendPush invocation error: $err');