@@ -71,11 +71,11 @@ export class VConQueries {
7171 }
7272 }
7373
74- // Insert main vcon
74+ // Upsert main vcon — idempotent on re-submission of same UUID
7575 // Set id = uuid so they match (id is the PK, uuid is the vCon document UUID)
7676 const { data : vconData , error : vconError } = await this . supabase
7777 . from ( 'vcons' )
78- . insert ( {
78+ . upsert ( {
7979 id : vcon . uuid , // Explicitly set id to match uuid
8080 uuid : vcon . uuid ,
8181 vcon_version : vcon . vcon ?? '0.3.0' ,
@@ -87,7 +87,7 @@ export class VConQueries {
8787 redacted : vcon . redacted || { } ,
8888 appended : vcon . appended || { } , // ✅ Added per spec
8989 tenant_id : tenantId , // ✅ Added for RLS multi-tenant support
90- } )
90+ } , { onConflict : 'id' } )
9191 . select ( 'id, uuid' )
9292 . single ( ) ;
9393
@@ -99,6 +99,14 @@ export class VConQueries {
9999 throw vconError ;
100100 }
101101
102+ // Delete existing child rows so re-submission replaces them cleanly
103+ await Promise . all ( [
104+ this . supabase . from ( 'parties' ) . delete ( ) . eq ( 'vcon_id' , vconData . id ) ,
105+ this . supabase . from ( 'dialog' ) . delete ( ) . eq ( 'vcon_id' , vconData . id ) ,
106+ this . supabase . from ( 'analysis' ) . delete ( ) . eq ( 'vcon_id' , vconData . id ) ,
107+ this . supabase . from ( 'attachments' ) . delete ( ) . eq ( 'vcon_id' , vconData . id ) ,
108+ ] ) ;
109+
102110 // Insert parties
103111 if ( vcon . parties . length > 0 ) {
104112 const partiesData = vcon . parties . map ( ( party , index ) => ( {
0 commit comments