diff --git a/CHANGELOG.md b/CHANGELOG.md index 27ad980..39e9a03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Backend 0.6.5] - 2026-08-19 + +### Fixed + +- Duplicate operation UUIDs in one import file now return a validation error instead of a database failure. + ## [Frontend 0.9.2 / Backend 0.6.4 / Shared 0.2.2] - 2026-08-19 ### Added diff --git a/backend/package.json b/backend/package.json index 327826d..3146015 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "@family-budget/backend", - "version": "0.6.4", + "version": "0.6.5", "private": true, "scripts": { "dev": "tsx watch src/app.ts", diff --git a/backend/src/services/import.ts b/backend/src/services/import.ts index 37deedb..5169804 100644 --- a/backend/src/services/import.ts +++ b/backend/src/services/import.ts @@ -133,12 +133,20 @@ function validateSemantics(data: StatementFile): ValidationError | null { } const fps = new Set(); + const operationIds = new Set(); for (let i = 0; i < data.transactions.length; i++) { const fp = computeFingerprint(data.statement.accountNumber, data.transactions[i]); if (fps.has(fp)) { return { status: 422, error: 'VALIDATION_ERROR', message: `Duplicate fingerprint found within file at transaction index ${i}` }; } fps.add(fp); + const operationId = data.transactions[i].operationId; + if (operationId) { + if (operationIds.has(operationId.toLowerCase())) { + return { status: 422, error: 'VALIDATION_ERROR', message: `Duplicate operationId found within file at transaction index ${i}` }; + } + operationIds.add(operationId.toLowerCase()); + } } return null;