refactor(webhooks): enhance lead processing and pipeline handling

- Updated comments in `route.ts` to clarify the lead capture process and its implications in production environments.
- Modified `kickLocalPipeline` to ensure immediate processing of events in Vercel's Hobby plan, addressing the lack of a cron job.
- Adjusted `enroll.ts` to omit `next_eval_at` during enrollment, allowing the database's default behavior to manage timing.
- Enhanced unit tests to reflect changes in enrollment behavior and ensure proper handling of lead processing.
This commit is contained in:
Ian Couto
2026-08-24 19:12:29 -03:00
parent 6186383c31
commit 7dbe7b3516
5 changed files with 11 additions and 8 deletions
+2 -1
View File
@@ -289,7 +289,8 @@ export async function POST(req: NextRequest, ctx: RouteCtx): Promise<NextRespons
metadata: { webhook_source_id: source.id },
});
// localhost: sem crontab. Prod não entra aqui (NODE_ENV=production).
// Captação: drena lead.created e inscreve no fluxo neste mesmo request.
// Sem isto, em prod (Vercel Hobby sem cron de 1 min) o gatilho fica pending.
await kickLocalPipeline(admin);
return respondWithLead(String(lead.id));
+2 -5
View File
@@ -23,10 +23,6 @@ import {
} from "@/lib/followup/engine";
import { logger } from "@/lib/logger";
function deveAcionarPipelineInline(): boolean {
return process.env.NODE_ENV === "development" || process.env.VERCEL === "1";
}
async function tickFollowupAteParar(admin: SupabaseClient): Promise<void> {
const enqueueJob = async (job: FollowupJobRequest): Promise<void> => {
const { error } = await admin.from("job_queue").insert({
@@ -67,6 +63,7 @@ export async function acelerarPipelineDeEventos(admin: SupabaseClient): Promise<
}
export async function kickLocalPipeline(admin: SupabaseClient): Promise<void> {
if (!deveAcionarPipelineInline()) return;
// Sempre: o webhook de captação em Vercel/Hobby não tem cron de 1 min.
// Na VPS o crontab continua; drenar neste request só antecipa o mesmo trabalho.
await acelerarPipelineDeEventos(admin);
}
+1
View File
@@ -42,6 +42,7 @@ function fakeDb(pointer: Row) {
insert(obj: Row) {
mode = "insert";
payload = obj;
expect(obj).not.toHaveProperty("next_eval_at");
return b;
},
eq(col: string, val: unknown) {
+2 -2
View File
@@ -107,7 +107,6 @@ export async function enrollFollowupFlow(
);
}
const now = new Date().toISOString();
const { data: created, error: insErr } = await supabase
.from("followup_enrollments")
.insert({
@@ -117,7 +116,8 @@ export async function enrollFollowupFlow(
contact_id: contactId,
current_node_id: triggerNode.id,
status: "active",
next_eval_at: now,
// next_eval_at omite: default now() do banco (migration 0147). new Date()
// do processo fica 17–34 ms à frente e o claim `<= now()` pula o tick.
agent_id: agentId,
})
.select(ENROLLMENT_LIST_COLUMNS)
@@ -58,6 +58,10 @@ const DIR = join(process.cwd(), "lib", "followup");
* `agenda` = 'nenhum' → menciona a coluna sem agendar (leitura, tradução).
*/
const ESCRITORES: Record<string, { agenda: "agora" | "futuro" | "nenhum"; nota: string }> = {
"enroll.ts": {
agenda: "agora",
nota: "o enrollment nasce vencido — o insert omite next_eval_at e o default now() do banco decide (0147).",
},
"gatilho-etapa.ts": {
agenda: "agora",
nota: "o enrollment nasce vencido — o insert omite a coluna e o default now() do banco decide (0147).",