nibula 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/.eleventy.js +82 -81
  2. package/CHANGELOG.md +395 -377
  3. package/LICENSE +169 -169
  4. package/NOTICE +4 -4
  5. package/README.md +110 -110
  6. package/bin/create.js +540 -505
  7. package/bin/delegate.js +58 -57
  8. package/bin/nibula.js +302 -302
  9. package/docs/Assistant CLI.md +65 -65
  10. package/docs/Backend.md +201 -201
  11. package/docs/Components.md +140 -140
  12. package/docs/Creating pages.md +69 -69
  13. package/docs/Deploy.md +210 -210
  14. package/docs/Head and SEO.md +139 -139
  15. package/docs/Javascript.md +126 -126
  16. package/docs/Styling with SCSS.md +141 -139
  17. package/nginx.conf +113 -113
  18. package/package.json +69 -69
  19. package/src/backend/.htaccess +6 -6
  20. package/src/backend/_core/composer.json +5 -5
  21. package/src/backend/_core/composer.lock +492 -492
  22. package/src/backend/_core/index.js +267 -267
  23. package/src/backend/_core/index.php +160 -160
  24. package/src/backend/_core/init.js +52 -52
  25. package/src/backend/_core/init.php +33 -33
  26. package/src/backend/_core/modules/RateLimiter.js +58 -58
  27. package/src/backend/_core/modules/RateLimiter.php +30 -30
  28. package/src/backend/_core/modules/Response.js +59 -59
  29. package/src/backend/_core/modules/Response.php +48 -48
  30. package/src/backend/api/protected/example-protected.js +23 -23
  31. package/src/backend/api/protected/example-protected.php +16 -16
  32. package/src/backend/api/public/example-public.js +24 -24
  33. package/src/backend/api/public/example-public.php +16 -16
  34. package/src/backend/database/Database.js +46 -46
  35. package/src/backend/database/Database.php +23 -23
  36. package/src/backend/example.config.js +37 -37
  37. package/src/backend/example.config.php +37 -37
  38. package/src/backend/package.json +17 -17
  39. package/src/backend/web.config +43 -43
  40. package/src/frontend/.htaccess +51 -51
  41. package/src/frontend/404.njk +17 -17
  42. package/src/frontend/assets/brand/favicon.svg +54 -54
  43. package/src/frontend/assets/brand/logo.svg +54 -54
  44. package/src/frontend/components/global/footer.njk +25 -25
  45. package/src/frontend/components/global/header.njk +6 -6
  46. package/src/frontend/components/welcome.njk +115 -115
  47. package/src/frontend/index.njk +8 -8
  48. package/src/frontend/js/global.js +10 -10
  49. package/src/frontend/js/modules/exampleModule.js +2 -2
  50. package/src/frontend/js/pages/404.js +8 -8
  51. package/src/frontend/js/pages/homepage.js +8 -8
  52. package/src/frontend/layouts/base.njk +135 -136
  53. package/src/frontend/layouts/page-components.njk +13 -13
  54. package/src/frontend/llms.njk +17 -17
  55. package/src/frontend/robots.njk +7 -7
  56. package/src/frontend/scss/_global.scss +46 -46
  57. package/src/frontend/scss/_root.scss +13 -13
  58. package/src/frontend/scss/modules/_animations.scss +24 -24
  59. package/src/frontend/scss/modules/_footer.scss +28 -28
  60. package/src/frontend/scss/modules/_header.scss +26 -26
  61. package/src/frontend/scss/modules/_mobile.scss +29 -29
  62. package/src/frontend/scss/modules/_typography.scss +18 -18
  63. package/src/frontend/scss/modules/frameworks/_bootstrap.scss +109 -109
  64. package/src/frontend/scss/modules/frameworks/_bulma.scss +108 -108
  65. package/src/frontend/scss/modules/frameworks/_foundation.scss +137 -137
  66. package/src/frontend/scss/modules/frameworks/_uikit.scss +109 -109
  67. package/src/frontend/scss/pages/404.scss +27 -27
  68. package/src/frontend/scss/pages/homepage.scss +22 -22
  69. package/src/frontend/sitemap.njk +17 -17
  70. package/src/frontend/ts/global.ts +11 -11
  71. package/src/frontend/ts/modules/exampleModule.ts +2 -2
  72. package/src/frontend/ts/pages/404.ts +8 -8
  73. package/src/frontend/ts/pages/homepage.ts +8 -8
  74. package/src/frontend/web.config +51 -51
  75. package/tools/assistant.js +122 -122
  76. package/tools/buildJs.js +39 -39
  77. package/tools/cleanOutput.js +23 -23
  78. package/tools/cli/prompt.js +40 -40
  79. package/tools/cli/ui.js +87 -87
  80. package/tools/config/messages.json +80 -80
  81. package/tools/config/settings.json +130 -130
  82. package/tools/lib/colors.js +17 -17
  83. package/tools/lib/files.js +75 -75
  84. package/tools/lib/logger.js +22 -22
  85. package/tools/lib/outputPath.js +141 -141
  86. package/tools/lib/pageActions.js +146 -146
  87. package/tools/lib/pageArtifacts.js +46 -46
  88. package/tools/lib/pageComponents.js +88 -88
  89. package/tools/lib/pagesData.js +87 -87
  90. package/tools/lib/paths.js +63 -63
  91. package/tools/lib/project.js +54 -54
  92. package/tools/lib/text.js +47 -47
  93. package/tools/lib/validation.js +40 -40
  94. package/tools/res/templates/template.js +7 -7
  95. package/tools/res/templates/template.njk +8 -8
  96. package/tools/res/templates/template.scss +22 -22
  97. package/tools/res/templates/template.ts +8 -8
  98. package/tsconfig.json +24 -24
  99. package/src/frontend/scss/pages/prova.scss +0 -23
package/CHANGELOG.md CHANGED
@@ -1,377 +1,395 @@
1
- # Changelog
2
-
3
- All notable changes to Nibula are documented here.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [2.0.0] - 2026-08-06
9
-
10
- ### Breaking
11
- - Per-page settings must move out of `site.json`. Take the block under the `pages`
12
- key and make it the root object of a new `src/frontend/data/pages.json`, then
13
- update `base.njk`, `sitemap.njk` and `llms.njk` to read `pages[title]` instead of
14
- `site.pages[title]`. Without `pages.json` the assistant reports the missing file
15
- and stops.
16
- - SCSS and JS import paths change with the `_root`, `_global` and `global` moves.
17
- Update the `@use` and `@import` lines in your page entry points accordingly.
18
- - Existing projects keep working until you run `npm install nibula@latest` inside
19
- them: commands now delegate to the project's own copy, so an old project keeps
20
- running the version it was built with.
21
-
22
- ### Changed
23
- - **Per-page settings moved from `site.json` to a new `pages.json`.** They were nested under a `pages` key in the same file the CLI writes on every page operation; splitting them means a syntax error in one page's record no longer makes the whole site configuration unreadable. Access changes from `{{ site.pages[title] }}` to `{{ pages[title] }}`, and the CLI now reads and writes `pages.json` only.
24
- - Commands run inside a project now execute the project's own Nibula, taken from its `node_modules`, instead of the globally installed one. `nib cli` typed in a terminal used to run the global copy against local files, so a project scaffolded with an older version could be operated on by a newer CLI expecting a different structure. When the two versions differ, the one being used is reported before the command runs, and the assistant's title shows it as well.
25
- - `_root.scss` and `_global.scss` moved out of `scss/modules/`. They are not modules — every page imports them and nothing else does — so they now sit at the root of `scss/`.
26
- - `global.js` and `global.ts` moved out of their `modules/` folders, for the same reason.
27
- - Import paths updated across existing modules, pages and scaffold templates to match both moves.
28
- - `base.njk` applies the `url` filter to per-page CSS and JS, to the favicons and to the framework scripts. Without it these paths ignore `pathPrefix`, so every asset 404s on a site published under a subpath — GitHub Pages being the common case.
29
- - Documentation updated throughout for the new structure and the `site.json` / `pages.json` split.
30
-
31
- ### Fixed
32
- - TypeScript page entry points imported modules with a `.js` extension.
33
- - `logo` was nested inside `legal` in `site.json`, so `{{ site.logo }}` resolved to nothing in the header, the footer, the Open Graph image and the JSON-LD publisher block. It now sits at the root, where the templates already looked for it.
34
-
35
- ### Removed
36
- - `legal.cookieControls` from `site.json`.
37
- - Preconnect hint to `cdn.jsdelivr.net` in `base.njk`. The project loads its framework from `node_modules` through passthrough copy, so the hint opened a TCP and TLS connection to a host that was never used.
38
-
39
- ## [1.5.3] - 2026-08-05
40
-
41
- ### Fixed
42
- - `web.config` no longer breaks on Windows shared hosting. `ApiToNode` was the
43
- first rule, so every `/api` request returned a 500: rewriting to an absolute
44
- URL needs the ARR module, and the `<serverVariables>` block needs an entry in
45
- `applicationHost.config` — neither is available on a shared plan. `ApiToPhp`
46
- is now the default and `ApiToNode` ships commented out, with the requirements
47
- spelled out above it. `<serverVariables>` is gone; on a server with ARR the
48
- forwarded-protocol header is set server-side.
49
- - The PHP front controller looked for `404.html` only under
50
- `$_SERVER['DOCUMENT_ROOT']`, which doesn't resolve to the site root on shared
51
- hosting, so an unknown `/api` route returned an empty page. It now falls back
52
- to the path relative to `_core`, matching how `index.js` already resolved it.
53
- - `Content-Type: text/html` was only sent when `404.html` existed; the plain
54
- fallback went out undeclared.
55
- - Requesting a protected endpoint in a browser opened a credentials prompt
56
- instead of showing the error. IIS attaches `WWW-Authenticate: Basic` to 401
57
- responses, which the browser answers with a login dialog. It is now removed in
58
- `web.config`, so the JSON envelope reaches the client as intended.
59
- - `httpErrors` under `backend/` is set to `PassThrough`. The site root keeps
60
- `Replace` so unknown pages get `404.html`, but under `backend/` every response
61
- is the API's own JSON envelope and IIS must not substitute its HTML for it.
62
- - `nib rename` overwrote the page's SEO title in `site.json` with one derived
63
- from the new name, discarding whatever you had written. It now moves the
64
- record under the new key and changes nothing else. This also fixes the rename
65
- failing outright when the record's `seo` field was malformed, since the field
66
- is no longer read.
67
- - `nib rename` rewrote `title` in the route's front matter for the same reason.
68
- Only `permalink` is updated now.
69
-
70
- ### Changed
71
- - `docs/Deploy.md` documents the new IIS default, and warns that a Node project
72
- published to Windows shared hosting should leave the `backend` folder out —
73
- the requests would be rewritten onto a PHP front controller the project
74
- doesn't contain.
75
-
76
- ## [1.5.2] - 2026-08-05
77
-
78
- ### Fixed
79
- - `nib new` no longer creates an empty `src/frontend/routes` folder. 1.5.1
80
- removed it from `CREATE_DIRS` but left it in `MANDATORY_COPY`, so it still
81
- arrived from the template. It is now created on demand when the first page is
82
- added, and removed again when the last one is deleted.
83
-
84
- ## [1.5.1] - 2026-08-05
85
-
86
- ### Fixed
87
- - `nib new` no longer creates an empty `routes` folder. Page source folders are
88
- created on demand when a page is added, and removed again when the last page
89
- in them is deleted — `routes`, `scss/pages` and the JS/TS pages folder alike.
90
- - Removing a page that doesn't exist reported the skip and then went on to strip
91
- its entry from `site.json` and `page-components.njk` anyway. It now stops.
92
- - `example.config.php` was missing the `APP_ENV` key, so PHP projects had no way
93
- to discover the debug switch from the template. Behaviour was unaffected —
94
- the code already fell back to `production` — but the key is now visible and
95
- documented, and the two templates are identical again.
96
- - The backend's `dev` script set `APP_ENV` as an environment variable, which
97
- neither backend reads. It ran in production mode and produced no debug output.
98
- The script is gone; error verbosity is set in `config.js` / `config.php`.
99
- - `bin/create.js` repeated the `mysql2` version already declared in
100
- `src/backend/package.json`. It now reads that file, so the two cannot drift.
101
- - `docs/Deploy.md` pointed at `backend/backend-node.service.example`, removed in
102
- 1.5.0. The systemd unit is written out in full instead.
103
- - `docs/Deploy.md` gave the backend path as `/var/www/backend/SITE_FOLDER`,
104
- inverted with respect to the rest of the document.
105
-
106
- ### Changed
107
- - Nginx setup steps moved from the `nginx.conf` header into `docs/Deploy.md`,
108
- under "Your own server". The header keeps only the three placeholders that
109
- appear in the file and a pointer to the docs, so a config copied into
110
- `/etc/nginx/sites-available/` no longer carries 60 lines of install
111
- instructions that were already followed.
112
- - `docs/Deploy.md` troubleshooting is now a table, with a row for a 502 on
113
- `/api` caused by the Node process not running.
114
- - `.eleventyignore` reduced to `src/frontend/assets/**`. The `scss`, `js` and
115
- `src/backend` entries excluded nothing: the first two are not Eleventy
116
- template formats and the third is outside the input directory. The last one
117
- was also misleading, since `.eleventy.js` deliberately copies `src/backend`
118
- into the build.
119
- - `docs/Backend.md` documents `APP_ENV` in its own section, including the
120
- `display_errors` behaviour specific to PHP, and states explicitly that it is
121
- a config key rather than an environment variable.
122
-
123
- ### Notes
124
- - Existing projects are unaffected: the scaffolding and template changes apply
125
- only to newly created ones.
126
-
127
- ## [1.5.0] - 2026-08-04
128
-
129
- ### Added
130
- - `nginx.conf` now covers **both backends** with no manual edits. `/api` is
131
- proxied to Node on `127.0.0.1:3000`; if Node is unreachable, the request is
132
- retried through the PHP front controller via the internal `@php_backend`
133
- location. The same file works for a Node deployment and a PHP one.
134
- - `nginx.conf` header now documents the PHP-FPM requirement, the version-agnostic
135
- socket, and the errors specific to a PHP deployment.
136
-
137
- ### Changed
138
- - PHP is invoked through `SCRIPT_FILENAME` instead of by URL, so `.php` requests
139
- keep returning 404 even on a PHP deployment and no source file is ever
140
- reachable by name.
141
- - `fastcgi_pass` targets the version-agnostic socket `unix:/run/php/php-fpm.sock`
142
- instead of a versioned path, so the config survives PHP upgrades.
143
- - `web.config` is now blocked anywhere in the tree, not only at the document root.
144
- - `docs/Backend.md` is limited to writing endpoints: routing, `public` vs
145
- `protected`, the `Response` helper and configuration. Examples are Node-only,
146
- with a note that PHP behaves identically. Hosting and server requirements
147
- moved to `docs/Deploy.md`.
148
- - `docs/Deploy.md` rewritten around where a site can be published and what each
149
- target requires, including why shared hosting cannot run the Node backend.
150
-
151
- ### Removed
152
- - `docs/Nginx.md` — the setup steps live in the `nginx.conf` header, where they
153
- are read at the moment they are needed.
154
- - `src/backend/backend-node.service.example` — the systemd unit is documented
155
- in `docs/Deploy.md` instead of shipped as a file.
156
-
157
- ## [1.4.0] - 2026-08-03
158
-
159
- ### Changed
160
- - `nginx.conf` is now a complete, ready-to-use site file instead of a set of
161
- directives to paste into your own `server` block. Replace three placeholders
162
- (`YOUR_DOMAIN`, `SITE_FOLDER`, `YOUR_CERTIFICATE`), symlink it into
163
- `sites-enabled/`, reload.
164
- - Nginx documentation moved from `docs/Deploy.md` to `docs/Nginx.md`;
165
- `Deploy.md` now covers only where to publish, one section per server.
166
-
167
- ### Added
168
- - HTTP → HTTPS redirect on port 80, with an optional ACME webroot block.
169
- - TLS setup via Let's Encrypt, with placeholders for the certificate path.
170
- - Security headers: `X-Content-Type-Options`, `X-Frame-Options`,
171
- `Referrer-Policy`, `Strict-Transport-Security` (`max-age=300` by default).
172
- - `.php` requests return 404, preventing source-code leaks when php-fpm is
173
- not configured.
174
-
175
- ### Removed
176
- - **Breaking:** the automatic Node → PHP fallback on Nginx. `/api` is now
177
- proxied to Node only; if the process is down, Nginx returns 502. For a PHP
178
- deployment, edit the `.php` block and `try_files` as described in
179
- `docs/Nginx.md`.
180
-
181
- ### Migration
182
- Existing Nginx deployments: replace your `server` block with the new
183
- `nginx.conf` and fill in the three placeholders. If you relied on the PHP
184
- fallback, follow *Using the PHP backend* in `docs/Nginx.md`.
185
-
186
- ## [1.3.0] - 2026-08-01
187
-
188
- ### Added
189
- - A `global.js` module in `src/frontend/js/modules/`, for code that has to run
190
- on every page — a header menu, a theme toggle, a cookie banner. Page entry
191
- points import it once and it takes care of running the shared modules, so
192
- there's no longer a line to remember in every single page.
193
- - `docs/Javascript.md` now covers the global module, with the header burger
194
- menu as a worked example and a note on when a behaviour belongs in
195
- `global.js` rather than in a page.
196
-
197
- ### Changed
198
- - Page entry points, and the template new pages are created from, now start
199
- with `import '../modules/global.js';`.
200
-
201
- ### Notes
202
- - Existing projects keep working as they are. To adopt the global module, add
203
- `src/frontend/js/modules/global.js` and the import line at the top of each
204
- page entry point.
205
-
206
- ## [1.2.6] - 2026-08-01
207
-
208
- ### Fixed
209
- - The scaffolder created the routes folder as `src/frontend/_routes` instead of
210
- `src/frontend/routes`. The CLI writes and looks for page templates in
211
- `routes`, so on a freshly created project every page ended up outside the
212
- folder Eleventy and the assistant expect.
213
-
214
- ### Notes
215
- - Projects created with 1.2.5 have an empty `src/frontend/_routes` folder that
216
- can be deleted. Pages created before this fix should be moved to
217
- `src/frontend/routes`.
218
-
219
- ## [1.2.5] - 2026-08-01
220
-
221
- ### Added
222
- - `nib new` now refuses to run from inside an existing Nibula project. Creating
223
- a project inside another one produced a broken setup, since the outer build
224
- would pick up the inner project's files. The error message reports the path of
225
- the project that was detected, so it's clear which one triggered the check.
226
- - A GitHub Actions workflow that publishes the package to npm whenever a release
227
- is created, using npm's trusted publishing. The workflow verifies that the git
228
- tag matches the version in `package.json` before publishing, and attaches a
229
- provenance attestation to the published package.
230
-
231
- ### Changed
232
- - Rewrote the README: added a section on when Nibula is *not* the right tool,
233
- clarified that Composer is only needed with the PHP backend, and moved the
234
- editor extensions from the required to the recommended prerequisites.
235
-
236
- ## [1.2.4] - 2026-07-31
237
-
238
- ### Changed
239
- - Internal refactor of `tools/`: the logic is now split across `lib/`, `cli/`
240
- and `config/`, with values and messages extracted into `settings.json` and
241
- `messages.json`. No behaviour changes — pages, `site.json` and
242
- `page-components.njk` are written exactly as before.
243
- - The CLI now uses a uniform palette: colour is limited to the title box, and
244
- the menu numbers are dimmed instead of each carrying its own colour.
245
-
246
- ### Fixed
247
- - The last line of the menu never closed the `dim` colour code, which stayed
248
- active on the following line.
249
-
250
- ## [1.2.3] - 2026-07-29
251
-
252
- ### Fixed
253
- - `updateOutputPath` no longer strips custom flags from `build:css` and `serve:css`: the output path is now replaced in place instead of regenerating the whole script
254
- - Missing `--load-path=node_modules` in the regenerated Sass scripts, which broke Bootstrap SCSS imports
255
- - Malformed `outDir` in `tsconfig.json` when the output path is absolute (`./c:/...`)
256
-
257
- ## [1.2.2] - 2026-07-23
258
-
259
- ### Added
260
- - **Full favicon set**: `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png`
261
- (180×180, opaque) in `assets/brand/`. iOS home-screen icons no longer fall back
262
- to a screenshot of the page.
263
-
264
- ### Changed
265
- - **`data_bs_theme` renamed to `theme`** in `site.json`. It still drives
266
- `data-bs-theme` on the `<html>` tag; the shorter name keeps the config readable
267
- and independent from the framework naming.
268
- - **`theme_color` is now a single value** instead of a `light`/`dark` pair. The
269
- theme is fixed per build, so two per-scheme colors could contradict the
270
- rendered page.
271
- - **Favicon paths are hardcoded in `base.njk`.** The `favicon` key was removed
272
- from `site.json`: it only ever covered one of the three tags, which was more
273
- confusing than helpful. Replace the files in `assets/brand/` instead.
274
- - `_routes/` renamed to `routes/` — it holds entry points, not internals.
275
-
276
- ### Removed
277
- - **`mdFile` shortcode** and the `markdown-it` dependency.
278
- - **`github-markdown-css`** and its two passthrough copies.
279
-
280
- ### Migration
281
- - In `site.json`: rename `data_bs_theme` to `theme`, flatten `theme_color` to a
282
- single string, drop `favicon`.
283
- - Place `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png` in
284
- `src/frontend/assets/brand/`.
285
- - If you used `{% mdFile %}`, render the Markdown ahead of time or add
286
- `markdown-it` back to your own project.
287
-
288
- ## [1.1.3] - 2026-07-22
289
-
290
- ### Changed
291
- - **The update check no longer runs on every command.** Previously every
292
- invocation of `nib` (and the `nbl` / `nibula` aliases) contacted the npm
293
- registry before doing anything, adding up to 2.5s of latency to `nib run`,
294
- `nib build`, `nib cli` and `nib clean`. The check now runs only for `nib new`
295
- and `nib update`; all other commands work entirely offline.
296
- - **`nib new` now completes the update automatically.** When a newer version is
297
- available and you accept the prompt, Nibula installs it and immediately
298
- re-runs the scaffolding with the new version, instead of asking you to type
299
- `nib new <project-name>` a second time.
300
- - **New projects are scaffolded at version `0.0.0`** instead of `1.0.0`, so a
301
- freshly created site no longer claims a stable public release. Bump it
302
- yourself as the project grows, and reach `1.0.0` when you go to production.
303
- - **Framework SCSS imports are now short and readable.** The framework modules
304
- in `src/frontend/scss/modules/frameworks/` used a five-level relative path
305
- back to `node_modules`; they now import directly by package name, e.g.
306
- `@import "bootstrap/scss/card";`. This matches what the styling docs already
307
- showed, and makes commenting modules out far less error-prone.
308
- - `nib help` no longer appends an "a newer version is available" line, since it
309
- no longer performs the check.
310
-
311
- ### Added
312
- - Internal `--skip-update-check` flag on `nib new`, set automatically when the
313
- command is re-run after a self-update. It prevents a loop if the registry is
314
- slow to propagate the new version.
315
- - `--load-path=node_modules` on the repository's own `build:css` and `serve:css`
316
- scripts, so the short framework imports resolve. Generated projects already
317
- carried this flag.
318
-
319
- ### Fixed
320
- - Repaired the ASCII header boxes and the commented-out example import inside
321
- `_bootstrap.scss`, `_bulma.scss` and `_foundation.scss`, where an earlier
322
- find-and-replace had injected the `node_modules` path into comment text and
323
- broken the alignment.
324
- - `src/frontend/data` is no longer copied to the output folder. It holds the
325
- Eleventy global data file, which is consumed at build time to render meta
326
- tags and page config — publishing it produced a dead file in `out/` and
327
- exposed the full page map, including `noindex` entries. It remains a watch
328
- target, so edits still trigger a rebuild.
329
-
330
- ### Notes
331
- - If the updated installation can't be located after `npm install -g` (an
332
- unusual `npm root -g` setup, for example), Nibula reports the problem and
333
- asks you to re-run the command, rather than scaffolding silently with the
334
- old templates.
335
- - Existing projects are unaffected by the version change: it applies only to
336
- newly created ones.
337
- - Short SCSS imports rely on Sass's `--load-path`, which is passed by the npm
338
- scripts. Compiling the stylesheets with a different tool (a VS Code Sass
339
- extension, for instance) will need the same load path configured.
340
-
341
- ## [1.1.0] - 2026-07-21
342
-
343
- ### Added
344
- - **Node.js backend** as an alternative to PHP, living side by side in
345
- `src/backend/`: `_core/index.js` front controller (which is also the HTTP
346
- server), `Response` and `RateLimiter` modules, a `mysql2` pool singleton
347
- `Database.js`, `example.config.js`, and a `package.json` for the backend's
348
- own dependencies. Same REST API as PHP: routing, `X-Api-Key` auth, CORS and
349
- file-based rate limiting are identical.
350
- - **Backend choice at scaffold time**: `nib new` now asks whether to use Node.js
351
- or PHP, in addition to language and CSS framework.
352
- - `backend/backend-node.service.example` — a ready-to-adapt **systemd** unit for
353
- keeping the Node backend running on a server.
354
- - `config.js` is generated from `example.config.js` at scaffold time (mirroring
355
- the existing `config.php` generation).
356
- - Deployment docs now cover running the Node backend with **`screen`** (quick /
357
- small setups) and **systemd** (production), plus environment variables.
358
-
359
- ### Changed
360
- - **Composer is now required only when the PHP backend is chosen.** If you pick
361
- Node, `composer install` is skipped entirely and the backend's npm
362
- dependencies (`mysql2`) are installed instead.
363
- - `.htaccess`, `web.config` and `nginx.conf` now cover **both** backends. On
364
- nginx, `/api` goes to Node and automatically falls back to the PHP front
365
- controller when Node is unreachable. On Apache/IIS the active backend is
366
- selected by configuration (documented), since per-directory configs can't
367
- health-check an upstream.
368
- - `.gitignore` now also ignores `src/backend/config.js`,
369
- `src/backend/node_modules/` and `src/backend/cache/`.
370
- - Documentation (`README.md`, `docs/Backend.md`, `docs/Deploy.md`) updated:
371
- backend examples now use JavaScript/Node as the reference, with the equivalent
372
- PHP shown alongside and a note that PHP behaves identically.
373
-
374
- ### Notes
375
- - Both backends are always scaffolded, so you can switch later without
376
- re-creating the project. The PHP front controller only serves `.php` endpoint
377
- files and the Node one only `.js`, so they coexist without conflict.
1
+ # Changelog
2
+
3
+ All notable changes to Nibula are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.6.2] - 2026-08-07
9
+
10
+ ### Added
11
+ - `nib --version` (also `-v`, `v`, `version`) prints the version number on its own line. Inside a project it reports the project's own copy, which is the one actually running the command.
12
+
13
+ ### Fixed
14
+ [...le quattro voci di prima, invariate...]
15
+
16
+ ### Changed
17
+ - `docs/Styling with SCSS.md` now matches the template: the Nunjucks snippets include the `url` filter and the config file is named `.eleventy.js`.
18
+
19
+ ## [1.6.1] - 2026-08-06
20
+
21
+ ### Fixed
22
+ - `src/frontend/scss/pages/prova.scss` was left in the template and shipped with 1.6.0, so every new project started with a stylesheet for a page that doesn't exist — no route, no script, no entry in `pages.json`.
23
+ - Open Graph and Twitter Card tags read `seo.title` and `seo.description` directly, with none of the fallbacks the `<title>` and meta description already had. A page that left those fields empty in `pages.json` published an empty social preview — exactly the case the fallbacks exist for. They now follow the same chain.
24
+ - `data-theme` was missing from the `<html>` tag. It is documented as the hook to target in SCSS for theme variables, so a selector written against it never matched.
25
+
26
+ ## [1.6.0] - 2026-08-06
27
+
28
+ ### Breaking
29
+ - Per-page settings must move out of `site.json`. Take the block under the `pages`
30
+ key and make it the root object of a new `src/frontend/data/pages.json`, then
31
+ update `base.njk`, `sitemap.njk` and `llms.njk` to read `pages[title]` instead of
32
+ `site.pages[title]`. Without `pages.json` the assistant reports the missing file
33
+ and stops.
34
+ - SCSS and JS import paths change with the `_root`, `_global` and `global` moves.
35
+ Update the `@use` and `@import` lines in your page entry points accordingly.
36
+ - Existing projects keep working until you run `npm install nibula@latest` inside
37
+ them: commands now delegate to the project's own copy, so an old project keeps
38
+ running the version it was built with.
39
+
40
+ ### Changed
41
+ - **Per-page settings moved from `site.json` to a new `pages.json`.** They were nested under a `pages` key in the same file the CLI writes on every page operation; splitting them means a syntax error in one page's record no longer makes the whole site configuration unreadable. Access changes from `{{ site.pages[title] }}` to `{{ pages[title] }}`, and the CLI now reads and writes `pages.json` only.
42
+ - Commands run inside a project now execute the project's own Nibula, taken from its `node_modules`, instead of the globally installed one. `nib cli` typed in a terminal used to run the global copy against local files, so a project scaffolded with an older version could be operated on by a newer CLI expecting a different structure. When the two versions differ, the one being used is reported before the command runs, and the assistant's title shows it as well.
43
+ - `_root.scss` and `_global.scss` moved out of `scss/modules/`. They are not modules — every page imports them and nothing else does — so they now sit at the root of `scss/`.
44
+ - `global.js` and `global.ts` moved out of their `modules/` folders, for the same reason.
45
+ - Import paths updated across existing modules, pages and scaffold templates to match both moves.
46
+ - `base.njk` applies the `url` filter to per-page CSS and JS, to the favicons and to the framework scripts. Without it these paths ignore `pathPrefix`, so every asset 404s on a site published under a subpath — GitHub Pages being the common case.
47
+ - Documentation updated throughout for the new structure and the `site.json` / `pages.json` split.
48
+
49
+ ### Fixed
50
+ - TypeScript page entry points imported modules with a `.js` extension.
51
+ - `logo` was nested inside `legal` in `site.json`, so `{{ site.logo }}` resolved to nothing in the header, the footer, the Open Graph image and the JSON-LD publisher block. It now sits at the root, where the templates already looked for it.
52
+
53
+ ### Removed
54
+ - `legal.cookieControls` from `site.json`.
55
+ - Preconnect hint to `cdn.jsdelivr.net` in `base.njk`. The project loads its framework from `node_modules` through passthrough copy, so the hint opened a TCP and TLS connection to a host that was never used.
56
+
57
+ ## [1.5.3] - 2026-08-05
58
+
59
+ ### Fixed
60
+ - `web.config` no longer breaks on Windows shared hosting. `ApiToNode` was the
61
+ first rule, so every `/api` request returned a 500: rewriting to an absolute
62
+ URL needs the ARR module, and the `<serverVariables>` block needs an entry in
63
+ `applicationHost.config` — neither is available on a shared plan. `ApiToPhp`
64
+ is now the default and `ApiToNode` ships commented out, with the requirements
65
+ spelled out above it. `<serverVariables>` is gone; on a server with ARR the
66
+ forwarded-protocol header is set server-side.
67
+ - The PHP front controller looked for `404.html` only under
68
+ `$_SERVER['DOCUMENT_ROOT']`, which doesn't resolve to the site root on shared
69
+ hosting, so an unknown `/api` route returned an empty page. It now falls back
70
+ to the path relative to `_core`, matching how `index.js` already resolved it.
71
+ - `Content-Type: text/html` was only sent when `404.html` existed; the plain
72
+ fallback went out undeclared.
73
+ - Requesting a protected endpoint in a browser opened a credentials prompt
74
+ instead of showing the error. IIS attaches `WWW-Authenticate: Basic` to 401
75
+ responses, which the browser answers with a login dialog. It is now removed in
76
+ `web.config`, so the JSON envelope reaches the client as intended.
77
+ - `httpErrors` under `backend/` is set to `PassThrough`. The site root keeps
78
+ `Replace` so unknown pages get `404.html`, but under `backend/` every response
79
+ is the API's own JSON envelope and IIS must not substitute its HTML for it.
80
+ - `nib rename` overwrote the page's SEO title in `site.json` with one derived
81
+ from the new name, discarding whatever you had written. It now moves the
82
+ record under the new key and changes nothing else. This also fixes the rename
83
+ failing outright when the record's `seo` field was malformed, since the field
84
+ is no longer read.
85
+ - `nib rename` rewrote `title` in the route's front matter for the same reason.
86
+ Only `permalink` is updated now.
87
+
88
+ ### Changed
89
+ - `docs/Deploy.md` documents the new IIS default, and warns that a Node project
90
+ published to Windows shared hosting should leave the `backend` folder out —
91
+ the requests would be rewritten onto a PHP front controller the project
92
+ doesn't contain.
93
+
94
+ ## [1.5.2] - 2026-08-05
95
+
96
+ ### Fixed
97
+ - `nib new` no longer creates an empty `src/frontend/routes` folder. 1.5.1
98
+ removed it from `CREATE_DIRS` but left it in `MANDATORY_COPY`, so it still
99
+ arrived from the template. It is now created on demand when the first page is
100
+ added, and removed again when the last one is deleted.
101
+
102
+ ## [1.5.1] - 2026-08-05
103
+
104
+ ### Fixed
105
+ - `nib new` no longer creates an empty `routes` folder. Page source folders are
106
+ created on demand when a page is added, and removed again when the last page
107
+ in them is deleted — `routes`, `scss/pages` and the JS/TS pages folder alike.
108
+ - Removing a page that doesn't exist reported the skip and then went on to strip
109
+ its entry from `site.json` and `page-components.njk` anyway. It now stops.
110
+ - `example.config.php` was missing the `APP_ENV` key, so PHP projects had no way
111
+ to discover the debug switch from the template. Behaviour was unaffected —
112
+ the code already fell back to `production` — but the key is now visible and
113
+ documented, and the two templates are identical again.
114
+ - The backend's `dev` script set `APP_ENV` as an environment variable, which
115
+ neither backend reads. It ran in production mode and produced no debug output.
116
+ The script is gone; error verbosity is set in `config.js` / `config.php`.
117
+ - `bin/create.js` repeated the `mysql2` version already declared in
118
+ `src/backend/package.json`. It now reads that file, so the two cannot drift.
119
+ - `docs/Deploy.md` pointed at `backend/backend-node.service.example`, removed in
120
+ 1.5.0. The systemd unit is written out in full instead.
121
+ - `docs/Deploy.md` gave the backend path as `/var/www/backend/SITE_FOLDER`,
122
+ inverted with respect to the rest of the document.
123
+
124
+ ### Changed
125
+ - Nginx setup steps moved from the `nginx.conf` header into `docs/Deploy.md`,
126
+ under "Your own server". The header keeps only the three placeholders that
127
+ appear in the file and a pointer to the docs, so a config copied into
128
+ `/etc/nginx/sites-available/` no longer carries 60 lines of install
129
+ instructions that were already followed.
130
+ - `docs/Deploy.md` troubleshooting is now a table, with a row for a 502 on
131
+ `/api` caused by the Node process not running.
132
+ - `.eleventyignore` reduced to `src/frontend/assets/**`. The `scss`, `js` and
133
+ `src/backend` entries excluded nothing: the first two are not Eleventy
134
+ template formats and the third is outside the input directory. The last one
135
+ was also misleading, since `.eleventy.js` deliberately copies `src/backend`
136
+ into the build.
137
+ - `docs/Backend.md` documents `APP_ENV` in its own section, including the
138
+ `display_errors` behaviour specific to PHP, and states explicitly that it is
139
+ a config key rather than an environment variable.
140
+
141
+ ### Notes
142
+ - Existing projects are unaffected: the scaffolding and template changes apply
143
+ only to newly created ones.
144
+
145
+ ## [1.5.0] - 2026-08-04
146
+
147
+ ### Added
148
+ - `nginx.conf` now covers **both backends** with no manual edits. `/api` is
149
+ proxied to Node on `127.0.0.1:3000`; if Node is unreachable, the request is
150
+ retried through the PHP front controller via the internal `@php_backend`
151
+ location. The same file works for a Node deployment and a PHP one.
152
+ - `nginx.conf` header now documents the PHP-FPM requirement, the version-agnostic
153
+ socket, and the errors specific to a PHP deployment.
154
+
155
+ ### Changed
156
+ - PHP is invoked through `SCRIPT_FILENAME` instead of by URL, so `.php` requests
157
+ keep returning 404 even on a PHP deployment and no source file is ever
158
+ reachable by name.
159
+ - `fastcgi_pass` targets the version-agnostic socket `unix:/run/php/php-fpm.sock`
160
+ instead of a versioned path, so the config survives PHP upgrades.
161
+ - `web.config` is now blocked anywhere in the tree, not only at the document root.
162
+ - `docs/Backend.md` is limited to writing endpoints: routing, `public` vs
163
+ `protected`, the `Response` helper and configuration. Examples are Node-only,
164
+ with a note that PHP behaves identically. Hosting and server requirements
165
+ moved to `docs/Deploy.md`.
166
+ - `docs/Deploy.md` rewritten around where a site can be published and what each
167
+ target requires, including why shared hosting cannot run the Node backend.
168
+
169
+ ### Removed
170
+ - `docs/Nginx.md` — the setup steps live in the `nginx.conf` header, where they
171
+ are read at the moment they are needed.
172
+ - `src/backend/backend-node.service.example` — the systemd unit is documented
173
+ in `docs/Deploy.md` instead of shipped as a file.
174
+
175
+ ## [1.4.0] - 2026-08-03
176
+
177
+ ### Changed
178
+ - `nginx.conf` is now a complete, ready-to-use site file instead of a set of
179
+ directives to paste into your own `server` block. Replace three placeholders
180
+ (`YOUR_DOMAIN`, `SITE_FOLDER`, `YOUR_CERTIFICATE`), symlink it into
181
+ `sites-enabled/`, reload.
182
+ - Nginx documentation moved from `docs/Deploy.md` to `docs/Nginx.md`;
183
+ `Deploy.md` now covers only where to publish, one section per server.
184
+
185
+ ### Added
186
+ - HTTP → HTTPS redirect on port 80, with an optional ACME webroot block.
187
+ - TLS setup via Let's Encrypt, with placeholders for the certificate path.
188
+ - Security headers: `X-Content-Type-Options`, `X-Frame-Options`,
189
+ `Referrer-Policy`, `Strict-Transport-Security` (`max-age=300` by default).
190
+ - `.php` requests return 404, preventing source-code leaks when php-fpm is
191
+ not configured.
192
+
193
+ ### Removed
194
+ - **Breaking:** the automatic Node → PHP fallback on Nginx. `/api` is now
195
+ proxied to Node only; if the process is down, Nginx returns 502. For a PHP
196
+ deployment, edit the `.php` block and `try_files` as described in
197
+ `docs/Nginx.md`.
198
+
199
+ ### Migration
200
+ Existing Nginx deployments: replace your `server` block with the new
201
+ `nginx.conf` and fill in the three placeholders. If you relied on the PHP
202
+ fallback, follow *Using the PHP backend* in `docs/Nginx.md`.
203
+
204
+ ## [1.3.0] - 2026-08-01
205
+
206
+ ### Added
207
+ - A `global.js` module in `src/frontend/js/modules/`, for code that has to run
208
+ on every page — a header menu, a theme toggle, a cookie banner. Page entry
209
+ points import it once and it takes care of running the shared modules, so
210
+ there's no longer a line to remember in every single page.
211
+ - `docs/Javascript.md` now covers the global module, with the header burger
212
+ menu as a worked example and a note on when a behaviour belongs in
213
+ `global.js` rather than in a page.
214
+
215
+ ### Changed
216
+ - Page entry points, and the template new pages are created from, now start
217
+ with `import '../modules/global.js';`.
218
+
219
+ ### Notes
220
+ - Existing projects keep working as they are. To adopt the global module, add
221
+ `src/frontend/js/modules/global.js` and the import line at the top of each
222
+ page entry point.
223
+
224
+ ## [1.2.6] - 2026-08-01
225
+
226
+ ### Fixed
227
+ - The scaffolder created the routes folder as `src/frontend/_routes` instead of
228
+ `src/frontend/routes`. The CLI writes and looks for page templates in
229
+ `routes`, so on a freshly created project every page ended up outside the
230
+ folder Eleventy and the assistant expect.
231
+
232
+ ### Notes
233
+ - Projects created with 1.2.5 have an empty `src/frontend/_routes` folder that
234
+ can be deleted. Pages created before this fix should be moved to
235
+ `src/frontend/routes`.
236
+
237
+ ## [1.2.5] - 2026-08-01
238
+
239
+ ### Added
240
+ - `nib new` now refuses to run from inside an existing Nibula project. Creating
241
+ a project inside another one produced a broken setup, since the outer build
242
+ would pick up the inner project's files. The error message reports the path of
243
+ the project that was detected, so it's clear which one triggered the check.
244
+ - A GitHub Actions workflow that publishes the package to npm whenever a release
245
+ is created, using npm's trusted publishing. The workflow verifies that the git
246
+ tag matches the version in `package.json` before publishing, and attaches a
247
+ provenance attestation to the published package.
248
+
249
+ ### Changed
250
+ - Rewrote the README: added a section on when Nibula is *not* the right tool,
251
+ clarified that Composer is only needed with the PHP backend, and moved the
252
+ editor extensions from the required to the recommended prerequisites.
253
+
254
+ ## [1.2.4] - 2026-07-31
255
+
256
+ ### Changed
257
+ - Internal refactor of `tools/`: the logic is now split across `lib/`, `cli/`
258
+ and `config/`, with values and messages extracted into `settings.json` and
259
+ `messages.json`. No behaviour changes — pages, `site.json` and
260
+ `page-components.njk` are written exactly as before.
261
+ - The CLI now uses a uniform palette: colour is limited to the title box, and
262
+ the menu numbers are dimmed instead of each carrying its own colour.
263
+
264
+ ### Fixed
265
+ - The last line of the menu never closed the `dim` colour code, which stayed
266
+ active on the following line.
267
+
268
+ ## [1.2.3] - 2026-07-29
269
+
270
+ ### Fixed
271
+ - `updateOutputPath` no longer strips custom flags from `build:css` and `serve:css`: the output path is now replaced in place instead of regenerating the whole script
272
+ - Missing `--load-path=node_modules` in the regenerated Sass scripts, which broke Bootstrap SCSS imports
273
+ - Malformed `outDir` in `tsconfig.json` when the output path is absolute (`./c:/...`)
274
+
275
+ ## [1.2.2] - 2026-07-23
276
+
277
+ ### Added
278
+ - **Full favicon set**: `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png`
279
+ (180×180, opaque) in `assets/brand/`. iOS home-screen icons no longer fall back
280
+ to a screenshot of the page.
281
+
282
+ ### Changed
283
+ - **`data_bs_theme` renamed to `theme`** in `site.json`. It still drives
284
+ `data-bs-theme` on the `<html>` tag; the shorter name keeps the config readable
285
+ and independent from the framework naming.
286
+ - **`theme_color` is now a single value** instead of a `light`/`dark` pair. The
287
+ theme is fixed per build, so two per-scheme colors could contradict the
288
+ rendered page.
289
+ - **Favicon paths are hardcoded in `base.njk`.** The `favicon` key was removed
290
+ from `site.json`: it only ever covered one of the three tags, which was more
291
+ confusing than helpful. Replace the files in `assets/brand/` instead.
292
+ - `_routes/` renamed to `routes/` — it holds entry points, not internals.
293
+
294
+ ### Removed
295
+ - **`mdFile` shortcode** and the `markdown-it` dependency.
296
+ - **`github-markdown-css`** and its two passthrough copies.
297
+
298
+ ### Migration
299
+ - In `site.json`: rename `data_bs_theme` to `theme`, flatten `theme_color` to a
300
+ single string, drop `favicon`.
301
+ - Place `favicon.svg`, `favicon-32.png` and `apple-touch-icon.png` in
302
+ `src/frontend/assets/brand/`.
303
+ - If you used `{% mdFile %}`, render the Markdown ahead of time or add
304
+ `markdown-it` back to your own project.
305
+
306
+ ## [1.1.3] - 2026-07-22
307
+
308
+ ### Changed
309
+ - **The update check no longer runs on every command.** Previously every
310
+ invocation of `nib` (and the `nbl` / `nibula` aliases) contacted the npm
311
+ registry before doing anything, adding up to 2.5s of latency to `nib run`,
312
+ `nib build`, `nib cli` and `nib clean`. The check now runs only for `nib new`
313
+ and `nib update`; all other commands work entirely offline.
314
+ - **`nib new` now completes the update automatically.** When a newer version is
315
+ available and you accept the prompt, Nibula installs it and immediately
316
+ re-runs the scaffolding with the new version, instead of asking you to type
317
+ `nib new <project-name>` a second time.
318
+ - **New projects are scaffolded at version `0.0.0`** instead of `1.0.0`, so a
319
+ freshly created site no longer claims a stable public release. Bump it
320
+ yourself as the project grows, and reach `1.0.0` when you go to production.
321
+ - **Framework SCSS imports are now short and readable.** The framework modules
322
+ in `src/frontend/scss/modules/frameworks/` used a five-level relative path
323
+ back to `node_modules`; they now import directly by package name, e.g.
324
+ `@import "bootstrap/scss/card";`. This matches what the styling docs already
325
+ showed, and makes commenting modules out far less error-prone.
326
+ - `nib help` no longer appends an "a newer version is available" line, since it
327
+ no longer performs the check.
328
+
329
+ ### Added
330
+ - Internal `--skip-update-check` flag on `nib new`, set automatically when the
331
+ command is re-run after a self-update. It prevents a loop if the registry is
332
+ slow to propagate the new version.
333
+ - `--load-path=node_modules` on the repository's own `build:css` and `serve:css`
334
+ scripts, so the short framework imports resolve. Generated projects already
335
+ carried this flag.
336
+
337
+ ### Fixed
338
+ - Repaired the ASCII header boxes and the commented-out example import inside
339
+ `_bootstrap.scss`, `_bulma.scss` and `_foundation.scss`, where an earlier
340
+ find-and-replace had injected the `node_modules` path into comment text and
341
+ broken the alignment.
342
+ - `src/frontend/data` is no longer copied to the output folder. It holds the
343
+ Eleventy global data file, which is consumed at build time to render meta
344
+ tags and page config — publishing it produced a dead file in `out/` and
345
+ exposed the full page map, including `noindex` entries. It remains a watch
346
+ target, so edits still trigger a rebuild.
347
+
348
+ ### Notes
349
+ - If the updated installation can't be located after `npm install -g` (an
350
+ unusual `npm root -g` setup, for example), Nibula reports the problem and
351
+ asks you to re-run the command, rather than scaffolding silently with the
352
+ old templates.
353
+ - Existing projects are unaffected by the version change: it applies only to
354
+ newly created ones.
355
+ - Short SCSS imports rely on Sass's `--load-path`, which is passed by the npm
356
+ scripts. Compiling the stylesheets with a different tool (a VS Code Sass
357
+ extension, for instance) will need the same load path configured.
358
+
359
+ ## [1.1.0] - 2026-07-21
360
+
361
+ ### Added
362
+ - **Node.js backend** as an alternative to PHP, living side by side in
363
+ `src/backend/`: `_core/index.js` front controller (which is also the HTTP
364
+ server), `Response` and `RateLimiter` modules, a `mysql2` pool singleton
365
+ `Database.js`, `example.config.js`, and a `package.json` for the backend's
366
+ own dependencies. Same REST API as PHP: routing, `X-Api-Key` auth, CORS and
367
+ file-based rate limiting are identical.
368
+ - **Backend choice at scaffold time**: `nib new` now asks whether to use Node.js
369
+ or PHP, in addition to language and CSS framework.
370
+ - `backend/backend-node.service.example` — a ready-to-adapt **systemd** unit for
371
+ keeping the Node backend running on a server.
372
+ - `config.js` is generated from `example.config.js` at scaffold time (mirroring
373
+ the existing `config.php` generation).
374
+ - Deployment docs now cover running the Node backend with **`screen`** (quick /
375
+ small setups) and **systemd** (production), plus environment variables.
376
+
377
+ ### Changed
378
+ - **Composer is now required only when the PHP backend is chosen.** If you pick
379
+ Node, `composer install` is skipped entirely and the backend's npm
380
+ dependencies (`mysql2`) are installed instead.
381
+ - `.htaccess`, `web.config` and `nginx.conf` now cover **both** backends. On
382
+ nginx, `/api` goes to Node and automatically falls back to the PHP front
383
+ controller when Node is unreachable. On Apache/IIS the active backend is
384
+ selected by configuration (documented), since per-directory configs can't
385
+ health-check an upstream.
386
+ - `.gitignore` now also ignores `src/backend/config.js`,
387
+ `src/backend/node_modules/` and `src/backend/cache/`.
388
+ - Documentation (`README.md`, `docs/Backend.md`, `docs/Deploy.md`) updated:
389
+ backend examples now use JavaScript/Node as the reference, with the equivalent
390
+ PHP shown alongside and a note that PHP behaves identically.
391
+
392
+ ### Notes
393
+ - Both backends are always scaffolded, so you can switch later without
394
+ re-creating the project. The PHP front controller only serves `.php` endpoint
395
+ files and the Node one only `.js`, so they coexist without conflict.