feat(client): FCM web push registration

web/index.html loads the Firebase compat SDK and defines
window.kcGetPushToken() — inits Firebase from window.KC_FIREBASE, asks for
notification permission, registers the service worker and returns an FCM
token (or null if not configured / denied). web/firebase-messaging-sw.js
shows background notifications.

browser_web.dart exposes getPushToken() over that JS function (stub returns
null off-web). After every successful login AppState fires
_registerForPush() -> POST /api/push/register, best-effort.

Config placeholders carry the known values (projectId konfi-castle-app,
messagingSenderId 307226979593); apiKey / appId / vapidKey still say
REPLACE_ME, so push stays inert until they're filled in — the app runs
either way. flutter analyze/test/build web green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 11:45:01 +02:00
co-authored by Claude Sonnet 5
parent cc663c7e17
commit 530be36458
5 changed files with 86 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
// Background handler for FCM web push. Keep the config in sync with
// window.KC_FIREBASE in index.html (a service worker can't read window).
// Fill in apiKey / appId from the Firebase console before enabling push.
importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-compat.js');
firebase.initializeApp({
apiKey: 'REPLACE_ME',
projectId: 'konfi-castle-app',
messagingSenderId: '307226979593',
appId: 'REPLACE_ME',
});
firebase.messaging().onBackgroundMessage(function (payload) {
const n = payload.notification || {};
self.registration.showNotification(n.title || 'KC-App', {
body: n.body || '',
icon: '/icons/Icon-192.png',
data: payload.data || {},
});
});
+33
View File
@@ -31,6 +31,39 @@
<title>KC-App</title>
<link rel="manifest" href="manifest.json">
<!-- Firebase Cloud Messaging (web push). Fill in apiKey / appId / vapidKey
from the Firebase console (Project settings > General / Cloud Messaging).
Until then window.KC_FIREBASE.apiKey stays "REPLACE_ME" and
kcGetPushToken() returns null, so the app simply runs without push. -->
<script src="https://www.gstatic.com/firebasejs/10.13.2/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-compat.js"></script>
<script>
window.KC_FIREBASE = {
apiKey: "REPLACE_ME",
authDomain: "konfi-castle-app.firebaseapp.com",
projectId: "konfi-castle-app",
storageBucket: "konfi-castle-app.firebasestorage.app",
messagingSenderId: "307226979593",
appId: "REPLACE_ME",
vapidKey: "REPLACE_ME"
};
window.kcGetPushToken = async function () {
try {
var cfg = window.KC_FIREBASE;
if (!cfg.apiKey || cfg.apiKey === "REPLACE_ME" || !("Notification" in window)) return null;
if (!firebase.apps.length) firebase.initializeApp(cfg);
var permission = await Notification.requestPermission();
if (permission !== "granted") return null;
var registration = await navigator.serviceWorker.register("firebase-messaging-sw.js");
var messaging = firebase.messaging();
return await messaging.getToken({ vapidKey: cfg.vapidKey, serviceWorkerRegistration: registration });
} catch (e) {
console.warn("[push] init failed", e);
return null;
}
};
</script>
</head>
<body>
<!--