PsTally Rebuilt.
A complete rebuild of PsTally on Next.js 15 — with the GTM layer engineered from the ground up. New stack, new architecture, same problem solved better.
PsTally was working. That was the problem.
Not in the way a broken system is a problem. In the way a ceiling is a problem — you can see exactly how high you can go, and you can see the space above it that you cannot reach.
The first version ran on WordPress Multisite. It was the right call at the time: fast to build, familiar, proven enough. It brought a gaming lounge its first reliable system for sessions, shifts, and reconciliation. It ended the arguments. It worked.
But WordPress did not know it was powering a SaaS product. Building a public organizer profile — the kind that could be shared on WhatsApp, indexed by Google, carry the right preview image when pasted into a message — meant fighting a system that was never designed to care about those things. Adding a tournament bracket layer meant working against the architecture instead of with it. The Lighthouse score was 56. The SEO ceiling was low. The GTM ceiling was the lowest of all.
The question was not whether to rebuild. It was what to build it into.
The ceiling showed itself in specific ways. Not as crashes or errors — as things that simply could not be built without fighting the architecture on every step.
A tournament organizer wanted a public profile page. Somewhere to point people when they shared a tournament link. A page that showed their events, their player count, their track record. A page that looked right when pasted into a WhatsApp message — the right preview image, the right title, something that carried the identity of the organizer rather than a generic WordPress URL.
On WordPress Multisite, that page was possible. Every piece of it required workarounds. The open graph image had to be generated differently per organizer. The SEO structure was fighting the theme. The route had to be hand-crafted outside the CMS. By the time it worked, it was built on a layer of compromises rather than a foundation designed to hold it.
A platform that requires workarounds for its own marketing surface is a platform that limits the product’s reach.
The same pattern repeated with performance. WordPress loads its full PHP stack on every request — even for pages that never change. A Lighthouse score of 56 is not a configuration problem. It is an architectural one. The foundation was not built to serve a marketing page at speed.
The GTM ceiling was the one that settled the decision. If the product cannot be shared elegantly, cannot be found easily, and cannot demonstrate itself without a salesperson — then the architecture is working against the business.
The rebuild was not about the technology. It was about what the technology would allow. Next.js 15 with the App Router, tRPC for the full-stack API layer, Drizzle ORM, PostgreSQL. Each decision was made for a specific reason — not because the stack was fashionable, but because the stack was right for what this product needed to become.
tRPC deserves a specific note. In a product where a schema change can break a live shift reconciliation, the difference between a type error at compile time and a runtime error during a staff handover is not academic. It is the difference between catching a problem in development and catching it when a lounge owner is waiting on a number at 10pm.
The stack was not chosen to be modern. It was chosen because the product could not afford the failure modes of the previous one.
The rebuild was also a GTM rebuild. Not a marketing strategy added after the product was built — a set of deliberate engineering decisions, made during the build, designed to make the product findable, shareable, and self-demonstrating.
The decisions were specific. They are worth naming individually.
The demo seeded with a real business — not placeholder data, not "Sample Lounge."
The interactive demo runs a fictional lounge called PsTally Demo. When someone arrives, two sessions are already active — Bay 2 running FC 26 for 43 minutes, Bay 5 running GTA Online for 22 minutes. Seven days of shift history are in the books. One shift is short by Ksh 200 from a Tuesday — the system caught it. One is over by Ksh 100. The rest balance clean.
The data is seeded nightly. Every morning the demo wakes up fresh, with yesterday’s shift just closed and two sessions already ticking. A visitor does not see a feature demonstration. They see what it looks like when the system is doing its job.
The organizer profile page as a distribution mechanism.
Every tournament organizer on the platform gets a public profile at pstally.com/org/their-name. It shows their events, their player count, their verified badge when they cross ten tournaments. The open graph image — the card that appears when the link is shared on WhatsApp or X — is generated dynamically per organizer. It carries their name, their stats, the PsTally identity.
When an organizer shares their profile, they are not sharing a link. They are sharing an artefact. The artefact travels. Every share is an impression for the platform that required no campaign.
The WhatsApp shift report engineered to the word.
At the end of every shift, the staff member sends a report to the owner’s WhatsApp. The message is not a notification that a report exists somewhere. It is the report. Revenue, cash reconciliation, discrepancy verdict, M-Pesa note — everything the owner needs, in the order she needs it, in the language that is right for reading on a phone at 9pm.
Every word in that message is a deliberate decision. “Not in till” instead of a paragraph. A checkmark when it balances. A red flag when it doesn’t. The message is a product in itself — the one the owner actually reads every night.
The lounge that had been running on the old system did not stop for the migration. Sync Gaming had active sessions on the old WordPress platform while the new system was being built on the same server.
The migration happened when the shift closed. A Python script pulled 1,368 sessions, 70 closed shifts, and 13 outstanding debt records from the MySQL database, mapped every integer ID to a UUID, preserved the relationships, and inserted the full history into PostgreSQL. Every customer who owed money, every shift reconciliation, every cashout — all of it moved intact.
The lounge owner did not experience a migration. She experienced a login at a new address, with her full history already there.
Zero hours of downtime. The next shift started on the new system without a conversation about it.
The monitoring system is often described as an operational tool. That framing understates what it does.
PS4 and PS5 consoles broadcast their presence on the local network via UDP. A lightweight Electron app installed on the lounge’s PC listens for those broadcasts, identifies each console by its MAC address — not its IP, which changes — and sends heartbeats to the dashboard every fifteen seconds. When a console turns on without a logged session, the system flags it. Not as an accusation. As a reference point.
The identification flow removes the technical problem entirely. The owner opens the Monitoring page, clicks Identify next to Bay 1, turns on only that console, and waits. The app detects it, stores the MAC address, and remembers it. The next time that console turns on — regardless of whether the router assigned it a new IP — the system knows which bay it is.
An owner who can see her consoles on a live dashboard trusts the system with her money. That trust is the GTM outcome — not a feature of it.
The Electron app is distributed as a single installer from the platform itself. The owner downloads it, enters the API key shown on her dashboard, and the app disappears to the system tray. It restarts automatically when the PC reboots. It requires no maintenance. The owner never thinks about it again — but she sees its output every day.
Lighthouse went from 56 to 91. The difference is not cosmetic. A gaming lounge owner checking her dashboard on a 4G connection at midnight is not using a fast device on a fast connection. The 35-point improvement is the difference between a dashboard that loads before she loses patience and one that doesn’t.
pstally.com is now the canonical address. The marketing page, the staff login, the owner dashboard, the organizer profiles, the tournament brackets, the monitoring page — all on one domain, all on one platform. The old WordPress site was retired the day the shift migrated.
The rebuild did not change what PsTally does. It changed what PsTally can become.
The clarity it delivers to a lounge owner is the same clarity the first version delivered. A session tracked. A shift reconciled. A discrepancy named before it disappears into argument. That has not changed.
What changed is the surface beneath it. The one a visitor lands on and decides whether to read further. The one a tournament organizer shares and carries her identity. The one that loads before an impatient owner gives up at midnight. The architecture that used to limit those surfaces is gone. What is there now was designed for them.
The platform no longer apologises for what it cannot do. It was rebuilt for what comes next.
This is a continuation of
← PsTally — the original build