Search by

kinetis / pingpong

aln-1

A runnable ping-pong demo application showcasing Kinetis: MySQL, migrations, the query builder, Redis-backed cache and queue, events, a cron-driven command, and real-time updates over kinetis/broadcasting, including a private channel.

Package info

github.com/kinetis-dev/pingpong

Type:project

pkg:composer/kinetis/pingpong

Statistics

Installs: 15

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.3.3 2026-09-13 21:41 UTC

This package is auto-updated.

Last update: 2026-09-13 21:59:47 UTC


README

Kinetis

kinetis/pingpong
A runnable ping-pong demo application for Kinetis

Packagist Version Packagist Downloads PHP Version License CI

Part of Kinetis, a non-blocking PHP framework for API-first applications, developed in the kinetis-dev/kinetis monorepo.

A small, working application showing most of Kinetis at once: MySQL + kinetis/migrations + kinetis/query-builder, Redis-backed kinetis/queue, Kinetis\Events, a Kinetis\Console command run on a schedule, a kinetis/mcp tool an AI agent can call for the per-scenario ping breakdown, and real-time browser updates over Soketi — behind a monochrome-amber, old-CRT-styled dashboard rendered with kinetis/views-php.

A ping can be answered three ways: POST /pong/direct replies in the same request; POST /pong/queued replies a few seconds later, from a separate queue-worker process; a scheduled command replies entirely on its own, every few seconds, with no request involved at all. The dashboard watches all three happen live, over a WebSocket.

Running it

docker run --rm -v "$PWD":/app -w /app composer:2 \
    create-project --no-install kinetis/pingpong my-app
cd my-app
cp .env.example .env
docker compose up --build

Then open http://localhost:8080. Docker is the only thing you need — the containers install the dependencies and run the app, so no PHP or Composer has to exist on the host. (--no-install is what keeps it that way: it fetches the project without resolving dependencies, which docker compose up then does inside the containers it will run them in.)

The project is yours from that point on. docker-compose.yml mounts it at /app and needs nothing outside it; MySQL, Redis and Soketi come up alongside it as services of the same stack.

app runs under a genuine FrankenPHP persistent worker — Kinetis's primary optimization target (persistent connection pooling, warm route caching). One consequence worth knowing before you start editing code: a FrankenPHP worker loads public/index.php (including all route/command/tool discovery) exactly once at boot, so a code change is invisible until the app container restarts — there's no PHP-FPM-style "every request reboots the script" hot reload here. See the CLI docs for the full discovery/hot-reload tradeoff. Looking for that kind of instant-feedback loop instead? See kinetis/skeleton, a much smaller demo running on nginx + PHP-FPM for exactly that reason.

Using this as a starting point

Start editing what you just created — every piece (bootstrap.php, the migration, the repository, the job, the scheduled command, the events, the broadcaster and its private-channel authorizer, the MCP tool controller, resources/views/dashboard.php) is a small, plain file meant to be read end to end. Kinetis deliberately reuses existing template engines instead of inventing another language. PingController::index() injects the engine-neutral Views service, while bootstrap.php selects the small pure-PHP adapter. The controller would be unchanged if the application selected Latte or Twig instead. The logo (public/logo.svg), stylesheet (public/dashboard.css), and browser script (public/dashboard.js) are plain static files served directly, not template data — only the Soketi connection details are actually dynamic, passed to dashboard.js through a type="application/json" data island rather than any inline script of the template's own.

Working on this package itself

This package is developed in the kinetis-dev/kinetis monorepo and published from it; kinetis-dev/pingpong is the split mirror the commands above install from. Inside the monorepo, composer.json still carries the path repositories that resolve every kinetis/* sibling from its own checkout, so the stack needs the override that mounts them:

docker compose -f docker-compose.yml -f docker-compose.monorepo.yml up --build

Container paths are /app either way — that override adds mounts and changes nothing else.

Learn by building the same thing yourself

The Tutorial builds this exact application from an empty directory, one working piece at a time — useful for understanding why each file looks the way it does, not just what it does.

License

MIT — see LICENSE.