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:
48
PLAN.md
48
PLAN.md
@@ -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.
|
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)
|
### Phase 1 — Framework skeleton (dev mode from day one)
|
||||||
|
|
||||||
- `framework/php` Symfony bundle with `Publisher`, `HealthController`, `SessionAuthenticator`.
|
- `framework/php` Symfony bundle with `Publisher`, `HealthController`, `SessionAuthenticator`.
|
||||||
|
|||||||
Reference in New Issue
Block a user