From ac6983ae685024a9bb73a620cf05cb452b6912d2 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Tue, 30 Jun 2026 11:02:49 +0000 Subject: [PATCH 1/3] only get most recent version of each uploaded file per s3 key --- .../live-tracking/property-documents/route.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/app/api/live-tracking/property-documents/route.ts b/src/app/api/live-tracking/property-documents/route.ts index 35f49915..6d5ee7f6 100644 --- a/src/app/api/live-tracking/property-documents/route.ts +++ b/src/app/api/live-tracking/property-documents/route.ts @@ -40,7 +40,31 @@ export async function GET(req: Request) { .from(uploadedFiles) .where(condition); - const documents = rows.map((row) => ({ + // Deduplicate rows that arise when the ingestion Lambda re-triggers for a deal + // that was already processed: same S3 key gets a new version, but a new DB row + // is written each time. + // + // Step 1: same s3FileKey → keep the row with the highest id (latest insert). + const latestByS3Key = new Map(); + for (const row of rows) { + const existing = latestByS3Key.get(row.s3FileKey); + if (!existing || row.id > existing.id) latestByS3Key.set(row.s3FileKey, row); + } + + // Step 2: among distinct keys, same (fileType, measureName) → keep latest. + // Rows with null fileType (unclassified) are kept as-is. + const latestByDocType = new Map(); + const unclassified: (typeof rows)[number][] = []; + for (const row of latestByS3Key.values()) { + if (!row.fileType) { unclassified.push(row); continue; } + const key = `${row.fileType}:${row.measureName ?? ""}`; + const existing = latestByDocType.get(key); + if (!existing || row.id > existing.id) latestByDocType.set(key, row); + } + + const dedupedRows = [...latestByDocType.values(), ...unclassified]; + + const documents = dedupedRows.map((row) => ({ id: String(row.id), s3FileKey: row.s3FileKey, s3FileBucket: row.s3FileBucket, From 7c9faba215461a7d30689b597417c114c78d40aa Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Tue, 30 Jun 2026 11:06:58 +0000 Subject: [PATCH 2/3] sort dupe files based on upload timestamp rather than id --- src/app/api/live-tracking/property-documents/route.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/api/live-tracking/property-documents/route.ts b/src/app/api/live-tracking/property-documents/route.ts index 6d5ee7f6..c8821de6 100644 --- a/src/app/api/live-tracking/property-documents/route.ts +++ b/src/app/api/live-tracking/property-documents/route.ts @@ -48,7 +48,9 @@ export async function GET(req: Request) { const latestByS3Key = new Map(); for (const row of rows) { const existing = latestByS3Key.get(row.s3FileKey); - if (!existing || row.id > existing.id) latestByS3Key.set(row.s3FileKey, row); + if (!existing || row.s3UploadTimestamp > existing.s3UploadTimestamp) { + latestByS3Key.set(row.s3FileKey, row); + } } // Step 2: among distinct keys, same (fileType, measureName) → keep latest. @@ -59,7 +61,9 @@ export async function GET(req: Request) { if (!row.fileType) { unclassified.push(row); continue; } const key = `${row.fileType}:${row.measureName ?? ""}`; const existing = latestByDocType.get(key); - if (!existing || row.id > existing.id) latestByDocType.set(key, row); + if (!existing || row.s3UploadTimestamp > existing.s3UploadTimestamp) { + latestByDocType.set(key, row); + } } const dedupedRows = [...latestByDocType.values(), ...unclassified]; From 54cf807f2b7153169a9d33067a314846c7142bcb Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Tue, 30 Jun 2026 11:10:19 +0000 Subject: [PATCH 3/3] correct comment following previous commit --- src/app/api/live-tracking/property-documents/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/live-tracking/property-documents/route.ts b/src/app/api/live-tracking/property-documents/route.ts index c8821de6..16e2f9ae 100644 --- a/src/app/api/live-tracking/property-documents/route.ts +++ b/src/app/api/live-tracking/property-documents/route.ts @@ -44,7 +44,7 @@ export async function GET(req: Request) { // that was already processed: same S3 key gets a new version, but a new DB row // is written each time. // - // Step 1: same s3FileKey → keep the row with the highest id (latest insert). + // Step 1: same s3FileKey → keep the row with the most recent upload timestamp. const latestByS3Key = new Map(); for (const row of rows) { const existing = latestByS3Key.get(row.s3FileKey);