feat: LinkedIn editorial, accesos agencia estables y deshacer en historial

Integra estrategias LinkedIn en calendarios (backlog publicado vs pendiente), unifica roles/cookies de vista agencia y permite deshacer cambios de brandbook dejando constancia en el historial.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-10-16 04:15:51 +02:00
parent 3b57cdce53
commit 4a1abd3318
54 changed files with 6400 additions and 527 deletions

View File

@@ -0,0 +1,82 @@
/**
* Re-enrich TYD/TSP/ECP/DTATF + dump Drive folder scores.
* npx tsx scripts/audit_four_brands.ts
*/
import { config } from 'dotenv';
import { resolve } from 'path';
config({ path: resolve(process.cwd(), '.env.local') });
import { enrichTenantBrandbook } from '../src/lib/brandbook-enrich';
import { ensureCreativesDriveFolders } from '../src/lib/creatives-drive';
import { listClientFoldersUnderClientes } from '../src/lib/google-drive';
import { scoreNameToTenant } from '../src/lib/match';
const FOCUS = ['tyd', 'tsp', 'ecp', 'dtatf'] as const;
async function main() {
const url = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const key = process.env.SUPABASE_SERVICE_ROLE_KEY!;
const h = { apikey: key, Authorization: `Bearer ${key}` };
const { folders, clientesRoot } = await listClientFoldersUnderClientes();
console.log(
'Drive root',
clientesRoot?.name || '(none)',
'folders',
folders.length
);
for (const f of [...folders].sort((a, b) => a.name.localeCompare(b.name))) {
console.log(' ', f.name);
}
for (const slug of FOCUS) {
const tr = await fetch(
`${url}/rest/v1/tenants?slug=eq.${slug}&select=id,name,slug,drive_folder_id`,
{ headers: h }
);
const t = (await tr.json())[0] as
| { id: string; name: string; slug: string; drive_folder_id?: string }
| undefined;
if (!t) {
console.log(`[missing] ${slug}`);
continue;
}
const scored = folders
.map((f) => ({
name: f.name,
id: f.id,
score: scoreNameToTenant(f.name, t.name, t.slug),
}))
.filter((x) => x.score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, 8);
console.log(`\n[${slug}] folder scores`, scored);
const r = await enrichTenantBrandbook({
tenantId: t.id,
forceSeed: true,
});
console.log(
`[enrich] ${slug} ok=${r.ok} created=${r.created} score=${r.completenessAfter} warn=${r.warning || '-'} sources=${r.sources.join('+')}`
);
const drive = await ensureCreativesDriveFolders(t.id, slug);
console.log(
`[creatives-folders] ${slug}`,
drive.ok ? 'ok' : drive.warning
);
const bb = await fetch(
`${url}/rest/v1/documents?tenant_id=eq.${t.id}&type=eq.brandbook&select=id&limit=1`,
{ headers: h }
);
const rows = (await bb.json()) as { id: string }[];
console.log(`[bb] ${slug}`, rows[0]?.id || 'MISSING');
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});