Enforces SOTA 2026 rules for the lease/EDL signing and post-signature flow. Use when creating, modifying, or reviewing any code that touches lease or EDL signing, signature tokens, document generation/storage, seal_lease, lease_signers, edl_signatures, post-signature automation, or invoice creation after signing. Prevents broken workflows where signed documents have no file in Storage, no seal, or no initial invoice.
app/api/leases/[id]/sign/route.tsapp/api/signature/[token]/sign/route.tslib/services/lease-post-signature.service.tslib/services/lease-pdf-generator.tsapp/api/leases/[id]/pdf-signed/route.tsapp/api/leases/[id]/seal/route.tsapp/owner/_data/fetchLeaseDetails.ts (lease consolidation section)app/api/edl/[id]/sign/route.tsapp/api/signature/edl/[token]/sign/route.tslib/services/edl-post-signature.service.tsapp/tenant/inspections/[id]/TenantEDLDetailClient.tsxlease_signers.signature_status, leases.statut, or edl_signaturessigned_pdf_path, sealed_at, seal_lease, or EDL storage_pathOwner signs (app) Tenant signs (token link)
POST /api/leases/[id]/sign POST /api/signature/[token]/sign
| |
| if fully_signed | if allSigned
v v
handleLeaseFullySigned(leaseId)
lib/services/lease-post-signature.service.ts
|
|--- 1. generateSignedLeasePDF() -> returns HTML (not PDF!)
|--- 2. Upload to Storage (bails/{leaseId}/signed_final.html)
|--- 3. Upsert document (type: "bail_signe")
|--- 4. seal_lease RPC (sealed_at + signed_pdf_path)
|--- 5. ensureInitialInvoiceForLease()
|--- 6. Outbox events
Self-healing (fetchLeaseDetails)
|--- if active + no signed_pdf_path + all signers signed
|--- calls handleLeaseFullySigned() transparently
Owner signs (app) Tenant signs (token link)
POST /api/edl/[id]/sign POST /api/signature/edl/[token]/sign
| |
| if allSigned | if allSigned
v v
handleEDLFullySigned(edlId)
lib/services/edl-post-signature.service.ts
|
|--- 1. Fetch EDL data (items, media, signatures, meters)
|--- 2. generateEDLHTML() + wrap in full HTML document
|--- 3. Upload to Storage (edl/{edlId}/signed_document.html)
|--- 4. Update documents table (storage_path -> real file)
handleLeaseFullySigned() or handleEDLFullySigned().seal_lease RPC without first attempting document generation.leases.statut to fully_signed without triggering post-signature automation.fetchLeaseDetails.ts.signed_pdf_path as a placeholder (pending_generation_*) without emitting a Lease.SealRetry outbox event.pdf-lib to generate a placeholder PDF — the Edge Function is not available. Store HTML documents instead.documents row with a fictitious storage_path — the file MUST exist in Storage.window.open(GET /api/edl/{id}/pdf) — that route does not exist. EDL PDF is POST /api/edl/pdf..html, text/html) — not PDF — until a reliable server-side PDF renderer is configured.handleLeaseFullySigned() from BOTH lease signing routes when all signataires have signed.handleEDLFullySigned() from BOTH EDL signing routes when all signataires have signed.getServiceClient() (not user-scoped client) for post-signature operations.lease.sealed_at && lease.signed_pdf_path before re-running post-signature (idempotency guard).bail_signe document entry in the documents table after successful upload.ensureInitialInvoiceForLease() after sealing.POST /api/edl/pdf + html2pdf.js for client-side EDL PDF download (both owner and tenant).| Document | Storage Path | Content-Type | Generated By |
|---|---|---|---|
| Bail signé | bails/{leaseId}/signed_final.html | text/html | handleLeaseFullySigned |
| EDL signé | edl/{edlId}/signed_document.html | text/html | handleEDLFullySigned |
| Quittance | quittances/{leaseId}/{paymentId}.pdf | application/pdf | ensureReceiptDocument |
| Attestation remise clés | key-handover/{leaseId}/{handoverId}/attestation.pdf | application/pdf | ensureKeyHandoverAttestation |
draft -> sent -> pending_signature -> partially_signed
-> pending_owner_signature
-> fully_signed (triggers post-signature)
-> active (after EDL + payment + key handover)
-> notice_given -> terminated -> archived
| Domain | File |
|---|---|
| Bail post-signature | lib/services/lease-post-signature.service.ts |
| Bail document generator | lib/services/lease-pdf-generator.ts |
| EDL post-signature | lib/services/edl-post-signature.service.ts |
| EDL HTML generator | lib/templates/edl/template.service.ts |
| EDL data mapper | lib/mappers/edl-to-template.ts |
| Invoice creation | lib/services/lease-initial-invoice.service.ts |
| Owner lease sign | app/api/leases/[id]/sign/route.ts |
| Token lease sign | app/api/signature/[token]/sign/route.ts |
| Owner EDL sign | app/api/edl/[id]/sign/route.ts |
| Token EDL sign | app/api/signature/edl/[token]/sign/route.ts |
| Document download | app/api/leases/[id]/pdf-signed/route.ts |
| Seal route | app/api/leases/[id]/seal/route.ts |
| seal_lease RPC | supabase/migrations/20251228100000_sealed_lease_pdf.sql |
| Lease detail fetch | app/owner/_data/fetchLeaseDetails.ts |
| Lease readiness | app/owner/_data/lease-readiness.ts |
| Contract tab UI | app/owner/leases/[id]/LeaseDetailsClient.tsx |
| Tenant EDL detail | app/tenant/inspections/[id]/TenantEDLDetailClient.tsx |
| Document view route | app/api/documents/view/route.ts |
| Document download route | app/api/documents/download/route.ts |
| Status constants | lib/constants/roles.ts (LEASE_STATUS) |
handleLeaseFullySigned() when fully_signedhandleLeaseFullySigned() is idempotent (checks sealed_at + signed_pdf_path).html with text/html content typeseal_lease RPC is called with real document path (not placeholder)ensureInitialInvoiceForLease() is called after sealfetchLeaseDetails still works for legacy data.html extensionany types leaked into public interfaceshandleEDLFullySigned() when all signers signedhandleEDLFullySigned() generates real HTML and uploads to Storagedocuments table storage_path matches the actual file in StoragePOST /api/edl/pdf + html2pdf.js (not GET)EDLPreview component (dynamic generation)