National retail group · sub-brand · 2023 — present

Multi-store liquor commerce platform

A customer mobile app and multi-store administration system, delivered end to end — from commercial scoping through payment-provider certification to production operation.

Role
CTO — architecture, delivery lead, hands-on
Scope
Mobile app, admin, payments, delivery, search
Model
Fixed-price, phased delivery
Status
In production, actively extended

Problem

A national retail group's liquor sub-brand needed to sell online across many physical stores, each with its own catalogue, pricing and stock position. Customers had to see what was genuinely available near them, pay by card, and be able to watch a delivery arrive — while store managers needed to work only inside their own store's data.

The constraints that mattered most were commercial, not technical. The engagement was fixed-price, the payment provider's integration required formal certification before go-live, and the delivery timeline was set by a marketing launch. Anything that added moving parts added risk to all three.

Approach

I designed the platform as one Laravel application with hard internal boundaries rather than a set of independently deployed services. Multi-store tenancy went into the data model in the first migration, so onboarding a new store became a configuration task instead of a project. Everything that could tolerate latency — notifications, delivery-partner callbacks, search indexing — moved onto queues, keeping the checkout path short.

Two things were deliberately kept outside the database: catalogue search, which went to Typesense so search load never competes with transactional load, and real-time order state, which is broadcast over WebSockets rather than polled.

The payment integration was treated as its own workstream from day one, because certification timelines are outside your control. I ran the certificate lifecycle, the sandbox testing cycle with the provider's integration team, and the production cutover.

Architecture

Customer
Vue 3 + TypeScript app
Store operations
FilamentPHP admin, access-scoped
↓ CloudFront · TLS ↓
Application core
Laravel monolith · EC2 ARM64 · zero-downtime deploys via Forge
RDS PostgreSQL
source of truth
Redis + SQS
queues, cache
Typesense
catalogue search
mTLS gateway
card payments
Laravel Reverb — live order & delivery tracking
Last-mile delivery partner API
ARM64 compute, a single managed database and one runtime to monitor keep the operating bill and the on-call surface proportionate to a platform this size. The boundaries that would exist between services exist as modules instead — recoverable later if scale ever justifies the cost.

Hard parts

Mutual-TLS card payments

The provider authenticates the client with a certificate, not just a key. That makes the certificate an operational asset: I managed DigiCert OV issuance and renewal, stored the private material in AWS Secrets Manager rather than on disk, and documented the rotation procedure so expiry can never become an outage.

Per-store availability at query time

Search results must reflect the store a customer is actually ordering from. Availability filtering is applied inside the search query rather than after it, so pagination and facet counts stay correct — the failure mode most multi-store catalogues ship with.

Order state that two systems own

Fulfilment state comes partly from store staff and partly from a delivery partner's callbacks. Both paths write through the same transactional model and broadcast the result, so the customer's live tracking and the admin's view can never disagree.

Outcome