fix(portal): validate waitlist preferredTime/preferredDate, return 400 on bad input (GRO-2211) #179

Merged
Flea Flicker merged 1 commits from fix/gro-2214-portal-waitlist-validation into dev 2026-06-08 17:19:40 +00:00
Member

What

Defense-in-depth (parent defect GRO-2211): the portal waitlist API must never return a raw 500 for malformed client input.

createWaitlistEntrySchema / updateWaitlistEntrySchema declared preferredTime / preferredDate as bare z.string(), so a malformed value (e.g. a full ISO datetime) was inserted straight into the Postgres time / date columns, throwing a DateTimeParseError that surfaced as an unhandled 500.

Changes (src/routes/portal.ts)

  • preferredTime constrained to ^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$ (HH:MM or HH:MM:SS) on both create and update schemas.
  • preferredDate constrained to ^\d{4}-\d{2}-\d{2}$ (YYYY-MM-DD) on both schemas.
  • HH:MM normalized to HH:MM:SS before insert/update (matches the Postgres time column).
  • With zValidator, malformed input now returns 400 before touching the DB.

Tests (src/__tests__/waitlist.test.ts)

  • Full ISO datetime preferredTime (2026-06-09T10:00:00.000Z) → 400 (create + update), no DB write.
  • Malformed preferredDate (03/25/2026) → 400.
  • Out-of-range preferredTime (25:99) → 400.
  • Valid HH:MM:SS201; HH:MM normalized to HH:MM:SS on insert.

Verification

  • npm run typecheck — clean
  • npm run lint — 0 errors (7 pre-existing warnings)
  • npm test630 passed (43 files)

Acceptance criteria

  • Full ISO-8601 preferredTime400 with validation message
  • Valid HH:MM:SS201 and inserts
  • Tests added and green
  • Root-script CI (lint / typecheck / test) green

Resolves GRO-2214 (parent GRO-2211).

## What Defense-in-depth (parent defect **GRO-2211**): the portal waitlist API must never return a raw **500** for malformed client input. `createWaitlistEntrySchema` / `updateWaitlistEntrySchema` declared `preferredTime` / `preferredDate` as bare `z.string()`, so a malformed value (e.g. a full ISO datetime) was inserted straight into the Postgres `time` / `date` columns, throwing a `DateTimeParseError` that surfaced as an unhandled **500**. ## Changes (`src/routes/portal.ts`) - `preferredTime` constrained to `^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$` (HH:MM or HH:MM:SS) on **both** create and update schemas. - `preferredDate` constrained to `^\d{4}-\d{2}-\d{2}$` (YYYY-MM-DD) on both schemas. - HH:MM normalized to HH:MM:SS before insert/update (matches the Postgres `time` column). - With `zValidator`, malformed input now returns **400** before touching the DB. ## Tests (`src/__tests__/waitlist.test.ts`) - Full ISO datetime `preferredTime` (`2026-06-09T10:00:00.000Z`) → **400** (create + update), no DB write. - Malformed `preferredDate` (`03/25/2026`) → **400**. - Out-of-range `preferredTime` (`25:99`) → **400**. - Valid `HH:MM:SS` → **201**; `HH:MM` normalized to `HH:MM:SS` on insert. ## Verification - `npm run typecheck` — clean - `npm run lint` — 0 errors (7 pre-existing warnings) - `npm test` — **630 passed (43 files)** ## Acceptance criteria - [x] Full ISO-8601 `preferredTime` → **400** with validation message - [x] Valid `HH:MM:SS` → **201** and inserts - [x] Tests added and green - [x] Root-script CI (lint / typecheck / test) green Resolves GRO-2214 (parent GRO-2211).
Flea Flicker added 1 commit 2026-06-08 17:17:40 +00:00
fix(portal): validate waitlist preferredTime/preferredDate, return 400 on bad input (GRO-2211)
CI / Test (pull_request) Successful in 26s
CI / Lint & Typecheck (pull_request) Successful in 29s
CI / Build & Push Docker Images (pull_request) Successful in 1m9s
2f20ef7287
createWaitlistEntrySchema/updateWaitlistEntrySchema declared preferredTime/
preferredDate as bare z.string(), so a malformed value (e.g. a full ISO
datetime) was inserted straight into the Postgres time/date columns, throwing
a DateTimeParseError that surfaced as an unhandled 500.

Constrain both fields with regexes (HH:MM[:SS] / YYYY-MM-DD) so zValidator
rejects bad input with 400 before it hits the DB, and normalize HH:MM to
HH:MM:SS on insert/update. Adds waitlist tests covering the 400 paths and
HH:MM normalization.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Flea Flicker merged commit 29c42e3130 into dev 2026-06-08 17:19:40 +00:00
Sign in to join this conversation.