Checkpoint: Correction robuste des doublons de factures : empreinte SHA-256 unique des PDF sources, détection globale avant import manuel/email/dossier/web, verrou contre les vérifications IMAP concurrentes, attente réelle de fin de traitement avant marquage lu, migration et tests de non-régression.

This commit is contained in:
Manus
2026-08-22 10:31:54 +00:00
parent d8b2a8fe6f
commit d729a94a96
12 changed files with 2637 additions and 82 deletions

View File

@@ -0,0 +1,2 @@
ALTER TABLE `sourceFiles` ADD `contentHash` varchar(64);--> statement-breakpoint
ALTER TABLE `sourceFiles` ADD CONSTRAINT `source_file_content_hash_unique` UNIQUE(`contentHash`);

File diff suppressed because it is too large Load Diff

View File

@@ -260,6 +260,13 @@
"when": 1785419093588,
"tag": "0036_broken_rattler",
"breakpoints": true
},
{
"idx": 37,
"version": "5",
"when": 1787394418464,
"tag": "0037_goofy_quentin_quire",
"breakpoints": true
}
]
}

View File

@@ -36,12 +36,16 @@ export const sourceFiles = mysqlTable("sourceFiles", {
fileName: varchar("fileName", { length: 255 }).notNull(),
fileKey: text("fileKey").notNull(), // Local storage key with YYYY-MM prefix
fileUrl: text("fileUrl").notNull(), // Public URL
/** Empreinte du PDF source, globale à l'application pour bloquer tout réimport identique. */
contentHash: varchar("contentHash", { length: 64 }),
totalInvoicesDetected: int("totalInvoicesDetected").default(0).notNull(),
processingStatus: mysqlEnum("processingStatus", ["processing", "completed", "error"]).default("processing").notNull(),
processingProgress: varchar("processingProgress", { length: 255 }), // Progress message (e.g., "Extraction 3/9 factures...")
createdAt: timestamp("createdAt").defaultNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
});
}, (table) => ({
contentHashIdx: uniqueIndex("source_file_content_hash_unique").on(table.contentHash),
}));
export type SourceFile = typeof sourceFiles.$inferSelect;
export type InsertSourceFile = typeof sourceFiles.$inferInsert;