Case StudyFood & Beverage Wholesale Distribution·2025·Austria (EU)

AEKSHEA FOODS

B2B Wholesale Trade Platform — Austria / EU

ClientAekshea Foods Wholesale GmbH, Salzburg
TypeB2B Trade Ordering Platform
Live Site
AEKSHEA FOODS
60+ SKUs live at launch, schema built for thousands

Catalogue

11 migrations with full audit trail

Schema History

2 shipped (EN / NL), extensible

Languages

~€0/month on commercially-licensed free tier

Hosting Cost

The Problem

A wholesaler's price list is its most guarded asset. Aekshea Foods distributes South Asian food brands — Haldiram's, MDH, TRS, Tata Tea, Patak's — to restaurants, grocers and caterers across Austria and the wider EU, and runs on negotiated pricing: a large restaurant group pays a different rate to an independent corner shop, and neither is meant to discover what the other pays. That makes a wholesale storefront fundamentally harder than a retail one. The catalogue has to be fully public for buyers and search engines, while the prices attached to it must be invisible to anyone without an approved trade account and tier-specific for everyone who has one. Hiding prices in the interface is theatre — the data still travels to the browser and sits in the API response.

What We Built

We enforced pricing visibility as a database access rule rather than application logic. Every request to the price table — from the website, the API, or anything else — passes through a PostgreSQL row-level security policy that asks who the caller is and returns only the rows their trade account is entitled to. An anonymous visitor does not receive a masked price or a hidden field; they receive zero rows. There is no code path, no forgotten endpoint and no future feature that can accidentally expose a price list, because the restriction is a property of the data itself rather than something the application must remember to apply.

// HOW IT WORKS

Under the Hood

Pricing Gate in the Database, Not the Interface

A row-level security policy on the prices table resolves the caller's customer group and validity window before returning any row. Stock levels follow the same rule, so competitors cannot read the inventory position off a public page. A standing check assumes the role of an anonymous visitor and counts reachable price rows — the expected answer is zero, verified before any feature work proceeds. It caught a genuine leak during development, where a catalogue view bypassed the policy until it was rebuilt to respect the caller identity.

EU VAT Engine That Fails Safely

Resolves domestic rate, reverse charge or export per order. Reverse charge applies only when a VAT number has been positively verified; an unverified number is treated exactly like no number at all. The failure mode is asymmetric — zero-rate a sale against an invalid number and the seller is liable for tax never collected — so the engine charges VAT in the ambiguous case.

Invoices as Frozen Documents

Each invoice captures a complete snapshot at issue: seller identity, buyer identity, every line, the VAT breakdown and the legal wording. Rendering an invoice from the live catalogue breaks the moment a product is renamed or a rate changes. Records are immutable by design, and the system refuses to issue any invoice while the seller tax identity is still a development placeholder.

Wholesale Rules Enforced Twice, Deliberately

Minimum order quantities, order multiples and order minimums are enforced by database triggers and also checked in the interface. The database layer makes an invalid order impossible; the interface layer lets a buyer understand why their cart is not ready before they reach checkout. Validation that only protects data produces correct orders and frustrated customers.

// TECH STACK
FrameworkNext.js 16 (App Router, React 19)
Data & AuthSupabase (PostgreSQL row-level security)
CMSSanity (marketing content, kept apart from product data)
HostingCloudflare Workers (global edge)
EmailResend (transactional)
// WHAT IT DOES
  • +Trade account approval — pricing unlocks only after staff review
  • +Tiered price lists with validity windows for seasonal and negotiated rates
  • +EU VAT engine resolving domestic, reverse-charge and export per order
  • +Invoicing on account against agreed payment terms, frozen at issue
  • +Quick-order pad and saved lists for weekly reordering in seconds
  • +Order minimums, case quantities and multiples enforced in the database
  • +Staff operations console — approvals, products, bulk import, picking, shipping
  • +Multi-language storefront with translations in dedicated tables
// THE HARD CALLS

Why We Did
What We Did

Every architectural decision has a reason. Here are the ones worth explaining.

01

Why enforce pricing in the database instead of the application?

Application-layer checks are only as good as every developer remembering to apply them to every endpoint, now and in future. A row-level security policy applies to every caller equally — website, API, or anything else — so no interface bug or new feature can expose a price list. The restriction is a property of the data, not a convention the code follows.

02

Why charge VAT when a buyer supplies an unverified VAT number?

The failure mode is asymmetric. Over-collecting produces a conversation; under-collecting produces a bill, because a seller who zero-rates against an invalid number is liable for the tax. Until live VIES verification is wired in, an unverified number is treated exactly like no number at all.

03

Why freeze invoices instead of rendering them from current data?

An invoice is a legal document, not a view. Render it from the live catalogue and reprinting an old invoice after a rename or a rate change shows something that was never billed. Freezing the full snapshot at issue keeps the record defensible.

Ready to Build Something Like This?

Let's talk about your project.