I Built a Real-Time QR Table Calling System in 48 Hours — Because Shouting “Boss!” Is Not a Scalable Architecture

For the past two days, I disappeared from civilization.

No meetings.
No calls.
No distractions.
Just caffeine, terminal windows, and a mission:

Build a real-time QR table calling system for Telaga Seafood Restaurant that actually works in the real world.

Not demo-world.
Not investor pitch deck world.
Real world. The place where WiFi drops, staff are busy, customers hungry, and someone at Table 7 is aggressively waving like they’re directing airport traffic.

The Moment I Decided This Needed to Exist

If you’ve ever sat in a restaurant waiting to pay the bill, you already understand the problem.

You try eye contact.
Staff busy.
You raise hand.
Still busy.
You whisper “excuse me…”
No response.

Then finally…

“BOSSSSSSSSS”

That right there is not a service workflow.
That is a survival mechanism.

Restaurants don’t have a communication system between customer and staff. They have hope. And hope is not real-time.

So I built one.

The Concept Is So Simple It’s Almost Suspicious

Each table has a QR code.
Customer scans.
A page opens.
They tap what they need.

Order. Bill. Help. General request.

That’s it.

No login. No app install. No signup. No OTP. No captcha. No “verify you are human by selecting motorcycles.”

Just tap and send.

Behind that innocent button press is where the nerdy magic happens.

What Happens After Customer Taps

Most devs would naïvely create a new record every time a button is pressed.

That’s how you end up with wallboards looking like:

Table 5 - Bill
Table 5 - Bill
Table 5 - Bill
Table 5 - Bill

Which is not helpful. That’s spam.

So I designed it smarter. Same table + same call type = update existing call instead of creating a new one.

Laravel handles that logic cleanly:

public function triggerCall(Table $table, string $type)
{
    $call = Call::updateOrCreate(
        ['table_id' => $table->id, 'type' => $type, 'status' => 'NEW'],
        ['last_called_at' => now(), 'repeat_count' => DB::raw('repeat_count + 1')]
    );

    broadcast(new CallUpdated($call))->toOthers();

    return $call;
}

Translation in human language:

“If table already called, don’t spam. Just increase urgency.”

Now the wallboard shows:

Table 5 - Bill (x4)

Staff instantly understand:
Oh. They’ve been waiting.

No training required. Brain auto-decoding.

Real-Time Means REAL Real-Time

I didn’t want fake real-time. You know the type — the system refreshes every 10 seconds and calls itself “live”.

No.

This one uses WebSockets. When a call happens, the wallboard updates instantly.

Frontend listener:

Echo.channel("calls")
    .listen("CallUpdated", (event) => {
        updateCallCard(event.call);
    });

No refresh.
No polling lag.
No staff smashing F5 like it’s 2009.

Just instant updates.

Because if customer can press button instantly, staff should see it instantly. Anything else is lying to yourself.

Stack Choice (AKA Why I Didn’t Use Trendy Stuff)

Some devs choose stacks like they’re picking sneakers.

I pick stacks like a mechanic choosing tools.

This system runs on:

Laravel + React + TypeScript + MySQL + Redis + Reverb + Nginx.

Not because it’s trendy.
Because it ships fast and behaves in production.

Laravel gives queues, events, validation, scheduling, broadcasting — basically the Swiss Army knife of backend frameworks. React handles the wallboard UI because dashboards + real-time state = React territory. Redis handles queues and realtime infrastructure because speed matters when tables are hungry.

Fancy stacks are nice.
Predictable stacks are profitable.

Built For Real Restaurant Conditions (Not Developer Fantasy Land)

I design systems assuming reality will misbehave.

WiFi will drop.
Staff will forget.
Browsers will block audio.
Servers will restart.
Timezones will mismatch.

So the system has fallback logic, auto resets, configurable timers, and timezone-aware scheduling built in from day one.

Because production is not a demo environment. Production is chaos wearing a uniform.

The Wallboard — Staff Command Center

This screen is intentionally simple. Not because I couldn’t make it fancy. Because staff don’t have time to admire UI gradients during dinner rush.

They need to glance once and understand everything.

Each call shows table number, type, urgency, repeat count, and time. Alerts play when new calls arrive. Timers visually escalate waiting requests.

No manuals.
No training videos.
No onboarding sessions.

If a system needs explanation, it’s already too complicated.

Production Debugging — The True Boss Fight

Localhost is a liar. Everything works there.

Production is the real exam hall.

During deployment I ran into issues like:

  • WebSocket service configured but not running

  • Nginx proxy blocking real-time channels

  • Yesterday’s calls showing today because timezone mismatch

  • Build permissions acting like they pay rent on the server

Each bug taught something. Each fix got documented. Because future me deserves not to suffer.

One rule I always follow:

Fix once. Document forever.

Why I Actually Enjoy Building Systems Like This

Because this kind of software doesn’t just sit pretty.

It changes workflow.

When staff stop scanning the room and start trusting the screen, their mental load drops. When customers stop shouting and start tapping, service feels smoother.

Nobody compliments the system directly.

They just say:

“Service today very fast ah.”

That sentence right there is the real KPI.

Final Thought From a Sleep-Deprived Developer

People think innovation means complicated.

In reality?

The best systems are boringly simple.

No drama.
No friction.
No confusion.

Just tap → notify → resolve.

That’s it.

If your business has a workflow problem that everyone pretends is normal, chances are it’s fixable with the right system.

That’s my specialty. Quietly fixing operational chaos with code.

Previous Article

I Built a Full Asset Management System in 2 Days — Because Spreadsheets Are Not Asset Tracking

Write a Comment

Leave a Comment

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨