Phase 3.1 WS2: Backend FCM fallback, ping config, unread API

- Add require_mitra_ping + mitra_ping_interval_seconds config keys (migration)
- Add getMitraPingConfig/setMitraPingConfig to config service
- Add GET/PATCH /internal/config/mitra-ping routes for control center
- Update mitra status service: honor ping config in auto-offline sweep,
  include ping config in GET /api/mitra/status response
- Enhance pairing FCM payload with action: 'open_accept' for deep-link
- Add FCM fallback to closure.service (initiateEarlyEnd, completeSession)
- Add FCM fallback to session-timer.service (onSessionExpired)
- Add unread count queries (getActiveSessionByCustomerWithUnread,
  getActiveSessionsByMitraWithUnread)
- Add GET /api/client/chat/session/active-with-unread route
- Add GET /api/mitra/chat-requests/sessions/active-with-unread route

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 14:22:41 +08:00
parent fa8c963d92
commit ed765d230c
11 changed files with 187 additions and 17 deletions

View File

@@ -1,7 +1,7 @@
import { authenticate } from '../../plugins/auth.js'
import { getMitraByFirebaseUid } from '../../services/mitra.service.js'
import { acceptPairingRequest, declinePairingRequest } from '../../services/pairing.service.js'
import { getActiveSessionsByMitra, endSession, getMitraHistory } from '../../services/session.service.js'
import { getActiveSessionsByMitra, getActiveSessionsByMitraWithUnread, endSession, getMitraHistory } from '../../services/session.service.js'
import { respondToExtension } from '../../services/extension.service.js'
import { EndedBy } from '../../constants.js'
@@ -38,6 +38,11 @@ export const mitraChatRoutes = async (app) => {
return reply.send({ success: true, data: sessions })
})
app.get('/sessions/active-with-unread', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const sessions = await getActiveSessionsByMitraWithUnread(request.mitra.id)
return reply.send({ success: true, data: sessions })
})
app.post('/sessions/:sessionId/end', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const session = await endSession(request.params.sessionId, EndedBy.MITRA, request.mitra.id)
return reply.send({ success: true, data: session })