feat: extend notification system with batch sender, bulk dialog, and logging

Add NotificationLog schema extensions (nullable userId, email, roundId,
projectId, batchId fields), batch notification sender service, and bulk
notification dialog UI. Include utility scripts for debugging and seeding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 13:29:06 +01:00
parent 8f2f054c57
commit f24bea3df2
15 changed files with 1316 additions and 16 deletions

View File

@@ -0,0 +1,68 @@
import { PrismaClient } from '@prisma/client'
import crypto from 'crypto'
import { sendInvitationEmail } from '../src/lib/email'
const prisma = new PrismaClient()
async function main() {
// Find a program to attach the project to
const program = await prisma.program.findFirst()
if (!program) throw new Error('No program found - run seed first')
// Create applicant user
const inviteToken = crypto.randomBytes(32).toString('hex')
const user = await prisma.user.create({
data: {
id: 'test_applicant_matt_ciaccio',
name: 'Matt Ciaccio',
email: 'matt.ciaccio@gmail.com',
role: 'APPLICANT',
roles: ['APPLICANT'],
status: 'INVITED',
mustSetPassword: true,
inviteToken,
inviteTokenExpiresAt: new Date(Date.now() + 72 * 60 * 60 * 1000),
},
})
console.log('Created user:', user.id)
// Create test project
const project = await prisma.project.create({
data: {
id: 'test_project_qa',
title: 'OceanWatch AI',
description: 'AI-powered ocean monitoring platform for marine conservation',
programId: program.id,
submittedByUserId: user.id,
},
})
console.log('Created project:', project.id)
// Create team member (LEAD)
await prisma.teamMember.create({
data: {
id: 'test_tm_lead',
projectId: project.id,
userId: user.id,
role: 'LEAD',
},
})
console.log('Created team member (LEAD)')
// Send styled invitation email
const url = `http://localhost:3000/accept-invite?token=${inviteToken}`
console.log('Invite URL:', url)
await sendInvitationEmail(
'matt.ciaccio@gmail.com',
'Matt Ciaccio',
url,
'APPLICANT',
72
)
console.log('Styled invitation email sent!')
}
main()
.catch(console.error)
.finally(() => prisma.$disconnect().then(() => process.exit(0)))