Skip to content

feat: add re-audit on pricing change with email notifications - #1

Open
darkNIGHT669 wants to merge 11 commits into
mainfrom
round-2-reaudit
Open

darkNIGHT669 wants to merge 11 commits into
mainfrom
round-2-reaudit

Conversation

@darkNIGHT669

@darkNIGHT669 darkNIGHT669 commented May 20, 2026 •

Copy link
Copy Markdown
Owner

ROUND2_PR.md

What this PR does

Adds a "re-audit on pricing change" system to SpendSight. Every audit now
stores a snapshot of the pricing data used at creation time. A detection
endpoint scans stored audits, identifies which ones are stale due to pricing
changes, and sends one consolidated email per affected user with a one-click
link to a diff view showing old vs new recommendations.

Why

AI tool pricing changes frequently — Cursor raised prices in 2024, Claude
added new tiers in 2025, Copilot restructured plans. A one-time audit becomes
misleading the moment pricing changes. Users who trusted the original audit
and acted on it deserve to know when the ground has shifted. For Credex, a
re-audit email is a high-intent re-engagement touchpoint — a user who already
cared enough to audit their stack will act on new savings information.

The assumption is that users want to be notified, not bombarded. The detection
logic sends one email per user regardless of how many of their audits are
affected, and records notifications to prevent duplicates.

How it works

Audit created
    │
    ▼
pricing_snapshot + pricing_version saved to audits table
    │
    ▼
POST /api/detect-changes (triggered by Vercel Cron weekly, or manually)
    │
    ├── Fetches all audits with pricing snapshots
    ├── Fetches all leads (email → audit_id)
    ├── For each audit: detectPricingChanges(snapshot) → PricingChange[]
    ├── Filters to changes affecting that audit's specific tools/plans
    ├── Groups affected audits by email (one email per user)
    │
    ▼
Resend email: "pricing changed, here's what's different, re-run link"
    │
    ▼
User clicks /reaudit/[auditId]
    │
    ▼
Server fetches original audit + re-runs AuditEngine with current pricing
    │
    ▼
AuditDiffView: side-by-side, changed rows highlighted, unchanged muted

New files:

  • lib/pricing-snapshot.ts — snapshot capture, change detection, version hashing
  • app/api/detect-changes/route.ts — detection + email sending
  • app/api/reaudit/[auditId]/route.ts — re-run endpoint
  • app/reaudit/[auditId]/page.tsx — diff view page
  • components/AuditDiffView.tsx — diff UI component
  • vercel.json — cron schedule (weekly Monday 9am)

Modified files:

  • app/api/audit/create/route.ts — now saves pricing_snapshot + pricing_version
  • app/api/leads/create/route.ts — fixed Resend sender for Round 1 email bug
  • app/globals.css — diff view styles appended

What I cut

  • Unsubscribe page UI — the email contains an unsubscribe link that hits
    /unsubscribe?email=X&auditId=Y but the actual page/route isn't built.
    The DB column exists (unsubscribed boolean on leads). Cut because the diff
    view is more important to the reviewer experience and the link is present
    in the email as required.

  • Admin dashboard — bonus feature, cut entirely. Would have been a table
    of stored audits + notifications sent. Skipped in favour of getting the
    diff view polished.

  • "What changed this week" public page — cut for the same reason. The
    pricing_changelog table is in the DB schema but nothing writes to it yet.
    The detection endpoint would populate it naturally with a one-line addition.

  • Per-plan detection granularity — the current detection compares
    monthlyPerSeat only. Annual billing rate changes aren't detected. This is
    a known gap; fixing it requires extending PlanSnapshot to include
    annualMonthlyEquivalent. Acceptable for 36 hours — the main price field
    is the one users care about.

  • Automated tests for new routes — ran out of time. The audit engine tests
    still pass. New routes were tested manually (see How to test below).

How to test it manually

  1. Go to https://spentsight.vercel.app and complete an audit with any tools
  2. On the results page, submit your email in the capture form
  3. Confirm you receive the Round 1 confirmation email (fixes Round 1 Resend bug)
  4. Trigger pricing change detection with a simulated price change:
curl -X POST "https://spentsight.vercel.app/api/detect-changes?simulate=cursor:pro:25" \
  -H "x-cron-secret: YOUR_CRON_SECRET"

This simulates Cursor Pro price changing from $20 to $25.

  1. Check your inbox — you should receive a re-audit email showing the change
  2. Click the "Re-run audit" link in the email
  3. The diff view at /reaudit/[auditId] shows old vs new recommendations
    with the Cursor Pro row highlighted as changed

To test without email (just the diff view):

  • Navigate directly to /reaudit/[any-valid-auditId]
  • Page always works — it re-runs the engine against the stored audit input

What's tested

  • All 6 Round 1 audit engine tests still pass (npm test)
  • detectPricingChanges() manually tested with a modified snapshot
  • getChangesAffectingAudit() manually tested with tool/plan filtering
  • Full end-to-end flow tested: audit → email capture → detect-changes →
    re-audit email → diff view

Skipped automated tests for:

  • /api/detect-changes — integration test requiring live Supabase
  • AuditDiffView — component test requiring React Testing Library setup
  • These are the first tests I'd add in a follow-up

Open questions / risks

  • Duplicate detection on cold starts: The in-memory rate limiter resets
    on serverless cold starts. The reaudit_notifications table prevents
    duplicate emails at the DB level, but if two detect-changes calls run
    simultaneously before either writes to the DB, a user could receive two
    emails. Fix: use a DB-level lock or upsert with a unique constraint on
    (audit_id, email).

  • Stale pricing_snapshot on old audits: Audits created before this PR
    have pricing_snapshot = null. The detection endpoint skips these with
    .not("pricing_snapshot", "is", null). All new audits will have snapshots.
    Old audits can never participate in re-audit notifications.

  • Cron on Vercel Hobby plan: Vercel Cron requires at minimum the Pro plan
    for custom schedules. The vercel.json cron config is included and will
    work if the project is on Vercel Pro. On Hobby, the manual POST endpoint
    still works — a GitHub Actions schedule calling the endpoint is the free
    fallback.

@vercel

vercel Bot commented May 20, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spentsight Ready Ready Preview, Comment May 21, 2026 11:55am

@darkNIGHT669 darkNIGHT669 changed the title feat: add re-audit on pricing change with email notificationsRound 2 reaudit feat: add re-audit on pricing change with email notifications May 21, 2026

This branch was successfully deployed

1 active deployment
Preview — b1441830 Deployed May 21, 2026 by vercel[bot]
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