PROJECT 02OWLX

OWLX.

A bar, club, and restaurant POS platform — a domain-driven Laravel core, a Flutter floor app, and a Next.js front door, built and deployed solo across three codebases and a realtime sidecar.

solo buildend-to-enddomain-driven designsplit-tier deploy
OWLX app iconOWLX app icon
01overview

OWLX is a management and point-of-sale SaaS for bars, clubs, and restaurants — table orders, billing, staff roles, thermal-printer receipts, and live floor notifications, built as one coherent system.

I built it end-to-end across three codebases and a realtime sidecar: a Laravel 10 backend designed strictly around Domain-Driven Design, a Flutter floor app for staff, a Next.js 14 marketing front door, and a Node.js Socket.IO service for live fan-out — deployed solo on a split-tier VPS architecture.

The backend is the spine — 25+ aggregates, 95+ migrations, four API versions, and a permission model with 80+ named grants. A POS this broad changes constantly; the discipline up front is what keeps it changeable.

02architecture

A domain-driven core, with three surfaces around it.

Here is how it fits together. A Laravel 10 backend, built strictly around Domain-Driven Design, owns every rule. A Flutter app runs the floor; a Next.js site is the front door. A Node.js Socket.IO sidecar carries live notifications — all on a split-tier VPS setup I deploy myself.

tier 01
surfaces
FL
dart · iOS + Android
Flutter floor app

31 screens · Riverpod · go_router auth-guard · ESC/POS thermal printing

rolestaff client
NX
ts · next.js 14
Next.js landing

App Router · shadcn/ui · 2-step OTP register · server-side reCAPTCHA BFF route

rolefront door
REST · Sanctum
tier 02
core
LV
php · laravel 10 · ddd
Laravel backend

REST API · 25+ aggregates · 95+ migrations · v1–v4 versioning · 17 domain events

roledomain core · auth · billing
ND
node · socket.io
Node.js sidecar

~1,600 LOC · Sanctum-token auth · MySQL polling · FCM + Socket.IO fan-out

rolerealtime notifications
infraSplit-tier · two Ubuntu VPS
App VPSDedicated MySQL VPSNginxLet's Encrypt9PayFCM
03engineering

Four pieces I'd hold up as proof.

A POS touches money, people, and a live floor at once. These four are the engineering that keeps that broad surface honest.

A · backend
25+domain aggregates, strictly bounded

A POS broad enough to need real boundaries.

The backend is built on strict Domain-Driven Design — 25+ aggregates, 95+ migrations, and 17 domain events with listeners. The API is versioned v1 through v4, so an old app build in the field never breaks when the contract moves.

aggregates
25+
migrations
95+
events
17
API
v1–v4
B · access
80+named permissions · Spatie + custom

Eighty permissions, one middleware to check them.

Role-based access runs on Spatie Permission plus a custom rbac:<permission> middleware — every route declares the exact grant it needs, scoped down to the action. Staff see only what their role allows, enforced in one place.

model
Spatie
guard
rbac:*
grants
80+
C · payments
9PayHMAC-signed · short-URL checkout

A Vietnamese payment flow that survives a closed tab.

I integrated the 9Pay Vietnam SDK with HMAC request signing, and distributed checkout as short URLs — /p/{code} with a 30-minute TTL — so a bill can be opened and paid from any device, not just the one that rang it up.

signing
HMAC
link
/p/{code}
TTL
30 min
D · realtime
~1,600lines · the Socket.IO sidecar

A sidecar that keeps the floor in sync.

A Node.js Socket.IO + Express service authenticates by parsing the Sanctum id|secret token, polls MySQL for new events, and fans them out over FCM and Socket.IO — kept separate from Laravel so the API stays a clean request/response surface.

auth
Sanctum
source
MySQL poll
fan-out
FCM + WS
integrated & in production
9Pay VietnamSpatie PermissionLaravel SanctumSocket.IOFCMESC/POSshadcn/uiGoogle reCAPTCHA
04impact

The system, in numbers.

3
codebases
+ Node sidecar, all solo
25+
aggregates
domain-driven design
95+
migrations
schema surface
80+
permissions
named RBAC grants
31
screens
Flutter floor app
v1–v4
API versions
no breaking clients
17
domain events
+ listeners
2
VPS tiers
app + dedicated MySQL

Reported from the OWLX codebases — aggregate, migration, permission, and screen counts taken from the Laravel and Flutter projects. Snapshot taken May 2026.

05screens

Five surfaces from the floor app.

captured from the Flutter client
OWLX — Home
01Home
OWLX — Table plan
02Table plan
OWLX — Transactions
03Transactions
OWLX — Alerts
04Alerts
OWLX — Live map
05Live map