Skip to content

fix: prevent data corruption in invoice share links and contract legacy fallback#9

Draft
cursor[bot] wants to merge 3 commits intomainfrom
cursor/critical-bug-inspection-b5c8
Draft

fix: prevent data corruption in invoice share links and contract legacy fallback#9
cursor[bot] wants to merge 3 commits intomainfrom
cursor/critical-bug-inspection-b5c8

Conversation

@cursor
Copy link
Copy Markdown

@cursor cursor Bot commented Apr 30, 2026

Critical bugs found and fixed

Bug 1: Invoice share links silently revert paid invoices to unpaid

Impact: Data corruption — income tracking becomes inaccurate, paid invoices appear unpaid.

Root cause: generateInvoiceShareLink in lib/api/invoices.ts unconditionally executed .update({ status: 'unpaid' }) on every call. When a user copies a share link for a paid invoice, its status is silently reset to unpaid, corrupting the income tracker.

Trigger scenario: User marks invoice as paid → clicks "Copy share link" to send the payment confirmation URL to a client → invoice status reverts to unpaid → income tracker shows lower revenue.

Fix: Read the current status before updating. Only transition draft/archived invoices to unpaid; paid and already-unpaid invoices are left untouched. The share token generation still works in all cases.

Bug 2: Operator precedence causes silent data loss on contract save

Impact: Silent data truncation — deliverables, milestones, clauses, and other extended columns are silently dropped.

Root cause: isLegacyContractConstraintOrSchemaError in lib/api/contracts.ts had a missing parentheses group:

// Before (broken): || has lower precedence than &&
lower.includes('contracts_status_check')
|| lower.includes('status')   // ← always matches generic status errors!
|| lower.includes('column') && lower.includes('contracts') && lower.includes('does not exist')

// After (fixed):
lower.includes('contracts_status_check')
|| (lower.includes('column') && lower.includes('contracts') && lower.includes('does not exist'))

Any error message containing the word "status" (e.g. "Failed to update contract status", "Request failed with status code 500") would falsely trigger the legacy fallback path, which silently drops deliverables, milestones, clauses, and all extended schema columns.

Trigger scenario: A transient network error or any Supabase error containing "status" during contract create/update → code enters legacy fallback → contract is saved with missing deliverables, milestones, and clauses.

Fix: Removed the overly broad lower.includes('status') branch and added proper parentheses grouping.

Validation

  • All 23 tests pass (5 test files), including 6 new regression tests for the legacy schema error detection logic.
  • Manual trace through all caller chains confirms both fixes are correct and minimal.
Open in Web View Automation 

cursoragent and others added 3 commits April 30, 2026 11:11
generateInvoiceShareLink unconditionally set status to 'unpaid',
silently reverting paid invoices back to unpaid when a user copies
a share link. This corrupts income tracking data.

Now reads current status first and only transitions draft/archived
invoices to 'unpaid'; paid and already-unpaid invoices are left
untouched.

Co-authored-by: Ananta Mishra <anantamishra@users.noreply.github.com>
isLegacyContractConstraintOrSchemaError had a missing parentheses
group, causing any error containing the word 'status' to trigger
the legacy fallback path. This silently dropped deliverables,
milestones, clauses, and other extended columns during contract
create/update operations.

Removed the overly broad 'status' branch and added proper grouping
for the column-missing check.

Co-authored-by: Ananta Mishra <anantamishra@users.noreply.github.com>
Covers the operator-precedence fix to prevent regression. Verifies
that generic errors containing 'status' no longer falsely trigger
the legacy fallback path.

Co-authored-by: Ananta Mishra <anantamishra@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stacklite-live Ready Ready Preview, Comment Apr 30, 2026 11:12am

@supabase
Copy link
Copy Markdown

supabase Bot commented Apr 30, 2026

This pull request has been ignored for the connected project gakcnwqvkusuifdqjqzz because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant