Back to projects
GOA B2B sign-in screen for professional customers
Sign-in — access is invitation-only: there is no public sign-up, only customers GOA already works with.

Project context


Orders used to arrive through a Jotform. Someone at GOA then retyped each one into Easybeer, by hand, between 100 and 150 times a month. The form knew nothing about who was ordering: no customer-specific prices, no discounts, no minimum order, no carrier constraints. Everything was checked afterwards, and mistakes were caught late.

The brief was not to rebuild that ERP, it was to stop duplicating it. The platform reads from Easybeer and writes only orders back to it, which means GOA keeps a single place to manage products, prices and customers — and their customers get an ordering experience that already knows their terms.

Customer shop showing products, per-client prices and a live cart
Customer shop — commercial terms, per-client prices, discounts and VAT are computed live while the cart is built.

How it works


  1. Sync

    A server-side job pulls the catalogue, per-client prices, discounts and delivery settings from Easybeer and caches them in Firestore.

  2. Order

    Professional customers browse their own catalogue at their own prices and build a cart that already knows their discounts, minimum and carrier rules.

  3. Write back

    Validating the cart creates the order directly in Easybeer. Nothing is retyped, and re-saving updates the same order instead of duplicating it.

Admin dashboard summarising customers, orders and catalogue
Admin dashboard — customers, orders and catalogue in one glance, with the timestamp of the last ERP sync.
Admin order list with statuses, payment state and documents
Orders — the list that used to be a form inbox, now reading order status, payment state and invoices straight from the ERP.
Catalogue administration with pricing tiers, visibility and stock toggles
Catalogue — the override layer: display name, price tiers, visibility and availability, product by product.

Selected product decisions


Easybeer stays the source of truth

The platform reads catalogue, prices, discounts, client settings and invoices from the ERP, and writes exactly one thing back: the order. No business data is duplicated, so GOA keeps managing its products and pricing where it always has.

Every price is personal

Prices are never uniform — the same bottle costs a different amount depending on customer type, with custom per-client rates and four levels of discounts layered on top. Every price on screen is resolved for the customer who is logged in, never a default list price.

An opt-in catalogue

The ERP holds dozens of referenced products, but only a handful should be orderable. An override layer lets GOA toggle visibility, rewrite technical labels, attach a photo and flag a product as out of stock — new products stay hidden by default.

Business rules live in the cart

Carrier constraints are enforced while ordering: customers shipped by La Poste order in multiples of 3 for 35 cl and 2 for 1 L so crates stay homogeneous, and the minimum order value is read from each customer record.

Editable, not re-ordered

An order stays editable until the ERP marks it as delivered. Saving again upserts the same order rather than creating a second one, which removes the old “this order cancels the previous one” workaround.

Mobile before desktop

Around 90 % of orders are placed from a phone, often in a bar or a back room. The ordering flow is designed for that context first; the admin side assumes a larger screen.

Admin customer list with search, customer types and account status
Customers — the bridge between an ERP record and a platform account, and where invitations are sent from.

Technical approach


Frontend

Vue 3, Vite and TypeScript, with shadcn-vue (Reka UI + Tailwind CSS v4) as a single design system across the customer shop and the admin console. TanStack Query for reads, TanStack Table for the admin grids, Zod for validation.

Backend

A Hono server acting as the only door to Easybeer: Basic Auth credentials stay server-side and never reach the browser bundle, alongside admin endpoints, order writes and the scheduled sync job.

Auth & data

Firebase Auth, with no public sign-up at all: an account exists only for a customer GOA already invoices, invited from their ERP record. Firestore holds the platform-side state — the part the ERP does not own — and Firebase Storage the product photos.

Living with a throttled API

The ERP API throttles aggressively, and retrying during a cooldown only makes it worse. A single outbound queue paces every call, a circuit breaker fails locally instead of hammering the API while a cooldown is active, and the cached read model means customer traffic never reaches the ERP at all — only order writes do.

Work with me