Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 96 additions & 54 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,6 @@
# Changelog

## Unreleased

### Changed (BREAKING — webroot reorganisation)

- **`public/` is now THE webroot.** Source code, the SQLite DB, configs,
composer artifacts, the editor's PHP source, theme PHP source and CLI
scripts all live OUTSIDE the webroot now. Defense-in-depth is no longer
load-bearing: a misconfigured Caddy/nginx that lacks deny rules can no
longer expose `data/imanager.db`, `.git/`, `vendor/`, `boot/`, or
`bin/` simply because those paths are not below the document root.
Server admins point `root` at `<install>/public/` and that's it.
- **Themes split into two halves.**
`themes/<name>/` (PHP source, includes only) +
`public/themes/<name>/` (static assets — css, fonts, images, scripts).
The `site/` wrapper directory is gone; `site/themes/` becomes
`themes/`, `site/modules/` becomes `modules/`.
- **Editor static assets move to `public/editor-assets/`.** The editor
theme's PHP files (`template.php`, `header.php`, `summary.php`) stay in
`editor/theme/` — included only by `editor/index.php`, never web-served.
`editor/lang/` stays in `editor/`.
- **User uploads move to `public/uploads/`** (was `data/uploads-2.0/`).
Inside the webroot, served by the web server directly, no alias rules
needed. The image rendering layer (`Frontend\ImageUrlBuilder`) is
backward-compatible with both the old `data/uploads/` (1.x-migrated)
and `data/uploads-2.0/` (2.0 pre-public-webroot) prefixes — existing
items in the live DB keep rendering without a path migration.
- **New asset-URL helpers**:
`Site::themeAssetUrl()`, `Site::editorAssetUrl()`, `Editor::assetUrl()`.
All bundled-theme + editor-theme templates are converted. Custom
themes built against 2.0 should switch to the helpers — see
[`docs/themes.md`](docs/themes.md).
- **`public/.htaccess`** replaces the root `.htaccess`. The deny list
collapses to dotfiles only, because the source/data directories no
longer live inside the webroot. The `editor/`-specific rewrite is
gone too — every request goes through `public/index.php`, which
handles admin-path delegation in PHP.
- **Demo image rewired**: `nginx.conf` `root` is `/var/www/scriptor/public`,
the `/data/` alias + deny rules are dropped (data/ is outside the
webroot now), `/uploads/` location added with long-cache headers.

See [`docs/refactor-public-webroot.md`](docs/refactor-public-webroot.md)
for the full migration plan including server-config templates for
Apache, Caddy, nginx and PHP's built-in server, and the
allow/deny test matrix.

## 2.0.0 — Ground-up rewrite on iManager 2.0
## 2.0.0 (2026-05-16) — Ground-up rewrite on iManager 2.0

Scriptor 2.0 replaces the embedded 1.x `imanager/` library with the
external [iManager 2.0][imanager] package and rebuilds Frontend +
Expand Down Expand Up @@ -79,6 +34,11 @@ dispatch, PSR-16 caching). The legacy 1.x flat-file storage is gone.
- **`Scriptor\Boot\Frontend\*`** — `Site`, `Page`, `PageRepository`,
`Sanitizer`, `ImageUrlBuilder` — public-site renderer that bundled
themes consume through the standard `$site` surface.
- **Asset-URL helpers**: `Site::themeAssetUrl()`,
`Site::editorAssetUrl()`, `Editor::assetUrl()` — used by every
bundled template after the public/-webroot split. Custom themes
built against 2.0 should call these instead of hard-coding paths;
see [`docs/themes.md`](docs/themes.md).

### Fixed

Expand All @@ -92,17 +52,62 @@ dispatch, PSR-16 caching). The legacy 1.x flat-file storage is gone.
`Site::buildPageUrl()` already tolerates cyclic data via a
visited-set guard, so the editor now matches the frontend's
defensive shape.
- **Trust `X-Forwarded-Proto` for site URL scheme.** Behind a
TLS-terminating reverse proxy (nginx-proxy on the Hetzner demo,
Caddy as a forwarding proxy), `Frontend\Site::detectSiteUrl()` and
`Editor\Editor::detectSiteUrl()` no longer hard-code `http` from
`$_SERVER['HTTPS']` — they read `X-Forwarded-Proto` first. Fixes
mixed-content errors when the site is reverse-proxied.
- **Demo seed restore recreates the FTS5 index.** The first-boot
entrypoint re-applies the FTS schema and runs `imanager fts:rebuild`
after dropping in the SQL dump, so editor password saves (which
trigger an FTS update) don't crash with "no such table: items_fts"
against snapshots captured by iManager <2.0.1.

### Changed (BREAKING — webroot reorganisation)

- **`public/` is now THE webroot.** Source code, the SQLite DB, configs,
composer artifacts, the editor's PHP source, theme PHP source and CLI
scripts all live OUTSIDE the webroot now. Defense-in-depth is no longer
load-bearing: a misconfigured Caddy/nginx that lacks deny rules can no
longer expose `data/imanager.db`, `.git/`, `vendor/`, `boot/`, or
`bin/` simply because those paths are not below the document root.
Server admins point `root` at `<install>/public/` and that's it.
- **Themes split into two halves.**
`themes/<name>/` (PHP source, includes only) +
`public/themes/<name>/` (static assets — css, fonts, images, scripts).
The `site/` wrapper directory is gone; `site/themes/` becomes
`themes/`, `site/modules/` becomes `modules/`.
- **Editor static assets move to `public/editor-assets/`.** The editor
theme's PHP files (`template.php`, `header.php`, `summary.php`) stay in
`editor/theme/` — included only by `editor/index.php`, never web-served.
`editor/lang/` stays in `editor/`.
- **User uploads move to `public/uploads/`** (was `data/uploads-2.0/`).
Inside the webroot, served by the web server directly, no alias rules
needed. The image rendering layer (`Frontend\ImageUrlBuilder`) is
backward-compatible with both the old `data/uploads/` (1.x-migrated)
and `data/uploads-2.0/` (2.0 pre-public-webroot) prefixes — existing
items in the live DB keep rendering without a path migration.
- **`public/.htaccess`** replaces the root `.htaccess`. The deny list
collapses to dotfiles only, because the source/data directories no
longer live inside the webroot. The `editor/`-specific rewrite is
gone too — every request goes through `public/index.php`, which
handles admin-path delegation in PHP.

See [`docs/refactor-public-webroot.md`](docs/refactor-public-webroot.md)
for the full migration plan including server-config templates for
Apache, Caddy, nginx and PHP's built-in server, and the
allow/deny test matrix.

### Changed

- **Composer dep on iManager: switched from path-repo + dev to the
Packagist stable release.** With `bigins/imanager 2.0.0` published
on Packagist, the `composer.json` no longer declares the
`../imanager` path repository or the `minimum-stability: dev` /
`prefer-stable: true` pair, and the constraint is plain `^2.0`
instead of `2.0.x-dev`. `composer install` now works against a
fresh clone without any sibling iManager checkout — and against
the public Packagist mirror, not the local working tree.
- **Composer dep on iManager: Packagist `^2.0` (locked to 2.0.1).**
With `bigins/imanager` published on Packagist, `composer.json` no
longer declares the `../imanager` path repository or the
`minimum-stability: dev` / `prefer-stable: true` pair. The lock
pins **2.0.1**, which fixes a `dump`-skips-FTS5 bug that broke
seed-restore round-trips. `composer install` now works against a
fresh clone without any sibling iManager checkout.
- **Demo image: drop the composer-rewrite workaround.** With
`bigins/imanager` resolvable from Packagist directly,
`docker/Dockerfile` no longer needs the `composer-rewrite.php`
Expand All @@ -124,6 +129,43 @@ dispatch, PSR-16 caching). The legacy 1.x flat-file storage is gone.
- **`scriptor-config.php` admin_path comment** no longer claims
the user must update `.htaccess` after changing `admin_path`.
The 2.0 PHP-level delegation in `index.php` makes that obsolete.
- **Domain rebrand: `scriptor-cms.info` → `scriptor-cms.dev`.** All
in-repo references updated; new banner at
`docs/images/scriptor-banner-2.0.png`.
- **Demo image rewired** for the public/-webroot layout:
`nginx.conf` `root` is `/var/www/scriptor/public`, the `/data/`
alias + deny rules are dropped (`data/` is outside the webroot
now), `/uploads/` location added with long-cache headers.
- **Demo image: two-image stack.** A tiny `nginx:alpine` web
image (`docker/Dockerfile.web`) bakes `public/` so
`SCRIPT_FILENAME` paths resolve identically in both containers
and the front isn't shadowed by a single shared volume.
- **Demo seed mirrors `https://scriptor.cms` content** instead of
the previous synthetic programmatic seed. Snapshot captured via
`imanager dump`. Ships with `admin / gT5nLazzyBob` — change
before exposing.
- **Docker volume layout split**: the pre-refactor single
`scriptor-app` volume mounted code AND state, which silently
shadowed image updates — `git pull && up -d --build` didn't
propagate code changes without `down -v` (which wiped state).
Now `scriptor-data` (DB, cache, logs, settings) and
`scriptor-uploads` (FileStorage) hold state; code lives in the
images, rebuilt on every `--build`.

### Security

- **Hardened response headers** on every response: tight
`Content-Security-Policy` (no `script-src 'unsafe-inline'`,
allow-lists `cdn.jsdelivr.net` for the basic theme's UIkit),
`X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`,
`Referrer-Policy: strict-origin-when-cross-origin`,
`Permissions-Policy` opting out of
geolocation/camera/microphone/payment/FLoC. `server_tokens off`
+ `expose_php=Off` — the nginx version no longer leaks and
`X-Powered-By` is gone.
- **Editor `IMSESSID` session cookie** ships with `Secure`
(X-Forwarded-Proto-aware, so local HTTP dev still works),
`HttpOnly`, `SameSite=Lax`.

### Removed

Expand Down