Skip to content

Back to projects

Project at Kobler

Live diagnostic for the Appolo workshop

Web app for an in-person business diagnostic workshop: the audience answers on WhatsApp, a projected screen shows the answers live, and the presenter moves through the questions from a PIN-protected panel.

Client
Kobler y Asociados
Context
Individual project
Period
October 2026 – present
Technologies
  • React
  • TypeScript
  • Vite
  • Tailwind CSS
  • React Router
  • Supabase
  • Vercel
  • Vitest
  • Supabase Realtime
  • n8n
  • WhatsApp

Key points

  1. A screen designed to be projected: a QR code to join on WhatsApp, live bars for the active question, each section's average for a few seconds when it closes and, at the end, the room's results: average per section, company stage, top bottlenecks, the most common way of managing schedules, and a word cloud.

  2. Host panel for laptop or phone: it opens with a PIN, commands are sent one at a time (a double click on “Next” sends only one), and sensitive ones ask for explicit confirmation.

  3. Live sync: every Supabase Realtime notice triggers a query for the full state, with at most two queries per second and a fallback poll every 5 seconds (every 3 if the channel drops).

  4. A demo mode that loops through a full simulated event with made-up data and goes through the same sync logic, to review the views and the design without a real audience.

  5. While it is open, the screen keeps the computer from going to sleep and hides the cursor after 3 seconds without movement.

Problem

At the in-person Appolo workshop, attendees answer a 20-question business diagnostic on WhatsApp, split into three sections (vision and leadership, operational order, and automation), plus a closing open question. The room needed to see its answers projected live, and the presenter needed to run the questionnaire from a laptop or phone without exposing the backend keys to the browser.

Solution

The web app has two views. The live screen is read-only: it shows the QR code to join on WhatsApp, the active question with its bars, each section's average when the section closes, a word cloud for the open question, and the room's results. The host panel, protected by a PIN, is used to advance and resend questions, send the results, close the session and open a new one. The app reads the state through a Supabase RPC, listens for notices over Supabase Realtime, and sends the host's commands to n8n through serverless functions on Vercel.

Technical decisions

  • The browser never sees the Supabase secret key, the session's host key or the n8n URL: the panel talks to three serverless functions of its own, which check the PIN and read the current session from Supabase on every request instead of keeping it in environment variables.
  • The PIN is compared in constant time, on its hash so the duration does not depend on its length either, and each failed attempt takes about 600 ms.
  • The screen only receives anonymous aggregates: never attendees' names or phone numbers.
  • Each section's closing is worked out only from the RPC response and the server's clock, so the screen shows it correctly even after a reload.

Failure handling

  • If the network fails, the screen keeps the last thing it showed, displays a discreet “Reconnecting…” notice and catches up on its own when the connection returns. A query that takes longer than 8 seconds is cancelled and the next one retries it.
  • If a view crashes, a “Something went wrong” message appears and the page reloads itself after 10 seconds.
  • If two people have the panel open, only one new session is created, and commands from the panel still looking at the old one are not applied: the server replies with the current session, and the panel warns and switches to it.
  • Retrying repeats the last command exactly; when advancing, the command carries the question it starts from, so a retry never skips a question.

My role

I wrote the code in this repository: both views in React and TypeScript, the host's serverless functions, the Supabase sync, the demo mode, and the tests with Vitest and Testing Library. The event backend (the Supabase database and the n8n flows behind the WhatsApp bot) lives outside the repository; the web app only reads its state and sends it the host's commands.

Results

  • The presenter runs the event from a laptop or phone, and the room sees its aggregated answers live, with no names or phone numbers.

Code kept private due to client confidentiality; screenshots, architecture, and a demo available upon request.