Expand Phase 0 with a concrete spike spec

Adds the spike's layout, flow, hardcoded values, and done criteria so
implementation has a clear target. No code yet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-02 00:03:15 +02:00
parent 8faaf764eb
commit 0b394510bc

48
PLAN.md
View File

@@ -512,6 +512,54 @@ Phased, each phase ends with something runnable.
Hardcoded everything. Qt window spawns FrankenPHP, hits `GET /api/ping`, opens an SSE stream, prints incoming events to a `Text` element. Goal: prove the transport on Linux. ~1 day.
#### Concrete spec
Lives in `spike/`. Removed when Phase 1's framework skeleton supersedes it. **No Symfony yet** — bare PHP behind FrankenPHP, the smallest thing that exercises both transport channels.
Layout:
```text
spike/
README.md # how to run, what it proves, expected output
run.sh # builds (if needed) and runs FrankenPHP + the Qt host
Caddyfile # binds 127.0.0.1:8080, enables Mercure, routes index.php
.env.local # MERCURE_PUBLISHER_JWT_KEY (dev-only static key)
.gitignore # bin/, build/
bin/frankenphp # downloaded static binary, gitignored
php/
index.php # GET /api/ping → returns pong, publishes to Mercure
qt/
CMakeLists.txt # minimal Qt 6 + QML project
main.cpp # QGuiApplication + QQmlApplicationEngine + spawns frankenphp child
Main.qml # window: status indicator, Ping button, event log
Mercure.qml # tiny SSE client (text/event-stream parser via QNetworkReply)
```
Flow:
1. `./run.sh` builds the Qt binary (if not built) and runs it.
2. Qt host starts and spawns `bin/frankenphp run --config Caddyfile` as a child process.
3. Once `GET /api/ping` succeeds, QML opens an SSE connection to `/.well-known/mercure?topic=app://ping`.
4. Clicking the "Ping" button triggers `GET /api/ping`. The handler returns `{ "pong": true, "now": ... }` and publishes the same payload to Mercure.
5. The event arrives on the SSE stream and is appended to the visible log.
Hardcoded for the spike:
- Backend URL: `http://127.0.0.1:8080`.
- Mercure topic: `app://ping`.
- Mercure JWT: dev-only static key in `.env.local`.
- No auth on `/api/ping`.
- FrankenPHP static binary version pinned in `run.sh`.
Done criteria:
- Click "Ping" → response text updates **and** an event line appears in the log within ~50 ms.
- Killing `bin/frankenphp` externally → Qt host visibly shows the connection dropping.
- Re-running `./run.sh` → everything reconnects.
- A brief writeup in `spike/README.md` of what the spike proved and any surprises.
Out of scope (lands in Phase 1+): optimistic updates, `Last-Event-ID` resume, per-session secret, single-instance lock, packaging, Symfony.
### Phase 1 — Framework skeleton (dev mode from day one)
- `framework/php` Symfony bundle with `Publisher`, `HealthController`, `SessionAuthenticator`.