From 0e42e2fecbe11b8386a40a3a1d8044062187cbbc Mon Sep 17 00:00:00 2001 From: meleki Date: Fri, 25 Sep 2026 18:22:07 +0200 Subject: [PATCH] Describe project snapshots and their API routes (#231) The editor can now keep named snapshots of a project. The wiki explains how to use them and where they live. - Concepts: new section "Snapshots" on create, restore with the automatic "Before restoring" copy, and delete. - API: the four routes under projects/{id}/snapshots. - Architecture: SnapshotStore on server and client, and the dialog. - Development: e2e module 50, the PHP test and the check sum 1393. --- API.md | 6 +++++- Architecture.md | 4 ++++ Concepts.md | 15 ++++++++++++++- Development.md | 3 ++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/API.md b/API.md index aab31d5..80d76c6 100644 --- a/API.md +++ b/API.md @@ -10,7 +10,11 @@ All routes go through `api/index.php?r=…` (the site's nginx does not pass `PAT | POST | `projects` | `{name}` → project document (201) | | GET | `projects/{id}` | `{id,name,revision,updatedAt,project}` | | PUT | `projects/{id}` | `{revision, project}` → `{revision,updatedAt}` or **409** `{error,revision}` when stale | -| DELETE | `projects/{id}` | 204 | +| DELETE | `projects/{id}` | 204, and the snapshots of the project go with it | +| GET | `projects/{id}/snapshots` | `[{id,name,revision,createdAt}]`, newest first — see [Concepts](Concepts) | +| POST | `projects/{id}/snapshots` | `{name?}` → `{id,name,revision,createdAt}` (201). Copies the project as stored; a blank name becomes the UTC date and time. **422** over 120 characters | +| DELETE | `projects/{id}/snapshots/{sid}` | 204 | +| POST | `projects/{id}/snapshots/{sid}/restore` | `{revision}` → `{revision,updatedAt,before}`. Keeps the stored project as the snapshot `before` (`Before restoring `), then saves the snapshot as the next revision. **409** `{error,revision}` when `revision` is stale | | GET | `textures` | `[{file,name,width,height,bytes,updatedAt}]` — what the image picker offers | | POST | `textures&name=hero.png` | **raw image bytes** → `{file,name,width,height,bytes}` (201) | | DELETE | `textures/{file}` | 204 | diff --git a/Architecture.md b/Architecture.md index 4fdd0ae..cbdf70d 100644 --- a/Architecture.md +++ b/Architecture.md @@ -90,6 +90,7 @@ src/core/particles/ nodes (the catalogue), compile (a graph → one function src/core/store/ serialize (untrusted JSON → Project), projectPlugins (which plugins a project switches on, read off the raw file before it is deserialized, #119), tilemapCells (the compact form of a layer's cells in the file), http (one API call), ProjectStore/HttpProjectStore (load takes a `prepare` that sees the raw JSON first), + SnapshotStore/HttpSnapshotStore (the snapshots of a project, #231), AuthStore/HttpAuthStore (signing in and out, #177; changing the password, #182), FileStore (what the server holds of one kind) + HttpFileStore (one generic client over the three file collections) — TextureStore, FontStore and SoundStore are its type parameters, nothing else @@ -136,6 +137,8 @@ src/viewport/ view (transforms), items (what to draw), symbols (how to src/editor/ App → Editor (layout + ticker), PlaySession (the run), ProjectSession (load/create/delete plus the top bar's one menu, #183), OpenProjectDialog (the project picker behind "Open project…"), + SnapshotsDialog + snapshots (the list behind "Snapshots…" and the rule of when a + snapshot may be made: only with everything saved, #231), ProjectSettingsDialog + settingsChanges (name, the start-scene switch and the collision layers in one dialog; the pure rule of what Apply has to carry out), EditorRun (run in editor), state, actions, shortcuts, debugHook (installs `window.__gm`; @@ -238,6 +241,7 @@ src/editor/console/ log (ring buffer, argument formatting, the console.* capt api/ PHP backend: index.php (routing and the sign-in gate), lib/{Store,TextureStore,FontStore,SoundStore,PluginStore,OriginalName,Response}.php, lib/{Auth,UserStore,SessionStore}.php (#177: accounts in data/users.json, sessions in data/sessions/) + lib/SnapshotStore.php (#231: data/snapshots/{projectId}/, one copy of the project per file) data/projects/ persisted projects, data/textures/ + data/fonts/ + data/sounds/ content-addressed uploads, data/plugins/ editor plugins, filled from plugins/ by the build and the seeder; which of them run is written in each project (#119) diff --git a/Concepts.md b/Concepts.md index eea2769..4efd9c2 100644 --- a/Concepts.md +++ b/Concepts.md @@ -57,8 +57,21 @@ Fixed steps start on a whole screen pixel, so pixel art at 100% stays sharp. The pixel, and Fit then names the factor in screen pixels (`Fit · 156%`). The choice is saved with the project, like *Play starts*, but it is no undo step: Ctrl+Z undoes edits, not a look at the game. +**Snapshots** (#231). *Menu → Snapshots…* lists the snapshots of the open project, newest first, +with the local time each was made. **Create snapshot** copies the project as the server has it +stored, under the name typed or, left blank, under the date and time; the autosave is written +first, and while anything is still unsaved (a run with edits waiting, a failed save, a conflict) +no snapshot is made. **Restore** asks first, then keeps the project as it is now as a snapshot of +its own, `Before restoring `, and writes the snapshot back as a new revision — so a restore +can itself be taken back. The project is loaded again, which starts the undo history over, and a +second tab still on the old revision is told the project was changed elsewhere. **Delete** asks, +then removes the one picked. A snapshot is only a copy of the project document: images, fonts, +sounds and pixel art are stored by their content and never removed, so everything it names is +still there. Deleting the project deletes its snapshots. Whoever can open a project can use its +snapshots, an administrator included. + **Toolbar and panels.** The toolbar carries five **icon buttons** and no captions (#183): the -**menu** (three bars) on the left with *New project*, *Open project…* and *Project settings…*, +**menu** (three bars) on the left with *New project*, *Open project…*, *Snapshots…* and *Project settings…*, **undo** and **redo** beside it, and **play** and **pause** in the middle — on the middle of the window, not of the space the row has left over — where play turns into a stop square while a run is on, and pause into a second play sign while it is held. On the right stand the diff --git a/Development.md b/Development.md index eae8a6d..e807e53 100644 --- a/Development.md +++ b/Development.md @@ -14,7 +14,8 @@ npm run build # writes dist/ and regenerates index.html ./build.sh # the same under `set -o pipefail`, for callers that pipe the output php tools/make-user.php [admin|user] # an account; every tool signs in (see Accounts) php tests/php/accounts.test.php # the API's account rules, no server needed (CI's gate job) -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1385 editor checks, screenshots in /tmp/gm-e2e-*.png +php tests/php/snapshots.test.php # the snapshot store (#231), the same way +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1393 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result