docs: rewrite README + add comprehensive docs/
README is now tight and link-heavy: 60-second tour, then deep links into docs/. The wall of detail moved out. docs/ covers the framework end-to-end: - getting-started.md — prerequisites by distro (Tumbleweed, Fedora, Debian/Ubuntu, Arch), full first-run walkthrough, troubleshooting. - architecture.md — process pair, transport, dev/bundled mode. - update-semantics.md — state machine + optimistic mutations + key round-tripping. - reactive-models.md — ReactiveListModel, ReactiveObject, Mercure dual-publish. - makers.md — make:bridge:resource/command/window. - dev-workflow.md — hot reload (PHP + QML), dev console, editor configs, bridge:doctor, snapshot/integration test loops, perfsmoke. - bundled-mode.md — supervisor, per-session secret rotation, first-launch migrations, auto-update wiring. - packaging-linux.md — make appimage, build-appimage.sh CLI, AppImageUpdate sidecar, perfsmoke budgets, release CI, bundle-size breakdown. - qml-api.md / php-api.md — exhaustive symbol reference with all Q_PROPERTY/Q_INVOKABLE/signals + every public PHP service / attribute / command. - configuration.md — every env var (host, Symfony, dev script, packaging script, perfsmoke), every CLI flag (php-qml-init, build-appimage.sh), make targets, default ports/paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
115
README.md
115
README.md
@@ -1,57 +1,36 @@
|
||||
# php-qml
|
||||
|
||||
A framework for building native desktop applications with a Symfony / FrankenPHP backend and a Qt/QML frontend, packaged as a single distributable per OS.
|
||||
A framework for native desktop applications with a **Symfony / FrankenPHP** backend and a **Qt / QML** frontend, packaged as a single distributable per OS.
|
||||
|
||||
## Status
|
||||
> **Status:** Phase 5 / pre-v0.1.0. Phases 0–4a are merged (working framework, real POC, Linux AppImage, auto-update, release CI). macOS and Windows packaging are deferred to 4b/4c. See [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
**Phase 5 / pre-v0.1.0.** Phases 0–4a are merged: working framework skeleton, reactive models, the headline `make:bridge:*` makers, a real POC (`examples/todo`), Linux AppImage packaging, AppImageUpdate auto-update, performance smoke harness, release CI on `v*` tags. Full design lives in [PLAN.md](PLAN.md) and the per-version log in [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
What's not done yet: macOS and Windows packaging (Phase 4b/4c).
|
||||
---
|
||||
|
||||
## What it is
|
||||
|
||||
php-qml lets a PHP developer write a desktop application using ordinary Symfony on the backend and ordinary QML on the frontend. The two halves run as a process pair inside one bundled binary:
|
||||
php-qml lets a PHP developer write a desktop app using ordinary Symfony on the backend and ordinary QML on the frontend. The two halves run as a **process pair** inside one bundled binary:
|
||||
|
||||
- A Qt/QML host process owns the window, input, and rendering.
|
||||
- A bundled FrankenPHP child runs a Symfony application in worker mode.
|
||||
- A Qt/QML host owns the window, input, and rendering.
|
||||
- A bundled FrankenPHP child runs a Symfony app in worker mode.
|
||||
- They communicate over a local socket — HTTP for commands and queries, Mercure SSE for state push.
|
||||
|
||||
The framework provides the lifecycle, transport, reactive models, and scaffolding so application code stays idiomatic on both sides.
|
||||
It is **not** a PHP↔Qt language binding — the languages run in separate processes; the bridge is a wire protocol, not an FFI layer. That deliberately avoids the failure mode that left php-gtk and php-qt unmaintained.
|
||||
|
||||
## What it is not
|
||||
|
||||
Not a PHP↔Qt language binding. It does not embed PHP into a Qt event loop and it does not generate Qt classes from PHP. The two languages run in separate processes; the bridge is a wire protocol, not an FFI layer.
|
||||
|
||||
If you've watched php-gtk and php-qt go quiet, that is the failure mode this project deliberately avoids — the framework owns the boring parts (lifecycle, transport, conventions) so it doesn't depend on a single maintainer keeping a language binding alive.
|
||||
|
||||
## Tech stack
|
||||
|
||||
- **Backend:** PHP 8.4+, Symfony 8, Doctrine ORM 3, FrankenPHP (worker mode), Mercure
|
||||
- **Frontend:** Qt 6.5+, QML, C++ plugin where required
|
||||
- **Build:** CMake, Composer
|
||||
- **CI:** Gitea Actions, Gitea Releases
|
||||
- **Packaging:** Linux AppImage today; macOS (`.app` + `.dmg`) and Windows (NSIS / MSIX) on the roadmap
|
||||
|
||||
## Quick start
|
||||
|
||||
Prerequisites: Qt 6.5+ dev packages, CMake, gcc-c++, PHP 8.4+, Composer, [FrankenPHP](https://frankenphp.dev/) on PATH.
|
||||
## 60-second tour
|
||||
|
||||
```bash
|
||||
git clone https://gitea.example/<you>/php-qml
|
||||
cd php-qml
|
||||
git clone https://gitea.example/<you>/php-qml && cd php-qml
|
||||
|
||||
# 1) Scaffold a fresh app (auto-detects this checkout as the framework)
|
||||
# Scaffold a fresh app
|
||||
./bin/php-qml-init my-app
|
||||
|
||||
# 2) Boot it
|
||||
# Run it
|
||||
cd my-app
|
||||
make doctor # bridge:doctor — readiness check
|
||||
make dev # FrankenPHP --watch + Qt host
|
||||
make doctor # readiness check
|
||||
make dev # FrankenPHP --watch + Qt host
|
||||
```
|
||||
|
||||
`make dev` opens the Qt window, connection state flips to **Online**, and a Ping button round-trips through `/api/ping` and back via Mercure SSE.
|
||||
|
||||
Add a reactive resource — entity + REST controller + QML snippet — with one maker:
|
||||
Add a reactive resource (entity + REST controller + QML snippet) with one maker:
|
||||
|
||||
```bash
|
||||
cd my-app/symfony
|
||||
@@ -59,68 +38,56 @@ bin/console make:bridge:resource Todo
|
||||
bin/console make:migration && bin/console doctrine:migrations:migrate -n
|
||||
```
|
||||
|
||||
The QML side gets a `TodoList.qml` whose `ReactiveListModel` does an initial GET, subscribes to `app://model/todo`, and applies diffs as Mercure pushes them. There is no handwritten cross-side glue.
|
||||
`make dev` opens the Qt window, connection state flips to **Online**, and the generated `TodoList.qml` shows a list whose `ReactiveListModel` is auto-subscribed to `app://model/todo` over Mercure. There is no handwritten cross-side glue.
|
||||
|
||||
For a non-trivial example with a multi-window test, crash-recovery test, and AppImage packaging, see [`examples/todo/`](examples/todo/README.md).
|
||||
For a non-trivial app with a multi-window test, crash-recovery test, and AppImage packaging, see [`examples/todo/`](examples/todo/README.md).
|
||||
|
||||
## Packaging (Linux)
|
||||
## Documentation
|
||||
|
||||
```bash
|
||||
cd examples/todo
|
||||
FRANKENPHP=/path/to/frankenphp make appimage
|
||||
./build/Todo-x86_64.AppImage
|
||||
```
|
||||
The full developer documentation lives under [`docs/`](docs/README.md):
|
||||
|
||||
`make appimage` bundles Qt, the Symfony app, the FrankenPHP binary, and the AppImageUpdate sidecar into one `~150 MB` AppImage that auto-detects bundled mode (no `BRIDGE_URL` set), spawns its own FrankenPHP child, generates a per-session bearer token, and runs first-launch migrations. CI builds this on every `v*` tag and uploads to Gitea Releases with a `latest.json` appcast and zsync metadata for in-place updates. See [PLAN.md §13 Phase 4a](PLAN.md#phase-4a) for the full pipeline.
|
||||
- **[Getting started](docs/getting-started.md)** — prerequisites by distro, first project, troubleshooting.
|
||||
- **[Architecture](docs/architecture.md)** — process pair, transport, dev vs bundled mode.
|
||||
- **[Update semantics](docs/update-semantics.md)** — connection state machine, optimistic mutations, idempotency.
|
||||
- **[Reactive models](docs/reactive-models.md)** — `ReactiveListModel`, `ReactiveObject`, Mercure dual-publish.
|
||||
- **[Makers](docs/makers.md)** — `make:bridge:resource` / `command` / `window`.
|
||||
- **[Dev workflow](docs/dev-workflow.md)** — hot reload, dev console, editor setup, `bridge:doctor`.
|
||||
- **[Bundled mode](docs/bundled-mode.md)** — supervisor, per-session secret rotation, first-launch migrations.
|
||||
- **[Linux packaging](docs/packaging-linux.md)** — `make appimage`, auto-update, performance budgets.
|
||||
- **[Configuration reference](docs/configuration.md)** — env vars, CLI flags.
|
||||
- **[QML API reference](docs/qml-api.md)** / **[PHP API reference](docs/php-api.md)** — singletons, components, attributes, services.
|
||||
|
||||
## Project structure
|
||||
Design rationale and roadmap live in [PLAN.md](PLAN.md). User-facing changes per release are in [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
```text
|
||||
bin/
|
||||
php-qml-init # bash scaffolder — copies the skeleton into a new project
|
||||
framework/
|
||||
php/ # the Symfony bundle (php-qml/bridge)
|
||||
qml/ # the Qt module (PhpQml.Bridge): BackendConnection, ReactiveListModel, …
|
||||
skeleton/ # reference application — what php-qml-init copies
|
||||
examples/
|
||||
todo/ # POC todo app exercising every primitive
|
||||
packaging/linux/ # build-appimage.sh + AppImageUpdate sidecar wiring
|
||||
.gitea/workflows/ # ci.yml (PR gate) + release.yml (v* tags)
|
||||
PLAN.md # design source of truth
|
||||
CHANGELOG.md # release log
|
||||
```
|
||||
## Tech stack
|
||||
|
||||
See [PLAN.md §9](PLAN.md#9-project-layout) for the conceptual layout.
|
||||
PHP 8.4+ · Symfony 8 · Doctrine ORM 3 · FrankenPHP 1.12+ (worker mode) · Mercure · Qt 6.5+ · CMake · Composer · Gitea Actions
|
||||
|
||||
## Roadmap
|
||||
|
||||
Six phases, each ending with something runnable. Detail in [PLAN.md §13](PLAN.md#13-roadmap-to-poc).
|
||||
|
||||
- **Phase 0** ✅ throwaway spike — prove transport on Linux.
|
||||
- **Phase 0** ✅ throwaway transport spike.
|
||||
- **Phase 1** ✅ framework skeleton, dev mode, single-instance lock, CI quality gate.
|
||||
- **Phase 2** ✅ reactive models, update semantics, headline maker (`make:bridge:resource`).
|
||||
- **Phase 3** ✅ POC todo application generated via the makers; testing infrastructure.
|
||||
- **Phase 4a** ✅ bundled mode, Linux AppImage, release CI, AppImageUpdate auto-update, performance smoke.
|
||||
- **Phase 4b/4c** ⏳ macOS and Windows packaging.
|
||||
- **Phase 5** 🚧 DX polish (in progress) — dev console, init script, hot-reload docs, v0.1.0 prep.
|
||||
- **Phase 2** ✅ reactive models, update semantics, headline maker.
|
||||
- **Phase 3** ✅ POC todo app, integration + snapshot tests.
|
||||
- **Phase 4a** ✅ bundled mode, Linux AppImage, release CI, AppImageUpdate.
|
||||
- **Phase 4b/4c** ⏳ macOS / Windows packaging.
|
||||
- **Phase 5** 🚧 DX polish — dev console, init script, hot-reload docs, v0.1.0 prep.
|
||||
|
||||
## Contributing
|
||||
|
||||
Active development happens on the `dev` branch; `main` only carries release commits. Pull requests target `dev`.
|
||||
|
||||
Quality gate that CI runs:
|
||||
|
||||
```bash
|
||||
cd framework/php && composer quality # PHPStan + cs-fixer (check) + PHPUnit
|
||||
cd framework/php && composer quality # PHPStan + cs-fixer + PHPUnit
|
||||
cd examples/todo && make quality # adds qmllint + integration test
|
||||
```
|
||||
|
||||
A dedicated `CONTRIBUTING.md` will arrive alongside Phase 5's wrap-up.
|
||||
A dedicated `CONTRIBUTING.md` arrives with Phase 5's wrap-up.
|
||||
|
||||
## Versioning
|
||||
|
||||
[Semantic Versioning](https://semver.org/) — `MAJOR.MINOR.BUGFIX`. MAJOR for breaking changes, MINOR for backwards-compatible features, BUGFIX for backwards-compatible fixes. Pre-v1.0.0 minor bumps may break public API.
|
||||
[Semantic Versioning](https://semver.org/) — `MAJOR.MINOR.BUGFIX`. Pre-v1.0.0, minor bumps may break public API.
|
||||
|
||||
## License
|
||||
|
||||
To be decided before v0.1.0 is tagged. The framework's own code will be permissively licensed; note that Qt is shipped under LGPL and that carries obligations for distributors — see [PLAN.md §12](PLAN.md#12-open-questions-and-risks) (Qt LGPL relinkability).
|
||||
To be decided before v0.1.0 is tagged. The framework's own code will be permissively licensed; Qt is shipped under LGPL with relinkability obligations — see [PLAN.md §12](PLAN.md#12-open-questions-and-risks).
|
||||
|
||||
Reference in New Issue
Block a user