Añade EPs HTTP para que el bot de WhatsApp pueble la BD
El bot (Luisa) es externo y no toca Postgres directamente. Cuatro endpoints autenticados con Bearer FUNNEL_API_KEY, validados con zod: - POST /api/leads/:id/conversacion → turno de chat (+ estado_wa/bot_step) - POST /api/leads/:id/perfil → update parcial del lead (extracción) - POST /api/leads/:id/calificacion → upsert de lead_calificacion - POST /api/leads/:id/intento → registro en intentos_contacto Helpers compartidos lib/api/funnel-auth.ts (autorizado + jsonResponse) y lib/api/bot-request.ts (validarBotRequest: auth + JSON + zod + lead existe). La ruta de ingesta se refactoriza para reutilizar funnel-auth (DRY). Schemas puros en lib/funnel/bot-schemas.ts con tests, y doc en api-docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
34
mvp/b2c/src/lib/api/bot-request.ts
Normal file
34
mvp/b2c/src/lib/api/bot-request.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { z } from 'zod';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { db } from '@/db';
|
||||
import { leads } from '@/db/schema';
|
||||
import { autorizado, jsonResponse } from '@/lib/api/funnel-auth';
|
||||
|
||||
// Valida una petición de los EPs del bot: auth Bearer + JSON + zod + que el lead exista.
|
||||
// Devuelve { error } con la Response lista, o { leadId, body } ya validado.
|
||||
export async function validarBotRequest<S extends z.ZodTypeAny>(
|
||||
req: Request,
|
||||
params: Promise<{ id: string }>,
|
||||
schema: S,
|
||||
): Promise<{ error: Response } | { leadId: string; body: z.infer<S> }> {
|
||||
if (!autorizado(req)) return { error: jsonResponse({ ok: false, error: 'No autorizado.' }, 401) };
|
||||
const { id } = await params;
|
||||
|
||||
let raw: unknown;
|
||||
try {
|
||||
raw = await req.json();
|
||||
} catch {
|
||||
return { error: jsonResponse({ ok: false, error: 'JSON inválido.' }, 422) };
|
||||
}
|
||||
const parsed = schema.safeParse(raw);
|
||||
if (!parsed.success) {
|
||||
return {
|
||||
error: jsonResponse({ ok: false, error: parsed.error.issues[0]?.message ?? 'Datos inválidos.' }, 422),
|
||||
};
|
||||
}
|
||||
|
||||
const [lead] = await db.select({ id: leads.id }).from(leads).where(eq(leads.id, id)).limit(1);
|
||||
if (!lead) return { error: jsonResponse({ ok: false, error: 'Lead no encontrado.' }, 404) };
|
||||
|
||||
return { leadId: id, body: parsed.data };
|
||||
}
|
||||
Reference in New Issue
Block a user