pinball.cv

Runbook

This runbook starts the cloud API, dashboard web views, and mobile web view for manual testing.

Ports

For the browser demo, open these TCP ports on the Vultr firewall:

  • 80 - redirects to HTTPS
  • 443 - HTTPS web views using the existing Let's Encrypt certificate

Keep these ports private/local only:

  • 3000 - Fastify cloud API, proxied publicly at https://www.pinball.cv/api/
  • 8081 - Expo mobile web view, proxied publicly at https://www.pinball.cv/mobile/
  • 3306 - MySQL

Start Services

Use two terminal sessions from the repo root. The normal nginx site serves the landing page and dashboard HTML on port 443.

Terminal 1:

npm run api:start

Terminal 2:

npm run mobile:web

Open Web Views

Dashboard URLs under /apps/web/ use HTTP Basic Auth:

Username: admin
Password: apple29

Each dashboard has a Cloud API base URL field. It should default to:

https://www.pinball.cv/api

If it shows localhost from your browser, replace it manually with https://www.pinball.cv/api.

The runbook page also includes an embedded Cloud API Test Console with preloaded demo values. Use that first when you want to exercise the API without opening the standalone Admin API Lab.

Click an endpoint name in the embedded console to load its request path and payload into the Selected API Payload panel. Click Execute selected API call to run the loaded request. Generated claim, device, user, and score IDs are shown in the console state readout.

Test API Health

  1. Open the runbook page.
  2. Scroll to Cloud API Test Console.
  3. Confirm API base URL is https://www.pinball.cv/api.
  4. Click GET /health.
  5. Expected response:
{
  "ok": true,
  "service": "pinballcv-api"
}

Test Device Boot and QR Claim

Use either the Operator dashboard or the Cloud API Test Console embedded on the runbook page.

  1. Open the Operator dashboard.
  2. Confirm Cloud API base URL.
  3. Leave the test MAC address as b8:27:eb:12:34:56, or enter another valid MAC.
  4. Click Boot test Pi.
  5. Expected: the Claim token field fills in.
  6. Click Claim device.
  7. Expected: Selected device ID fills in and the fleet list shows a device.

This simulates an unassigned Pi booting, receiving a QR claim token, and being claimed by the operator profile.

Test Operator Fleet

  1. Open the Operator dashboard.
  2. Click Load fleet.
  3. Click a device in the Fleet list.
  4. Expected: Selected device ID updates to that device.

Test Custom Playfield Message

  1. Open the Operator dashboard.
  2. Select a device.
  3. Edit Custom playfield message.
  4. Click Save message.
  5. Click Load fleet.
  6. Expected: the saved message appears in the last API response and persists in the database.

Test Score Submission

  1. Open the Operator dashboard.
  2. Select a claimed device.
  3. Click Submit demo score.
  4. Expected: last API response includes scoreId, localRank, and globalRank.

Test Local Leaderboard Button

  1. Open the Operator dashboard.
  2. Select a claimed device.
  3. Click Local leaderboard.
  4. Expected: leaderboard table shows scores submitted from that selected device.

Test Global Leaderboard Button

  1. Open the Operator dashboard.
  2. Click Global leaderboard.
  3. Expected: leaderboard table shows scores across all devices.

Test Admin Users and Devices

  1. Open the Admin dashboard.
  2. Click Load users.
  3. Expected: operator users appear in the Users list.
  4. Click a user.
  5. Expected: that user's devices appear in the Devices list.
  6. Click a device to select it.

Test Admin Subscription Override

  1. Open the Admin dashboard.
  2. Click Load devices.
  3. Select a device.
  4. Click Set Pro.
  5. Expected: selected device tier changes to pro.
  6. Click Set free.
  7. Expected: selected device tier changes back to free.

Test Admin Username Moderation

  1. Open the Admin dashboard.
  2. Leave Banned Stern username as luna_spin, or enter another username.
  3. Click Ban username.
  4. Open the Operator dashboard.
  5. Select a device and click Submit demo score.
  6. Expected: score submission for the banned username fails.
  7. Return to the Admin dashboard and click Unban username to remove the test ban.

Test Every API From Runbook Page

  1. Open the runbook page.
  2. Scroll to Cloud API Test Console.
  3. Click Run full demo flow.
  4. Expected: the response log shows successful calls for health, device boot, claim, heartbeat, score submission, local leaderboard, global leaderboard, operator fleet, users, user devices, subscription overrides, ban, and unban.
  5. Click New demo identity before re-running the full flow if you want a fresh unclaimed device and operator email.

Test Admin Delete APIs

  1. Open the runbook page.
  2. Scroll to Cloud API Test Console.
  3. Click New demo identity.
  4. Click Run full demo flow to create a demo user and device.
  5. Click DELETE device.
  6. Expected: the response log shows deleted: true for the selected device.
  7. Click New demo identity, then Run full demo flow again.
  8. Click DELETE user.
  9. Expected: the response log shows deleted: true and releasedDevices for the selected demo user.

Test Mobile App Web View

  1. Open the Mobile app web view.
  2. Confirm Cloud API base URL is https://www.pinball.cv/api; edit it if needed.
  3. On the Claim tab, click Boot test Pi.
  4. Click Claim device.
  5. Go to Fleet and click Refresh fleet.
  6. Go to Scores.
  7. Click Submit demo score.
  8. Click Local leaderboard.
  9. Click Global leaderboard.

On a real phone running the Expo app, use the camera scanner instead of pasting the claim token. In web view, use the token field because browser camera support for Expo Camera is limited.

Cloud API Test Console

Select an endpoint, review or edit the JSON request, then execute it against the live cloud API.

Idle
How to run endpoints
1. Click an endpoint name to load its request.
2. Edit the JSON in Selected API Payload if needed.
3. Click Execute selected API call.
Setup: Run full demo flow first when an endpoint needs a device, user, or score ID.

Selected API Payload

Request / Response Log

Click "Run full demo flow" or any individual endpoint button.