feat(db): phase 4 group 1 — lib/ settings + notifications to Drizzle
Convert lib/settings.ts, lib/notifications/{in-app,email,capa-escalation,
effectiveness-recheck}.ts from Supabase PostgREST to Drizzle asAdmin queries.
Drop supabase arg from all call sites in app/api/ and cron routes. Rewrite
notification unit tests to mock @/lib/db/with-user instead of SupabaseClient.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,7 +56,7 @@ export async function POST(
|
||||
})
|
||||
|
||||
if (capa.owner_user_id) {
|
||||
await createInAppNotifications(supabase, [{
|
||||
await createInAppNotifications([{
|
||||
userId: capa.owner_user_id,
|
||||
title: body.verdict === 'verified'
|
||||
? 'Your CAPA action was verified'
|
||||
|
||||
@@ -67,7 +67,7 @@ export async function POST(request: NextRequest) {
|
||||
p_new_value: { incident_id, description, owner_user_id, department, due_date },
|
||||
})
|
||||
|
||||
await createInAppNotifications(supabase, [{
|
||||
await createInAppNotifications([{
|
||||
userId: owner_user_id,
|
||||
title: `CAPA assigned to you, due ${due_date}`,
|
||||
link: `/hse/capa/${capa.id}`,
|
||||
|
||||
@@ -2,7 +2,6 @@ export const dynamic = 'force-dynamic'
|
||||
|
||||
import { timingSafeEqual } from 'crypto'
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { escalateOverdueCapa } from '@/lib/notifications/capa-escalation'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
@@ -15,7 +14,6 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const supabase = await createClient()
|
||||
const { notified } = await escalateOverdueCapa(supabase)
|
||||
const { notified } = await escalateOverdueCapa()
|
||||
return NextResponse.json({ ok: true, notified })
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ export const dynamic = 'force-dynamic'
|
||||
|
||||
import { timingSafeEqual } from 'crypto'
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { sendEffectivenessRecheckNotifications } from '@/lib/notifications/effectiveness-recheck'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
@@ -15,7 +14,6 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const supabase = await createClient()
|
||||
const { notified } = await sendEffectivenessRecheckNotifications(supabase)
|
||||
const { notified } = await sendEffectivenessRecheckNotifications()
|
||||
return NextResponse.json({ ok: true, notified })
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ export async function POST() {
|
||||
return NextResponse.json({ error: 'Rate limit: wait 60 seconds between AI requests' }, { status: 429 })
|
||||
}
|
||||
|
||||
const deepseekKey = await getApiKey(supabase, 'DEEPSEEK_API_KEY')
|
||||
const deepseekKey = await getApiKey('DEEPSEEK_API_KEY')
|
||||
const client = createDeepSeekClient(deepseekKey)
|
||||
|
||||
let res: Awaited<ReturnType<typeof client.chat.completions.create>>
|
||||
|
||||
@@ -28,7 +28,7 @@ export async function POST(
|
||||
if ((recentCount ?? 0) > 0)
|
||||
return NextResponse.json({ error: 'Rate limited — please wait 60 seconds' }, { status: 429 })
|
||||
|
||||
const deepseekKey = await getApiKey(supabase, 'DEEPSEEK_API_KEY')
|
||||
const deepseekKey = await getApiKey('DEEPSEEK_API_KEY')
|
||||
const client = createDeepSeekClient(deepseekKey)
|
||||
|
||||
const { data: incident } = await supabase
|
||||
|
||||
@@ -28,7 +28,7 @@ export async function POST(
|
||||
if ((recentCount ?? 0) > 0)
|
||||
return NextResponse.json({ error: 'Rate limited — please wait 60 seconds' }, { status: 429 })
|
||||
|
||||
const deepseekKey = await getApiKey(supabase, 'DEEPSEEK_API_KEY')
|
||||
const deepseekKey = await getApiKey('DEEPSEEK_API_KEY')
|
||||
const client = createDeepSeekClient(deepseekKey)
|
||||
|
||||
const { data: incident } = await supabase
|
||||
|
||||
@@ -51,7 +51,7 @@ export async function POST(
|
||||
})
|
||||
|
||||
if (incident.reported_by) {
|
||||
await createInAppNotifications(supabase, [{
|
||||
await createInAppNotifications([{
|
||||
userId: incident.reported_by,
|
||||
title: `Your incident report ${incident.reference_no ?? ''} has been closed`,
|
||||
link: '/reporter',
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function GET(
|
||||
|
||||
const supabase = await createClient()
|
||||
|
||||
const googleAiKey = await getApiKey(supabase, 'GOOGLE_AI_API_KEY')
|
||||
const googleAiKey = await getApiKey('GOOGLE_AI_API_KEY')
|
||||
|
||||
const { data: incident } = await supabase
|
||||
.from('incidents')
|
||||
|
||||
@@ -22,7 +22,7 @@ export async function POST(request: NextRequest) {
|
||||
if ((recentCount ?? 0) > 0)
|
||||
return NextResponse.json({ error: 'Rate limited — please wait 60 seconds' }, { status: 429 })
|
||||
|
||||
const deepseekKey = await getApiKey(supabase, 'DEEPSEEK_API_KEY')
|
||||
const deepseekKey = await getApiKey('DEEPSEEK_API_KEY')
|
||||
const client = createDeepSeekClient(deepseekKey)
|
||||
|
||||
let body: { description?: string; incident_type?: string }
|
||||
|
||||
@@ -165,8 +165,8 @@ async function handlePost(request: Request) {
|
||||
// WhatsApp alert — fire-and-forget alongside email
|
||||
;(async () => {
|
||||
try {
|
||||
const phoneNumberId = await getApiKey(supabase, 'META_WHATSAPP_PHONE_NUMBER_ID')
|
||||
const accessToken = await getApiKey(supabase, 'META_WHATSAPP_ACCESS_TOKEN')
|
||||
const phoneNumberId = await getApiKey('META_WHATSAPP_PHONE_NUMBER_ID')
|
||||
const accessToken = await getApiKey('META_WHATSAPP_ACCESS_TOKEN')
|
||||
const { data: siteData } = await supabase
|
||||
.from('sites').select('name').eq('id', zone.site_id).single()
|
||||
const siteName = (siteData as { name: string } | null)?.name ?? 'Unknown'
|
||||
@@ -177,7 +177,6 @@ async function handlePost(request: Request) {
|
||||
.eq('site_id', zone.site_id)
|
||||
|
||||
await createInAppNotifications(
|
||||
supabase,
|
||||
(recipients ?? []).map((r: { id: string }) => ({
|
||||
userId: r.id,
|
||||
title: `New ${input.incident_type.replace(/_/g, ' ')} incident ${incident.reference_no ?? ''} at ${siteName}`,
|
||||
@@ -205,7 +204,7 @@ async function handlePost(request: Request) {
|
||||
// Embed description asynchronously for future similarity search
|
||||
const supabaseForEmbed = supabase
|
||||
import('@/lib/settings').then(({ getApiKey }) =>
|
||||
getApiKey(supabaseForEmbed, 'GOOGLE_AI_API_KEY').then(googleAiKey =>
|
||||
getApiKey('GOOGLE_AI_API_KEY').then(googleAiKey =>
|
||||
import('@/lib/claude/embed').then(({ embedText }) =>
|
||||
embedText(input.description.trim(), googleAiKey).then(embedding =>
|
||||
supabase.from('incidents').update({
|
||||
|
||||
Reference in New Issue
Block a user