Make Clientify CRM sync daily and reliable via incremental upsert.

Webhooks alone miss WooCommerce deals; replace wipe+cap sync with lookback upsert and a dedicated Dokploy cron.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-10-08 11:02:51 +02:00
parent b4e843762e
commit 4baf256750
8 changed files with 419 additions and 100 deletions

View File

@@ -0,0 +1,56 @@
import { NextRequest, NextResponse } from 'next/server';
import { assertCronAuth } from '@/lib/cron-auth';
import { syncAllClientifyTenants } from '@/lib/clientify-sync';
export const dynamic = 'force-dynamic';
export const maxDuration = 300;
/**
* Daily Clientify reconciliation (source of truth for CRM deals/leads).
* Webhooks are best-effort; WooCommerce→Clientify often skips outbound events.
*
* Dokploy (daily ~05:15 UTC):
* curl -sS -H "Authorization: Bearer $CRON_SECRET" \
* "https://app.4ventures.es/api/cron/clientify-sync?lookback=60"
*/
export async function GET(req: NextRequest) {
const denied = assertCronAuth(req);
if (denied) return denied;
const lookbackDays = Math.min(
120,
Math.max(14, Number(req.nextUrl.searchParams.get('lookback')) || 60)
);
const tenantId = req.nextUrl.searchParams.get('tenant_id') || undefined;
try {
const { results } = await syncAllClientifyTenants({
tenantId,
lookbackDays,
});
const withErrors = results.filter((r) => r.error);
return NextResponse.json(
{
ok: withErrors.length === 0,
at: new Date().toISOString(),
lookbackDays,
synced: results.filter((r) => !r.error).length,
withErrors: withErrors.length,
results,
},
{ status: withErrors.length ? 207 : 200 }
);
} catch (e) {
return NextResponse.json(
{
ok: false,
error: e instanceof Error ? e.message : 'clientify-sync failed',
},
{ status: 500 }
);
}
}
export async function POST(req: NextRequest) {
return GET(req);
}

View File

@@ -92,10 +92,10 @@ export async function GET(req: NextRequest) {
};
}
// 4) Clientify CRM → leads/deals
// 4) Clientify CRM → leads/deals (prefer dedicated /api/cron/clientify-sync)
try {
const [clientify, gohighlevel] = await Promise.all([
syncAllClientifyTenants(),
syncAllClientifyTenants({ lookbackDays: Math.max(days * 2, 30) }),
syncAllGhlTenants(),
]);
const results = [...clientify.results, ...gohighlevel.results];

View File

@@ -329,7 +329,7 @@ async function upsertDeal(tenantId: string, d: Json) {
else if (/google/.test(tagBlob)) source = 'google';
else if (
/woocommerce|ecommerce/.test(tagBlob) ||
/^order\s+\d+/i.test(dealName)
/^(order|pedido)\s+\d+/i.test(dealName)
) {
source = 'ecommerce';
}