fix(migration): NocoDB import safety + dedup helpers + lead-source backfill

migration-apply: residential client + interest inserts now wrap in
db.transaction so a partial failure can't leave an orphan client
row without its interest (or vice versa).

migration-transform: buildPlannedDocument returns null when there
are no signers so the apply pass doesn't try to send a Documenso
envelope without recipients. mapDocumentStatus gets an explicit
"Awaiting Further Details" branch that no longer auto-promotes via
stale sign-time fields. parseFlexibleDate handles ISO and DD-MM-YYYY
inputs uniformly.

backfill-legacy-lead-source: chunk UPDATE WHERE clause now
isNull(source) on top of the inArray match, so a re-run can't
overwrite a more accurate source written between batches.

Adds 235 lines of vitest coverage on migration-transform.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Ciaccio
2026-05-04 22:56:18 +02:00
parent 089f4a67a4
commit d62822c284
9 changed files with 938 additions and 47 deletions

View File

@@ -178,6 +178,12 @@ async function main(): Promise<void> {
);
console.log(` Output: ${s.outputClients} clients, ${s.outputInterests} interests`);
console.log(` ${s.outputContacts} contacts, ${s.outputAddresses} addresses`);
console.log(
` ${s.outputDocuments} EOI documents, ${s.outputDocumentSigners} signers`,
);
console.log(
` ${s.outputResidentialClients} residential clients (with default-stage interests)`,
);
console.log(
` Dedup: ${s.autoLinkedClusters} auto-linked clusters, ${s.needsReviewPairs} pairs flagged for review`,
);
@@ -217,6 +223,14 @@ async function main(): Promise<void> {
console.log(
` Interests: ${result.interestsInserted} inserted, ${result.interestsSkipped} already linked`,
);
console.log(
` Documents: ${result.documentsInserted} inserted, ${result.documentsSkipped} already linked`,
);
console.log(` Signers: ${result.documentSignersInserted} inserted`);
console.log(
` Res-Clt: ${result.residentialClientsInserted} inserted, ${result.residentialClientsSkipped} already linked`,
);
console.log(` Res-Int: ${result.residentialInterestsInserted} inserted`);
if (result.warnings.length > 0) {
console.log('');