← Back to Throw Joshua Under The Bus
Table of Contents

Core Gameplay

4 features

The main throw-under-the-bus mechanic and counter

F1

Counter Display

3 requirements

The main counter shows how many times Joshua has been thrown under the bus.

Requirements

F1.R1 Counter element visible on load

The counter element is visible when the page first loads.

F1.R2 Counter shows numeric value

The counter displays a numeric value fetched from the server.

F1.R3 Value matches API response

The displayed value matches the count returned by the API.

F2

Counter Increment (Throw)

3 requirements

Clicking the Joshua doll throws him under the bus, incrementing the counter.

Requirements

F2.R1 Click sends POST /api/increment

Clicking the doll sends a POST request to /api/increment.

F2.R2 Display updates after click

The counter display updates to reflect the new count after the throw.

F2.R3 Multiple clicks increment correctly

Sequential throws each increment the counter by one.

F3

Counter Persistence

4 requirements

The counter value is persisted to disk so it survives server restarts.

Requirements

F3.R1 Written to counter.json on increment

Each increment writes the new value to counter.json.

F3.R2 File created on init if missing

If counter.json doesn't exist, it's created with count 0.

F3.R3 Existing file not overwritten on init

Starting the server does not reset an existing counter.

F3.R4 Handles edge cases

Write handles zero, negative, and large numbers correctly.

F8

Bus Animation

2 requirements

A bus SVG animates across the screen when Joshua is thrown.

Requirements

F8.R1 Bus animates on throw

The bus SVG drives across the screen when the user clicks to throw.

F8.R2 Animation completes and resets

The bus animation finishes and the bus returns to its hidden position.

Defense & Recovery

2 features

Crossing guard and ambulance mechanics

F20

Crossing Guard

7 requirements

Crossing guards stop the bus from hitting Joshua, absorbing throws.

Requirements

F20.R1 Guard button visible

The crossing guard button is visible on the page.

F20.R2 Click sends POST /api/guard

Clicking the guard button sends a POST to /api/guard.

F20.R3 Guard count displayed

Active crossing guards are shown as icons.

F20.R4 Guard animation on click

The guard button animates when clicked.

F20.R5 Guards absorb throws

Throwing with active guards consumes a guard instead of incrementing.

F20.R6 Guards decay over time

Guards decay by 1 every 10 seconds on the server.

F20.R7 Guard maximum is 10

The maximum number of active guards is 10.

F21

Ambulance

6 requirements

The ambulance picks up Joshua, decrementing the counter.

Requirements

F21.R1 Ambulance button visible

The ambulance button is visible on the page.

F21.R2 Click sends POST /api/ambulance

Clicking the ambulance sends a POST to /api/ambulance.

F21.R3 Ambulance decrements counter

The ambulance reduces the counter by 1, minimum 0.

F21.R4 Ambulance animation on click

The ambulance button animates when clicked.

F21.R5 3-second cooldown

The ambulance has a 3-second cooldown between uses.

F21.R6 Cooldown timer displayed

A cooldown timer is shown near the ambulance button.

Real-time & Sync

3 features

Multi-user synchronization and live updates

F4

Multi-user Sync

2 requirements

Multiple users see the same counter value in real time.

Requirements

F4.R1 Polls every 5 seconds

The client polls GET /api/counter periodically.

F4.R2 Updates on external change

Display updates when another user changes the counter.

F25

WebSocket Sync

3 requirements

WebSocket provides instant updates without polling.

Requirements

F25.R1 WebSocket server attached

A WebSocket server is attached to the HTTP server.

F25.R2 State broadcast on mutation

Every state change is broadcast to all connected WebSocket clients.

F25.R3 Initial state on connect

New WebSocket clients receive the current state immediately.

F22

Current Users Display

4 requirements

Shows how many users are currently active.

Requirements

F22.R1 User count displayed

The current user count is shown on the page.

F22.R2 Count updates on poll

The user count updates with each API poll.

F22.R3 IP tracking with 15s window

Server tracks active users by IP with a 15-second window.

F22.R4 Location grouping

GET /api/users returns users grouped by location.

UI & UX

8 features

User interface polish and interactions

F5

Double-click Protection

2 requirements

Prevents rapid clicking from sending multiple requests.

Requirements

F5.R1 Lock prevents concurrent submits

The isUpdating lock prevents concurrent API calls.

F5.R2 Rapid clicking sends one request

Rapid clicking only results in one increment.

F6

Number Formatting

1 requirement

Large numbers are formatted with locale-specific separators.

Requirements

F6.R1 toLocaleString formatting

The counter uses toLocaleString for thousands separators.

F7

Joshua Doll SVG

2 requirements

The clickable Joshua doll character.

Requirements

F7.R1 SVG visible with dimensions

The Joshua SVG is visible with nonzero dimensions.

F7.R2 Accessible SVG

The SVG has role="img" and aria-label attributes.

F9

Counter Bump Animation

1 requirement

The counter bumps/pulses when the value changes.

Requirements

F9.R1 Bump animation on increment

The .bump class is applied to the counter after increment.

F10

Toast Notifications

4 requirements

Non-blocking toast messages for errors and feedback.

Requirements

F10.R1 Toast visible on error

The toast element becomes visible when an error occurs.

F10.R2 Descriptive error message

Toast shows a helpful error message.

F10.R3 Auto-dismiss after 4s

The toast automatically hides after 4 seconds.

F10.R4 Error styling class

Error toasts have the toast-error CSS class.

F11

Error Recovery UI

2 requirements

Graceful handling when the server is unreachable.

Requirements

F11.R1 Counter shows Error

The counter displays "Error" when the API is unreachable.

F11.R2 Error message appended

An error message div is appended to the container.

F12

Responsive Design

2 requirements

The layout adapts to different screen sizes.

Requirements

F12.R1 600px breakpoint

Layout adapts at the 600px breakpoint.

F12.R2 Smaller doll on mobile

The Joshua doll is smaller on mobile viewports.

F13

Accessibility

5 requirements

The app is accessible to screen readers and keyboard users.

Requirements

F13.R1 Throw button has aria-label

The throw button has an aria-label attribute.

F13.R2 SVG accessible

SVGs have role="img" and aria-label.

F13.R3 Toast aria-live

The toast has aria-live="polite".

F13.R4 Focus-visible ring

Buttons have a visible focus ring on keyboard navigation.

F13.R5 Keyboard activation

The throw button is activatable via Enter or Space.

Server & API

10 features

Backend API endpoints and server functionality

F14

Homepage HTML

2 requirements

The server serves the main page at the root URL.

Requirements

F14.R1 GET / returns 200 HTML

GET / returns 200 with HTML content.

F14.R2 Contains key elements

The HTML contains #counter-value, #throw-button, and the title.

F15

GET /api/counter

4 requirements

Returns the current counter state.

Requirements

F15.R1 Returns 200 JSON

Returns 200 with application/json content type.

F15.R2 Has count and guards

Response body includes count and guards fields.

F15.R3 count is non-negative integer

The count field is a non-negative integer.

F15.R4 Reflects increments

The count reflects previous increments.

F16

POST /api/increment

5 requirements

Increments the counter (throws Joshua under the bus).

Requirements

F16.R1 Returns 200 JSON

Returns 200 with application/json content type.

F16.R2 Has count and guards

Response body includes count and guards fields.

F16.R3 Count incremented by 1

Each call increments the count by exactly 1.

F16.R4 Persists to disk

The increment is persisted to counter.json.

F16.R5 No bodyPart required

No bodyPart field is needed — single target.

F17

Counter File Recovery

3 requirements

Graceful handling of corrupt or missing counter files.

Requirements

F17.R1 Returns 0 when missing

Returns count 0 when counter.json is missing.

F17.R2 Recreates file

Recreates the counter file when missing.

F17.R3 Handles invalid JSON

Returns count 0 for invalid JSON content.

F18

CORS

2 requirements

Cross-Origin Resource Sharing headers.

Requirements

F18.R1 CORS on GET

Access-Control-Allow-Origin: * header on GET requests.

F18.R2 CORS on POST

CORS headers present on POST requests.

F19

Static File Serving

3 requirements

Static assets served from the public directory.

Requirements

F19.R1 CSS and JS load

CSS and JS files load successfully.

F19.R2 Favicon exists

A favicon link element exists in the HTML.

F19.R3 404 for missing assets

Nonexistent assets return 404.

F23

Rate Limiting

2 requirements

API rate limiting to prevent abuse.

Requirements

F23.R1 Rate limiter on /api/*

Rate limiter middleware is applied to all /api/* routes.

F23.R2 429 when exceeded

Returns 429 when the rate limit is exceeded.

F24

Server-Side Ambulance Cooldown

3 requirements

Server-enforced cooldown for the ambulance action.

Requirements

F24.R1 Cooldown tracked per IP

Server tracks ambulance cooldown per IP address.

F24.R2 429 when on cooldown

Returns 429 when the ambulance is on cooldown.

F24.R3 First succeeds, second rejected

First ambulance call succeeds, immediate second is rejected.

F26

Atomic File Writes

2 requirements

Counter state is written atomically to prevent corruption.

Requirements

F26.R1 tmp + rename pattern

writeState uses a temporary file and rename for atomicity.

F26.R2 No leftover .tmp file

No .tmp file remains after a successful write.

F31

Security Headers

2 requirements

Security headers via helmet middleware.

Requirements

F31.R1 Security headers on responses

Security headers middleware is applied to all responses.

F31.R2 CSP configured

Content Security Policy allows only same-origin and inline resources.

Infrastructure

6 features

PWA, versioning, admin, and automation

F27

Progressive Web App (PWA)

4 requirements

The app is installable as a PWA.

Requirements

F27.R1 Manifest at /manifest.json

Web app manifest is served at /manifest.json.

F27.R2 Required PWA fields

Manifest includes name, icons, start_url, display.

F27.R3 Service worker registered

A service worker is registered on page load.

F27.R4 PWA meta tags

HTML includes theme-color and apple-touch-icon meta tags.

F28

Versioning & Navigation

3 requirements

Version display and navigation between pages.

Requirements

F28.R1 Version displayed

The version number is displayed on the page.

F28.R2 Links to releases

The version number links to the /releases/ page.

F28.R3 Version.json endpoint

version.json provides the current version.

F29

User Feature Requests

3 requirements

Users can submit and view feature requests.

Requirements

F29.R1 Form and history

Feature requests page has a form and request history.

F29.R2 Server-side persistence

Requests are persisted server-side and shared across users.

F29.R3 Implemented badge

Implemented requests show the release version.

F30

Admin Panel

4 requirements

Admin panel for counter management and moderation.

Requirements

F30.R1 Authentication

Admin authentication with login and logout.

F30.R2 Counter management

Admin can reset and set the counter value.

F30.R3 Action toggle

Admin can disable/enable throw, guard, and ambulance.

F30.R4 Request moderation

Admin can approve or deny feature requests.

F32

CI/CD Pipeline

1 requirement

Automated testing and deployment pipeline.

Requirements

F32.R1 Automated pipeline

CI/CD runs test, deploy, and verify jobs automatically.

F33

Automated Feature Implementation

3 requirements

Approved feature requests are automatically implemented by Claude Code.

Requirements

F33.R1 Polling script

A polling script detects approved feature requests.

F33.R2 Claude Code headless

Claude Code is launched headlessly to implement features.

F33.R3 Mark-implemented workflow

A GitHub Action notifies the production server when done.