# Admin and support-agent push notifications The Unity game already registers a Firebase Installation ID and reacts to a fixed payload. This Next.js project (admin dashboard and customer support agent) needs two player routes, a send when an agent replies, and the admin broadcast actions. Leave the existing support-agent app notifications as they are. Those still use that app's own registration tokens. The game talks to `https://kkadmin.playpoolstudios.com` with the bearer token from `POST /api/support/player/login`. Use that same player auth on the new routes. A `401` signs the player out of support, so only return it when the bearer token is actually invalid. ## Store the game install Add one row per player. A new registration replaces the previous one. | Column | Value | | --- | --- | | `userId` | Support player id from the bearer token | | `fid` | Firebase Installation ID from the game | | `platform` | `android` | | `updatedAt` | Set on every successful register | This id is not the registration token already stored for the support-agent app. Keep those tables separate. The game id only works for the Android app `com.WalkInvest.KickKings` in the `kickkings-admin` Firebase project. The same service account can send to both apps. ### `POST /api/support/player/devices` ```json { "fid": "the-installation-id", "platform": "android" } ``` Upsert that player's row. Any `2xx` is enough. `{}` is fine. The game treats an empty success body as success. ### `DELETE /api/support/player/devices` ```json { "fid": "the-installation-id", "platform": "android" } ``` Delete the row only when both `userId` and `fid` match. If it is already gone, still return `2xx`. The game logs out even when this call fails. ## When an agent replies After the staff message is saved, load that ticket's player and send to the stored `fid`. Do this only for a staff reply. A player message does not notify the player. ```json { "message": { "fid": "", "notification": { "title": "Support", "body": "Support replied to your ticket" }, "data": { "type": "support_reply", "ticketId": "" }, "android": { "priority": "high", "notification": { "channel_id": "support" } } } } ``` `data.type` and `data.ticketId` must be those exact strings. `ticketId` is the same id the game already uses in `/api/support/player/tickets/{ticketId}`. Both data values have to be strings. Keep the lock-screen body generic. Ticket text can include withdrawal or payment details, so do not put the message body in the notification. With the Firebase Admin SDK, set `fid` to the stored id. On an older SDK that has no `fid` field, put that same id in `token`. During the current migration, `token` still accepts an installation id. If FCM returns `UNREGISTERED`, delete that row and stop retrying it. The game opens that ticket when it receives `support_reply`. If the player is already looking at it, the thread refreshes immediately. ## Admin notifications Add two actions to the admin dashboard. Both use the same sender and the same Android channel. ### Everyone This includes players who never opened support. ```json { "message": { "topic": "kk_broadcast", "notification": { "title": "", "body": "<message>" }, "data": { "type": "announcement" }, "android": { "priority": "high", "notification": { "channel_id": "support" } } } } ``` Do not prefix the topic with `/topics/`. The game subscribes to `kk_broadcast` on its own. ### One player Use the same payload, with `fid` set to that player's stored id and no `topic`. If that player has no row, show that the game has not registered yet. `announcement` does not open a screen. The title and body are the whole message, and they have to be in `notification`. The tray shows that text while the game is in the background. While the game is open, this build does not add its own banner. Sending a support reply and an admin message is the same function. Only `fid` versus `topic`, and `support_reply` versus `announcement`, change.