← All updates
FeatureFixSecurity

Multi-tenant hardening, image uploads, and a fully furnished demo

A big day for the platform. Tenant isolation is now airtight, image uploads are live, the demo account got a complete makeover, and subdomains register themselves.

Automatic subdomain registration

New tenants no longer need a manual trip to the Vercel dashboard. When someone signs up, Whal calls the Vercel Domains API to register their subdomain automatically — slug.whal.com.au is live by the time they finish the wizard. If the API is unreachable, signup continues and the domain can be added later.

Image uploads via Vercel Blob

Three places in the app now support image uploads backed by Vercel Blob CDN storage:

  • Products — upload a product photo from the product form (compact camera icon next to Category).
  • Stock adjustments — attach evidence photos when recording damage, breakage, or corrections.
  • Inbound receiving — document delivery condition with multiple photos per receipt.

Images are drag-and-drop or click-to-browse, with thumbnail previews and one-click removal. Files are validated for type and size (5 MB max) before upload.

Tenant isolation fixes

The warehouse config reader had an unsafe fallback: when the session's tenantId was missing, it fell back to SELECT * FROM warehouse_config LIMIT 1 with no tenant filter — silently reading another tenant's data. This was the root cause of warehouse types showing incorrectly across tenants.

Both getWarehouseConfig() and saveWarehouseConfig() now refuse to operate without a valid tenant scope. Additionally, the JWT callback now backfills tenantId from the database for sessions created before multi-tenancy was added, so stale tokens self-heal on the next request.

Branded dashboard header

The dashboard header now shows the tenant's logo (compact pill mark), business name, and a Bonded/Standard badge — giving each warehouse its own identity instead of a generic page title.

Fully furnished demo warehouse

The demo account has been rewritten from scratch. Logging in as demo@whal.com.au now drops you into Sandbox Spirits Warehouse — a complete bonded warehouse with:

  • 3 clients (Sandbox Spirits, Coastal Distillery, Mountain Creek Wines)
  • 16 products across gin, vodka, whisky, rum, liqueur, RTD, and wine
  • A 4-zone warehouse layout with ~120 slots across 7 rows
  • 30 pallets placed into specific locations, including one on hold and one quarantined
  • 8 weeks of movement history, invoices, charges, dispatch requests, and alerts

The demo reset wipes all three clients and all tenant-scoped data (layout, config, fees, settings) before reseeding — so every visitor gets a clean warehouse.

Other fixes

  • Trial banner hidden for demo users — the demo tenant doesn't have a real subscription, so "Trial · 90 days left" no longer appears.
  • Trial banner hidden for super admins — platform operators don't need billing nags.
  • Setup wizard pre-populates from existing config instead of overriding your signup choices with defaults.
  • Signup form now defaults to "Bonded" warehouse type to match the DB default.