FRE-4533: Merge apps/{api,web,mobile} and shared-db into ShieldAI repo
Merge FrenoCorp apps into ShieldAI packages/: - packages/api: merged routes (notifications), middleware (auth, rate-limit, error, logging), config, services (darkwatch, spamshield, voiceprint), tests - packages/web: new SolidJS web app stub - packages/mobile: new SolidJS mobile app stub - packages/shared-db: new Prisma DB package (separate from existing packages/db) - pnpm-workspace.yaml: restored (apps/* removed, already covered by packages/*) Next: reconcile packages/shared-db with packages/db, and fix server.ts correlationRoutes import
This commit is contained in:
213
packages/api/src/routes/notifications.routes.ts
Normal file
213
packages/api/src/routes/notifications.routes.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import { NotificationService } from '@shieldsai/shared-notifications';
|
||||
|
||||
export async function notificationRoutes(fastify: FastifyInstance): Promise<void> {
|
||||
let notificationService: NotificationService | undefined;
|
||||
|
||||
// Initialize notification service (will be injected via config)
|
||||
fastify.addHook('onReady', async () => {
|
||||
// Notification service will be initialized from config
|
||||
notificationService = fastify.notificationService;
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/v1/notifications/send
|
||||
* Send a notification to a user
|
||||
*/
|
||||
fastify.post(
|
||||
'/notifications/send',
|
||||
{
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['userId', 'channel', 'subject', 'body'],
|
||||
properties: {
|
||||
userId: { type: 'string' },
|
||||
channel: { type: 'string', enum: ['email', 'push', 'sms'] },
|
||||
subject: { type: 'string' },
|
||||
body: { type: 'string' },
|
||||
email: { type: 'string' },
|
||||
phone: { type: 'string' },
|
||||
fcmToken: { type: 'string' },
|
||||
apnsToken: { type: 'string' },
|
||||
priority: { type: 'string', enum: ['low', 'normal', 'high', 'urgent'] },
|
||||
metadata: { type: 'object' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const { userId, channel, subject, body, priority, metadata } = request.body;
|
||||
|
||||
const recipient = {
|
||||
userId,
|
||||
email: request.body.email,
|
||||
phone: request.body.phone,
|
||||
fcmToken: request.body.fcmToken,
|
||||
apnsToken: request.body.apnsToken,
|
||||
};
|
||||
|
||||
try {
|
||||
if (!notificationService) {
|
||||
return reply.status(503).send({
|
||||
success: false,
|
||||
error: 'Notification service not initialized',
|
||||
});
|
||||
}
|
||||
|
||||
const notifications = await notificationService.sendMultiChannelNotification(
|
||||
recipient,
|
||||
channel,
|
||||
subject,
|
||||
body,
|
||||
priority,
|
||||
metadata
|
||||
);
|
||||
|
||||
return reply.send({
|
||||
success: true,
|
||||
notifications,
|
||||
});
|
||||
} catch (error) {
|
||||
return reply.status(500).send({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /api/v1/notifications/:userId/preferences
|
||||
* Get notification preferences for a user
|
||||
*/
|
||||
fastify.get(
|
||||
'/notifications/:userId/preferences',
|
||||
{
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
required: ['userId'],
|
||||
properties: {
|
||||
userId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const { userId } = request.params;
|
||||
|
||||
try {
|
||||
if (!notificationService) {
|
||||
return reply.status(503).send({
|
||||
success: false,
|
||||
error: 'Notification service not initialized',
|
||||
});
|
||||
}
|
||||
|
||||
const preferences = await notificationService.getNotificationPreferences(userId);
|
||||
|
||||
return reply.send({
|
||||
success: true,
|
||||
preferences,
|
||||
});
|
||||
} catch (error) {
|
||||
return reply.status(500).send({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* PUT /api/v1/notifications/:userId/preferences
|
||||
* Update notification preferences for a user
|
||||
*/
|
||||
fastify.put(
|
||||
'/notifications/:userId/preferences',
|
||||
{
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
required: ['userId'],
|
||||
properties: {
|
||||
userId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean' },
|
||||
categories: { type: 'array', items: { type: 'string' } },
|
||||
},
|
||||
},
|
||||
push: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean' },
|
||||
categories: { type: 'array', items: { type: 'string' } },
|
||||
},
|
||||
},
|
||||
sms: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
enabled: { type: 'boolean' },
|
||||
categories: { type: 'array', items: { type: 'string' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (request, reply) => {
|
||||
const { userId } = request.params;
|
||||
const updates = request.body;
|
||||
|
||||
try {
|
||||
// TODO: Update preferences in database
|
||||
return reply.send({
|
||||
success: true,
|
||||
message: 'Preferences updated',
|
||||
userId,
|
||||
updates,
|
||||
});
|
||||
} catch (error) {
|
||||
return reply.status(500).send({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /api/v1/notifications/config
|
||||
* Get notification configuration status
|
||||
*/
|
||||
fastify.get('/notifications/config', async (request, reply) => {
|
||||
try {
|
||||
if (!notificationService) {
|
||||
return reply.status(503).send({
|
||||
success: false,
|
||||
error: 'Notification service not initialized',
|
||||
});
|
||||
}
|
||||
|
||||
const config = notificationService.getConfigSummary();
|
||||
|
||||
return reply.send({
|
||||
success: true,
|
||||
config,
|
||||
});
|
||||
} catch (error) {
|
||||
return reply.status(500).send({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user