Skip to content

Constrain trade inquiry venueType to known options server-side (#126) - #127

Merged
spizeck merged 1 commit into
mainfrom
fix/issue-126-venue-type-validation
Sep 24, 2026
Merged

spizeck merged 1 commit into
mainfrom
fix/issue-126-venue-type-validation

Conversation

@spizeck

@spizeck spizeck commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

Post-professionalization audit finding (also flagged during #117): POST /api/trade-inquiry required venueType to be present and ≤64 chars but accepted any string. A direct request could persist arbitrary values into tradeLeads and the Resend notification email. The form's <select> only offers six canonical options — the server now enforces the same set.

Closes #126

Changes

  • lib/trade-leads-common.ts: new exported TRADE_VENUE_TYPES (value/label pairs — single source for the <select> and the API check); pipeline rejects unknown venueType with 400 { ok: false, error: "Please choose a business type." } after required/length/email validation, before honeypot/rate-limit/submit. Trimmed values are checked, matching existing normalization.
  • components/trade-inquiry-form.tsx: renders options from TRADE_VENUE_TYPES instead of a local array (module is dependency-free, safe for the client bundle).
  • lib/trade-leads.ts: internal notification email row label Venue Type → Business Type, matching the current form/admin-doc terminology.
  • tests/lib/trade-leads.test.ts: rejects garbage/Bar/bar; DROP TABLE/bars with 400 + submit never called; accepts all six canonical values and a whitespace-padded value (trim normalization).

Regression proof: with the check removed, venueType: "garbage" returned 200 and reached submit; restored → 400, submit never called.

Verification

  • npx tsc --noEmit — clean
  • npm run lint — clean (pre-existing jsx-ast-utils notice)
  • npm test — 352 pass (2 new tests)
  • npm run build — pass
  • npx playwright test on trade-touching specs (smoke/accessibility/analytics) — 42 pass
  • npm run test:rules — 29 pass (ran on identical pipeline earlier today; no rules-adjacent change)
  • npm run check:md-links, check:react-versions — pass
  • npm audit --omit=dev — 0 vulnerabilities

Risk / deployment notes

Direct API callers sending non-canonical venueType values (e.g. capitalized "Bar") now get 400 — that is the intended fix; the UI only ever submits canonical lowercase values. No schema change; existing records unaffected.

Generated with Devin

Summary by Sourcery

Constrain trade inquiry business types to the canonical options accepted by the form.

Bug Fixes:

  • Reject trade inquiry submissions with unknown business types before they can be persisted or included in notification emails.

Enhancements:

  • Use a shared canonical business-type option list for server validation and the trade inquiry form.
  • Rename the notification email field from Venue Type to Business Type.

Tests:

  • Add coverage for rejecting invalid business types and accepting all canonical values, including trimmed input.

@sourcery-ai

sourcery-ai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The PR makes business type validation consistent across the UI and server by sharing a canonical option list, rejecting arbitrary API values before side effects, and adding focused regression tests; it also updates notification wording and includes temporary production audit scripts.

Sequence diagram for server-side trade inquiry venue validation

sequenceDiagram
    participant Client
    participant API as handleTradeInquiry
    participant Submit as trade lead submit
    participant Email as Notification email

    Client->>API: POST /api/trade-inquiry
    API->>API: Validate required fields, length, and email
    API->>API: Trim venueType
    alt venueType not in TRADE_VENUE_TYPES
        API-->>Client: 400 Please choose a business type.
        Note over API,Submit: submit is not called
    else canonical venueType
        API->>Submit: submit(trade lead)
        Submit->>Email: Send Business Type notification
        API-->>Client: Success response
    end
Loading

File-Level Changes

Change Details Files
Centralize the canonical business-type options and enforce them in the inquiry API.
  • Export value/label pairs for the six supported options.
  • Render the form select from the shared options.
  • Reject unknown or non-canonical values with a 400 response after normalization and basic validation, before honeypot, rate limiting, or submission.
lib/trade-leads-common.ts
components/trade-inquiry-form.tsx
Expand regression coverage for venue-type validation and normalization.
  • Verify representative invalid values are rejected without invoking submission.
  • Verify all canonical values and whitespace-padded values are accepted and trimmed.
tests/lib/trade-leads.test.ts
Align notification terminology with the business-type terminology used by the form and API.
  • Rename the notification email row from Venue Type to Business Type.
lib/trade-leads.ts
Add temporary production audit scripts for broad browser-based site checks.
  • Add scripts covering route health, rendering metadata, assets, console/request failures, consent behavior, mobile navigation, and map loading.
scripts/__tmp-prod-audit.mjs
scripts/__tmp-prod-audit2.mjs

Assessment against linked issues

Issue Objective Addressed Explanation
#126 Enforce the canonical venueType set server-side, returning HTTP 400 for unknown values before persistence or notification, while sharing the option list with the public form. ✅
#126 Update the internal trade inquiry notification label from "Venue Type" to "Business Type" for consistency with the form and documentation. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel

vercel Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated
deepdivebrewing-web Ready Ready Preview Sep 24, 2026 1:17am UTC

Request Review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

The form select only offers the six canonical business types, but the
API accepted any free-text value — a direct request could persist
arbitrary venueType strings into tradeLeads and the notification email.
The server now enforces the shared TRADE_VENUE_TYPES list with a 400
before persistence, same pattern as the email-format check, and the
form renders options from that list so the two can never drift.

Also aligns the internal notification email row label with the current
"Business type" form/doc terminology.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@spizeck
spizeck force-pushed the fix/issue-126-venue-type-validation branch from fd6b15f to 6394ca4 Compare September 24, 2026 01:16
@spizeck
spizeck merged commit 14a254a into main Sep 24, 2026
4 checks passed
@spizeck
spizeck deleted the fix/issue-126-venue-type-validation branch September 24, 2026 01:44

This branch was successfully deployed

1 active deployment
Preview — 6394ca4e Deployed Sep 24, 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.

Constrain trade inquiry venueType to known options server-side

1 participant