import type { FastifyInstance } from 'fastify'; import type { FastifySchema } from 'fastify'; import type pg from 'pg'; import { z } from 'zod'; import type { Authenticate } from '../../../shared/auth.js'; import { requireRole } from '../../../shared/auth.js'; import { parseJson } from '../../../shared/http-input.js'; import { errorSchema } from '../../../shared/swagger.js'; import { NotificationsService } from '../application/notifications-service.js'; import { PgNotificationsRepository } from '../infrastructure/pg-notifications-repository.js'; export interface NotificationsRoutesDeps { pool: pg.Pool; authenticate: Authenticate; emailProvider: import('../domain/ports.js').EmailProvider; } const dispatchSchema = z .object({ eventId: z.string().min(1).max(120), template: z.enum(['order_confirmation', 'payment_failed', 'order_shipped', 'account_created']), recipient: z.string().email(), subject: z.string().min(1).max(200), body: z.string().min(1).max(5000), }) .strip(); export async function registerNotificationsRoutes( app: FastifyInstance, deps: NotificationsRoutesDeps, ): Promise { const service = new NotificationsService( new PgNotificationsRepository(deps.pool), deps.emailProvider, ); const dispatchSwaggerSchema: FastifySchema = { tags: ['Admin'], summary: 'Dispatch notification (admin)', body: { type: 'object' }, response: { 401: errorSchema, 403: errorSchema }, }; app.post('/notifications/dispatch', { schema: dispatchSwaggerSchema }, async (request, reply) => { const user = await deps.authenticate(request); requireRole(user, 'admin'); const input = parseJson(dispatchSchema, request.body); const outcome = await service.dispatch(input); return reply.send({ outcome }); }); const getMessageSchema: FastifySchema = { tags: ['Admin'], summary: 'Get notification message (admin)', params: { type: 'object', required: ['eventId'], properties: { eventId: { type: 'string' } } }, response: { 401: errorSchema, 403: errorSchema, 404: errorSchema }, }; app.get( '/notifications/messages/:eventId', { schema: getMessageSchema }, async (request, reply) => { const user = await deps.authenticate(request); requireRole(user, 'admin'); const params = z.object({ eventId: z.string().min(1).max(120) }).parse(request.params); const repo = new PgNotificationsRepository(deps.pool); const found = await repo.findByEventId(params.eventId); if (!found) throw new (await import('../../../shared/errors.js')).AppError( 404, 'NOT_FOUND', 'Message not found', ); return reply.send(found); }, ); }