v0.2.0 (9/N): pre-migration auto-backup of var/data.sqlite
PLAN.md §12 *Migrations on schema change* flagged this as a v1.0 prereq. SQLite has no transactional DDL — a half-applied migration can corrupt the user's data with no rollback path. Cheapest defence is a copy-aside before each migrate. backupDatabase() runs at the head of runMigrations() in bundled mode: - skipped on first launch (no data.sqlite yet) - copies var/data.sqlite to var/data.sqlite.<unix-timestamp>.bak - trims to kMaxDatabaseBackups=5 most recent (mtime sort, oldest go first) - copy failure logs a warning and continues; a missing safety-net is not a reason to refuse to boot Dev mode is unaffected — developers own their var/data.sqlite lifecycle and don't want a backup written every time `make dev` restarts. Integration test: bundled-supervisor.sh gained an assertion after the 2nd-launch /healthz check that at least one data.sqlite.*.bak file appears under the user data dir. Verified locally — backup landed at the expected path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ This section tracks work landing on `dev` toward **v0.2.0** (next minor; pre-1.0
|
||||
- **`make:bridge:resource --with-dto` opt-in.** Generates `Create<Name>Dto` + `Update<Name>Dto` under `src/Dto/` alongside the controller, and the controller dispatches via `#[MapRequestPayload]`. Closes the input-validation gap from the audit: malformed JSON, missing required fields, or `#[Assert\NotBlank]` violations now produce RFC 7807 `application/problem+json` automatically (Symfony's `RequestPayloadValueResolver`) — no more `if (isset($data['title']))` boilerplate, no silent type coercion. Update DTOs use nullable defaults so PATCH callers send only the fields they want changed. Without `--with-dto` the legacy template still ships unchanged. Maker fails loud if `symfony/validator` isn't autoloadable. Skeleton + example/todo composer.json pull `symfony/validator` so scaffolded apps work out of the box. Snapshot test exercises both modes.
|
||||
- **`make:bridge:event <Name>` maker.** Generates a domain-event class (`src/Event/<Name>Event.php`, readonly value object), a subscriber (`src/EventSubscriber/<Name>Subscriber.php`) that republishes via `PublisherInterface` on `app://event/<kebab-name>`, and a QML stub (`{qml_path}/<Name>EventHandler.qml`) that listens via `MercureClient` and re-emits as a typed `signal`. Closes the third row of PLAN.md §8's makers table; pairs with the existing `make:bridge:resource` / `command` / `window` makers so domain events have a one-command path from PHP through to QML.
|
||||
- **`make:bridge:read-model <Name>` maker.** Generates a query-only projection: `src/ReadModel/<Name>ReadModel.php` (query service stub injecting `EntityManagerInterface`), `src/Controller/<Name>Controller.php` (single GET handler at `/api/<kebab-plural>`), and `{qml_path}/<Name>List.qml` (`ReactiveListModel` bound to the route, deliberately *no* Mercure topic — read-models aren't auto-reactive; invalidation is event-driven via `make:bridge:event`). Closes the fourth row of PLAN.md §8's makers table.
|
||||
- **Pre-migration auto-backup of `var/data.sqlite`.** Bundled-mode supervisor copies the SQLite file to `var/data.sqlite.<unix-timestamp>.bak` before invoking `doctrine:migrations:migrate`; trims to the 5 most recent. SQLite's lack of transactional DDL means a half-applied migration can corrupt the database with no rollback path; cheap insurance against that. Skipped on first launch (no DB to back up); failure to copy logs a warning and continues (a missing safety-net is not a reason to refuse to boot). Backup runs only in bundled mode — dev mode users own their `var/data.sqlite` lifecycle. Bundled-supervisor integration test gained an assertion that a `.bak` file appears under the user data dir on second launch.
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user