KI-AGENT: Zentrale Benachrichtigungsengine mit Desktop Push umsetzen

This commit is contained in:
2026-05-18 19:51:08 +02:00
parent 24c09d7891
commit 4aeefb2b83
15 changed files with 11252 additions and 109 deletions

View File

@@ -1,8 +1,22 @@
import { FastifyInstance } from "fastify"
import { and, eq, ne } from "drizzle-orm"
import { authTenantUsers, authUsers } from "../../db/schema"
import { matrixService } from "../modules/matrix.service"
import { NotificationService, UserDirectory } from "../modules/notification.service"
const getUserDirectory: UserDirectory = async (server: FastifyInstance, userId) => {
const rows = await server.db
.select({ email: authUsers.email })
.from(authUsers)
.where(eq(authUsers.id, userId))
.limit(1)
return rows[0] || null
}
export default async function communicationRoutes(server: FastifyInstance) {
const matrix = matrixService(server)
const notifications = new NotificationService(server, getUserDirectory)
const handleMatrixError = (req: any, reply: any, err: any, fallbackMessage: string) => {
req.log.error(err)
return reply
@@ -33,6 +47,45 @@ export default async function communicationRoutes(server: FastifyInstance) {
}
}
const callModeFromRequest = (req: any): "audio" | "video" => {
const body = (req.body || {}) as { mode?: string }
return body.mode === "audio" ? "audio" : "video"
}
const notifyTenantUsersAboutCall = async (req: any, room: { key?: string; name?: string }, mode: "audio" | "video") => {
if (!req.user.tenant_id) return
try {
const recipientRows = await server.db
.select({ userId: authTenantUsers.user_id })
.from(authTenantUsers)
.where(and(
eq(authTenantUsers.tenant_id, req.user.tenant_id),
ne(authTenantUsers.user_id, req.user.user_id)
))
const userIds = recipientRows.map((row) => row.userId)
if (!userIds.length) return
await notifications.trigger({
tenantId: req.user.tenant_id,
userIds,
eventType: "communication.call.started",
title: mode === "audio" ? "Audioanruf gestartet" : "Videokonferenz gestartet",
message: `${room.name || room.key || "Ein Chatraum"} hat eine laufende Besprechung.`,
payload: {
link: "/communication/chat",
roomKey: room.key,
roomName: room.name,
mode,
},
channels: ["inapp", "push"],
})
} catch (err) {
req.log.error({ err }, "Call-Benachrichtigung konnte nicht ausgelöst werden")
}
}
server.get("/communication/matrix/status", async () => {
return matrix.getStatus()
})
@@ -138,10 +191,13 @@ export default async function communicationRoutes(server: FastifyInstance) {
server.post("/communication/matrix/rooms/general/call-session", async (req, reply) => {
try {
return await matrix.createLiveKitRoomSession(req.user.user_id, req.user.tenant_id, {
const room = {
key: "allgemein",
name: "Allgemeiner Chat",
})
}
const session = await matrix.createLiveKitRoomSession(req.user.user_id, req.user.tenant_id, room)
await notifyTenantUsersAboutCall(req, room, callModeFromRequest(req))
return session
} catch (err: any) {
return handleMatrixError(req, reply, err, "Matrix call session failed")
}
@@ -226,11 +282,14 @@ export default async function communicationRoutes(server: FastifyInstance) {
server.post("/communication/matrix/rooms/:roomKey/call-session", async (req, reply) => {
try {
return await matrix.createLiveKitRoomSession(
const room = roomOptionsFromRequest(req)
const session = await matrix.createLiveKitRoomSession(
req.user.user_id,
req.user.tenant_id,
roomOptionsFromRequest(req)
room
)
await notifyTenantUsersAboutCall(req, room, callModeFromRequest(req))
return session
} catch (err: any) {
return handleMatrixError(req, reply, err, "Matrix call session failed")
}