domma-cms 1.6.60 → 1.7.0
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.
- package/CHANGELOG.md +4344 -0
- package/README.md +1 -1
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/js/lib/effect-defs.js +1 -1
- package/admin/js/lib/effects-builder.js +2 -2
- package/admin/js/lib/page-editor-reference.js +5 -5
- package/admin/js/lib/shortcode-tags.js +1 -1
- package/admin/js/templates/docs/usage-shortcodes.html +39 -0
- package/docs/DommaFeatures.md +3005 -0
- package/docs/MultiTenant.md +176 -0
- package/docs/api-reference.md +1667 -0
- package/docs/cache.md +96 -0
- package/docs/configuration.md +1811 -0
- package/docs/editions-and-licences.md +190 -0
- package/docs/getting-started.md +201 -0
- package/docs/guides/form-triggers.md +260 -0
- package/docs/guides/mongodb-storage-adapter.md +282 -0
- package/docs/guides/multi-page-forms.md +121 -0
- package/docs/images/scribe-composer.png +0 -0
- package/docs/markdown-shortcodes.md +1738 -0
- package/docs/pentest-report-2026-04-03.md +181 -0
- package/docs/plans/2026-02-28-admin-topbar-login-forms.md +349 -0
- package/docs/plans/2026-02-28-domma-ui-polish.md +286 -0
- package/docs/plans/2026-02-28-reset-seed-fresh-commands.md +520 -0
- package/docs/plans/2026-03-02-cookie-consent-design.md +86 -0
- package/docs/plans/2026-03-02-cookie-consent-plugin.md +453 -0
- package/docs/plans/2026-03-02-tooltip-sweep-and-back-to-top-plugin-design.md +126 -0
- package/docs/plans/2026-03-02-tooltip-sweep-back-to-top.md +427 -0
- package/docs/plans/2026-03-05-cookie-consent-btt-core.md +115 -0
- package/docs/plans/2026-03-05-custom-css-migrate-to-core-design.md +35 -0
- package/docs/plans/2026-03-05-custom-css-migrate-to-core.md +352 -0
- package/docs/plans/2026-03-05-scribe-script-shortcode.md +373 -0
- package/docs/plans/2026-03-05-user-types-design.md +139 -0
- package/docs/plans/2026-03-05-user-types-implementation.md +1035 -0
- package/docs/plans/2026-03-09-page-editor-view-cta-inserts-design.md +78 -0
- package/docs/plans/2026-03-09-page-editor-view-cta-inserts.md +388 -0
- package/docs/plans/2026-03-09-pro-documentation-design.md +80 -0
- package/docs/plans/2026-03-09-pro-documentation.md +1017 -0
- package/docs/plans/2026-06-10-core-project-design.md +240 -0
- package/docs/plugin-development.md +827 -0
- package/docs/recruitment-recipe.md +501 -0
- package/docs/scaffolding.md +312 -0
- package/docs/screenshots/calculator-floating.png +0 -0
- package/docs/screenshots/calculator-standard.png +0 -0
- package/docs/screenshots/email-settings.png +0 -0
- package/docs/screenshots/messages-count.png +0 -0
- package/docs/structure/user-types.md +107 -0
- package/docs/superpowers/plans/2026-05-25-admin-sidebar-via-menus.md +1112 -0
- package/docs/superpowers/plans/2026-06-08-navbar-mobile-drawer-and-menu-enrichment.md +1161 -0
- package/docs/superpowers/plans/2026-06-25-domma-docs-project.md +695 -0
- package/docs/superpowers/plans/2026-06-26-surveys-HANDOFF.md +68 -0
- package/docs/superpowers/plans/2026-06-26-surveys-pro-plugin.md +1902 -0
- package/docs/superpowers/plans/2026-08-19-collection-context-sort-export.md +1577 -0
- package/docs/superpowers/plans/2026-10-09-content-api.md +1192 -0
- package/docs/superpowers/specs/2026-03-12-form-followup-actions-design.md +152 -0
- package/docs/superpowers/specs/2026-03-12-page-editor-form-insert-and-per-page-theme-design.md +115 -0
- package/docs/superpowers/specs/2026-03-17-nav-hidden-items-design.md +85 -0
- package/docs/superpowers/specs/2026-03-19-accordion-insert-design.md +175 -0
- package/docs/superpowers/specs/2026-03-25-static-block-shortcode-design.md +153 -0
- package/docs/superpowers/specs/2026-03-25-text-shortcode-design.md +168 -0
- package/docs/superpowers/specs/2026-04-05-card-builder-design.md +315 -0
- package/docs/superpowers/specs/2026-04-06-insert-builders-design.md +278 -0
- package/docs/superpowers/specs/2026-04-06-layouts-design.md +226 -0
- package/docs/superpowers/specs/2026-04-07-blog-plugin-design.md +300 -0
- package/docs/superpowers/specs/2026-04-07-calendar-plugin-design.md +538 -0
- package/docs/superpowers/specs/2026-04-17-components-area-design.md +368 -0
- package/docs/superpowers/specs/2026-05-02-effects-slideover-overhaul-design.md +193 -0
- package/docs/superpowers/specs/2026-05-06-dashboard-rebuild-design.md +257 -0
- package/docs/superpowers/specs/2026-05-24-menus-design.md +466 -0
- package/docs/superpowers/specs/2026-05-25-admin-sidebar-via-menus-design.md +358 -0
- package/docs/superpowers/specs/2026-05-25-projects-design.md +380 -0
- package/docs/superpowers/specs/2026-06-08-navbar-mobile-drawer-and-menu-enrichment-design.md +292 -0
- package/docs/superpowers/specs/2026-06-08-sidebar-tools-plugins-folders-design.md +59 -0
- package/docs/superpowers/specs/2026-06-25-domma-docs-project-design.md +192 -0
- package/docs/superpowers/specs/2026-06-26-domma-charts-upstream-proposal.md +44 -0
- package/docs/superpowers/specs/2026-06-26-manager-scheduler-upstream-proposal.md +46 -0
- package/docs/superpowers/specs/2026-06-26-surveys-pro-plugin-design.md +206 -0
- package/docs/superpowers/specs/2026-07-02-shortcode-context-menu-design.md +96 -0
- package/docs/superpowers/specs/2026-08-19-collection-context-sort-export-design.md +330 -0
- package/docs/superpowers/specs/2026-09-22-dcms-marketplace-design.md +1150 -0
- package/docs/superpowers/specs/2026-10-09-content-api-design.md +325 -0
- package/docs/superpowers/specs/plans/2026-03-12-form-followup-actions.md +624 -0
- package/docs/superpowers/specs/plans/2026-03-12-page-editor-form-insert-and-per-page-theme.md +125 -0
- package/docs/superpowers/specs/plans/2026-03-17-nav-hidden-items.md +578 -0
- package/docs/superpowers/specs/plans/2026-03-19-accordion-insert.md +635 -0
- package/docs/superpowers/specs/plans/2026-03-25-text-shortcode.md +545 -0
- package/docs/superpowers/specs/plans/2026-04-05-card-builder.md +1970 -0
- package/docs/superpowers/specs/plans/2026-04-06-insert-builders.md +1049 -0
- package/docs/superpowers/specs/plans/2026-04-06-layouts.md +1015 -0
- package/docs/superpowers/specs/plans/2026-04-07-calendar-plugin.md +1526 -0
- package/docs/superpowers/specs/plans/2026-04-08-plugin-monetisation-split.md +242 -0
- package/docs/superpowers/specs/plans/2026-04-17-components-area.md +2038 -0
- package/docs/superpowers/specs/plans/2026-05-02-effects-slideover-overhaul.md +2335 -0
- package/docs/superpowers/specs/plans/2026-05-06-dashboard-rebuild.md +1999 -0
- package/docs/superpowers/specs/plans/2026-05-17-cache-system.md +1436 -0
- package/docs/superpowers/specs/plans/2026-05-24-menus.md +3096 -0
- package/docs/superpowers/specs/plans/2026-05-25-projects.md +2869 -0
- package/docs/superpowers/specs/plans/2026-09-22-marketplace-step2-consolidation.md +505 -0
- package/docs/superpowers/specs/plans/2026-09-22-marketplace-step3-catalogue-and-key.md +154 -0
- package/docs/superpowers/specs/plans/2026-09-22-tools-promotion.md +260 -0
- package/docs/theming.md +320 -0
- package/package.json +2 -2
- package/public/js/celebrations/core/canvas.js +1 -1
- package/public/js/celebrations/index.js +1 -1
- package/public/js/celebrations/licenses/ABeeZee-Regular-OFL.txt +93 -0
- package/public/js/celebrations/licenses/Allura-Regular-OFL.txt +93 -0
- package/public/js/celebrations/message-attrs.mjs +1 -0
- package/public/js/celebrations/themes/anniversary.js +1 -0
- package/public/js/celebrations/themes/autumn.js +1 -0
- package/public/js/celebrations/themes/birthday.js +1 -0
- package/public/js/celebrations/themes/butterfly-flight.js +1 -0
- package/public/js/celebrations/themes/calendar.js +1 -0
- package/public/js/celebrations/themes/chinese-new-year-dates.js +1 -0
- package/public/js/celebrations/themes/chinese-new-year.js +1 -0
- package/public/js/celebrations/themes/christmas.js +1 -1
- package/public/js/celebrations/themes/easter.js +1 -0
- package/public/js/celebrations/themes/garden-drawing.js +1 -0
- package/public/js/celebrations/themes/garden.js +1 -0
- package/public/js/celebrations/themes/graduation.js +1 -0
- package/public/js/celebrations/themes/greeting.js +1 -0
- package/public/js/celebrations/themes/make-it-rain.js +1 -0
- package/public/js/celebrations/themes/money-rain.js +1 -0
- package/public/js/celebrations/themes/new-year.js +1 -0
- package/public/js/celebrations/themes/occasion-drawing.js +1 -0
- package/public/js/celebrations/themes/occasions.js +1 -0
- package/public/js/celebrations/themes/rain-control.js +1 -0
- package/public/js/celebrations/themes/sparkler-font-data.js +1 -0
- package/public/js/celebrations/themes/sparkler-font.js +1 -0
- package/public/js/celebrations/themes/sparkler-writing.js +1 -0
- package/public/js/celebrations/themes/summer-garden.js +1 -0
- package/public/js/celebrations/themes/winter.js +1 -0
- package/public/js/celebrations/trait-data.mjs +1 -1
- package/public/js/effects.js +1 -1
- package/scripts/build.js +4 -0
- package/server/services/markdown.js +5 -2
- package/server/templates/page.html +1 -1
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
# Domma Docs Project - Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
>
|
|
5
|
+
> **Commits:** This repo's owner commits separately - do NOT run `git commit`. Where a normal plan would commit, this plan has a **Checkpoint** step: stop, report what changed, and let the owner review/commit.
|
|
6
|
+
>
|
|
7
|
+
> **Environment:** Server is already running on port 4096 and must NOT be killed/restarted. Use `curl` for server-side checks. The owner is on SSH - live browser checks are at `http://192.168.1.4:4096`. Never claim a UI change is "verified" without a real browser load (per project convention).
|
|
8
|
+
|
|
9
|
+
**Goal:** Ship a built-in, disabled-by-default **Domma Docs** project whose pages are the CMS documentation, published on the public site under `/domma-docs/...` and removed from it when the project is toggled off.
|
|
10
|
+
|
|
11
|
+
**Architecture:** A new seeded project (`domma-docs`, `rootUrl: /domma-docs`, `enabled: false`, `protected: true`) reuses the *existing* public kill-switch (`public.js` 404s pages whose project is disabled). The ~30 admin documentation screens are ported into public Markdown pages (bodies lifted verbatim from the admin HTML templates) via a one-shot script, then the admin doc screens are retired.
|
|
12
|
+
|
|
13
|
+
**Tech Stack:** Fastify 5 (ESM), Node built-in test runner (`node --test`), file-based content (Markdown + YAML frontmatter), Domma SPA admin, `marked` + shortcode pipeline.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## File Structure
|
|
18
|
+
|
|
19
|
+
**Modify:**
|
|
20
|
+
- `server/services/projects.js` - add `DOCS_PROJECT_SLUG`, `DOCS_PROJECT_SEED`, `seedDocsProject()`; generalise `deleteProject()` and `untagAllForProject()` to refuse any `protected` project.
|
|
21
|
+
- `server/server.js` - call `seedDocsProject()` after `seedCoreProject()`.
|
|
22
|
+
- `server/routes/api/projects.js` - return 403 on delete/untag-all for `protected` projects.
|
|
23
|
+
- `public/css/site.css` - `.docs-body` styling.
|
|
24
|
+
- `public/js/site.js` - run `Domma.syntax.scan()` on rendered page content.
|
|
25
|
+
- `config/menus/admin-sidebar.json` - remove the hardcoded **Documentation** section.
|
|
26
|
+
- `server/services/sidebar-migration.js` - strip the **Documentation** section from already-seeded installs (idempotent).
|
|
27
|
+
- `admin/js/app.js` - remove the doc/tutorial routes (lines 104-136).
|
|
28
|
+
- `admin/js/views/index.js` - remove the doc view imports/registrations.
|
|
29
|
+
|
|
30
|
+
**Create:**
|
|
31
|
+
- `scripts/migrate-docs.js` - one-shot porter: admin doc templates → public page artefacts.
|
|
32
|
+
- `content/pages/domma-docs/index.md`, `usage/index.md`, `tutorials/index.md`, `api/index.md` - hand-authored landing pages.
|
|
33
|
+
- `content/pages/domma-docs/**` - generated by the migration script.
|
|
34
|
+
|
|
35
|
+
**Delete (Phase 3, after migration runs):**
|
|
36
|
+
- `admin/js/views/documentation.js`, `admin/js/views/tutorials.js`, `admin/js/views/doc-pages.js`
|
|
37
|
+
- `admin/js/templates/docs/*.html`
|
|
38
|
+
|
|
39
|
+
**Test:**
|
|
40
|
+
- `tests/services/projects.test.js` - seed + protected-guard tests.
|
|
41
|
+
- `tests/routes/projects.test.js` - route guard tests.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Phase 0 - The engine (seed + undeletable guards)
|
|
46
|
+
|
|
47
|
+
### Task 1: Seed the Domma Docs project
|
|
48
|
+
|
|
49
|
+
**Files:**
|
|
50
|
+
- Modify: `server/services/projects.js`
|
|
51
|
+
- Test: `tests/services/projects.test.js`
|
|
52
|
+
|
|
53
|
+
- [ ] **Step 1: Write the failing test**
|
|
54
|
+
|
|
55
|
+
Add to `tests/services/projects.test.js` (import `DOCS_PROJECT_SLUG, seedDocsProject` in the existing import block from `../../server/services/projects.js`):
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
test('seedDocsProject - creates a disabled, protected docs project after core', async () => {
|
|
59
|
+
await seedDocsProject();
|
|
60
|
+
await seedDocsProject(); // idempotent
|
|
61
|
+
const docs = await getProject(DOCS_PROJECT_SLUG);
|
|
62
|
+
assert.ok(docs, 'docs project exists');
|
|
63
|
+
assert.equal(docs.slug, 'domma-docs');
|
|
64
|
+
assert.equal(docs.name, 'Domma Docs');
|
|
65
|
+
assert.equal(docs.icon, 'document');
|
|
66
|
+
assert.equal(docs.rootUrl, '/domma-docs');
|
|
67
|
+
assert.equal(docs.enabled, false);
|
|
68
|
+
assert.equal(docs.protected, true);
|
|
69
|
+
|
|
70
|
+
// sortOrder 0 sits immediately after core (-1)
|
|
71
|
+
const all = await listProjects();
|
|
72
|
+
const core = all.findIndex(p => p.slug === CORE_PROJECT_SLUG);
|
|
73
|
+
const di = all.findIndex(p => p.slug === DOCS_PROJECT_SLUG);
|
|
74
|
+
assert.ok(core < di, 'core sorts before docs');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('seedDocsProject - never clobbers an existing record (preserves enabled state)', async () => {
|
|
78
|
+
await seedDocsProject();
|
|
79
|
+
await updateProject(DOCS_PROJECT_SLUG, {enabled: true}); // admin turned it on
|
|
80
|
+
await seedDocsProject(); // reboot
|
|
81
|
+
assert.equal((await getProject(DOCS_PROJECT_SLUG)).enabled, true);
|
|
82
|
+
await updateProject(DOCS_PROJECT_SLUG, {enabled: false}); // reset for other tests
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
87
|
+
|
|
88
|
+
Run: `npm test -- --test-name-pattern="seedDocsProject"`
|
|
89
|
+
Expected: FAIL - `seedDocsProject is not a function` / `is not exported`.
|
|
90
|
+
|
|
91
|
+
- [ ] **Step 3: Write minimal implementation**
|
|
92
|
+
|
|
93
|
+
In `server/services/projects.js`, after the `CORE_PROJECT_SLUG`/`CORE_PROJECT_SEED` block, add:
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
/** Slug of the built-in, disabled-by-default documentation project. */
|
|
97
|
+
export const DOCS_PROJECT_SLUG = 'domma-docs';
|
|
98
|
+
|
|
99
|
+
/** Seed record for the Domma Docs project (created at boot if absent). */
|
|
100
|
+
const DOCS_PROJECT_SEED = {
|
|
101
|
+
slug: DOCS_PROJECT_SLUG,
|
|
102
|
+
name: 'Domma Docs',
|
|
103
|
+
description: 'The Domma CMS handbook - guides, tutorials, component & API ' +
|
|
104
|
+
'reference. Switch on to publish it on your own site.',
|
|
105
|
+
icon: 'document',
|
|
106
|
+
rootUrl: '/domma-docs',
|
|
107
|
+
sortOrder: 0,
|
|
108
|
+
enabled: false,
|
|
109
|
+
protected: true
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Then add the seed function next to `seedCoreProject`:
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
/**
|
|
117
|
+
* Seed the built-in Domma Docs project at boot. Create-if-absent by slug - an
|
|
118
|
+
* existing record (including the admin's enabled/disabled choice and any edits)
|
|
119
|
+
* is returned untouched. Disabled by default: a fresh site ships with the docs
|
|
120
|
+
* off until an admin enables the project.
|
|
121
|
+
*
|
|
122
|
+
* @returns {Promise<object>} The docs project record.
|
|
123
|
+
*/
|
|
124
|
+
export async function seedDocsProject() {
|
|
125
|
+
const {entries} = await listEntries(PROJECTS_COLLECTION_SLUG, {limit: 0});
|
|
126
|
+
const existing = entries.find(e => e.data?.slug === DOCS_PROJECT_SLUG);
|
|
127
|
+
if (existing) return normalise(existing);
|
|
128
|
+
const now = new Date().toISOString();
|
|
129
|
+
const data = {...DOCS_PROJECT_SEED, createdAt: now, updatedAt: now};
|
|
130
|
+
await createEntry(PROJECTS_COLLECTION_SLUG, data);
|
|
131
|
+
return data;
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
136
|
+
|
|
137
|
+
Run: `npm test -- --test-name-pattern="seedDocsProject"`
|
|
138
|
+
Expected: PASS (both tests).
|
|
139
|
+
|
|
140
|
+
- [ ] **Step 5: Checkpoint** - report the new export + tests; pause for owner review.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### Task 2: Make `protected` projects undeletable (service layer)
|
|
145
|
+
|
|
146
|
+
**Files:**
|
|
147
|
+
- Modify: `server/services/projects.js` (`deleteProject`, `untagAllForProject`)
|
|
148
|
+
- Test: `tests/services/projects.test.js`
|
|
149
|
+
|
|
150
|
+
- [ ] **Step 1: Write the failing test**
|
|
151
|
+
|
|
152
|
+
```js
|
|
153
|
+
test('deleteProject - refuses to delete a protected project', async () => {
|
|
154
|
+
await seedDocsProject();
|
|
155
|
+
await assert.rejects(() => deleteProject(DOCS_PROJECT_SLUG), /protected/i);
|
|
156
|
+
assert.ok(await getProject(DOCS_PROJECT_SLUG), 'still present');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('untagAllForProject - refuses a protected project', async () => {
|
|
160
|
+
await seedDocsProject();
|
|
161
|
+
await assert.rejects(() => untagAllForProject(DOCS_PROJECT_SLUG), /protected/i);
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
166
|
+
|
|
167
|
+
Run: `npm test -- --test-name-pattern="protected project"`
|
|
168
|
+
Expected: FAIL - `deleteProject` resolves/deletes instead of rejecting.
|
|
169
|
+
|
|
170
|
+
- [ ] **Step 3: Write minimal implementation**
|
|
171
|
+
|
|
172
|
+
In `deleteProject`, after the entry is found and before `deleteEntry`:
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
const entry = entries.find(e => e.data?.slug === slug);
|
|
176
|
+
if (!entry) return false;
|
|
177
|
+
if (entry.data?.protected === true) {
|
|
178
|
+
throw new Error(`Cannot delete the protected "${slug}" project`);
|
|
179
|
+
}
|
|
180
|
+
await deleteEntry(PROJECTS_COLLECTION_SLUG, entry.id);
|
|
181
|
+
return true;
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
In `untagAllForProject`, right after the existing core check:
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
if (projectSlug === CORE_PROJECT_SLUG) {
|
|
188
|
+
throw new Error('Cannot untag the core project - artefacts would immediately resolve back to it');
|
|
189
|
+
}
|
|
190
|
+
const proj = await getProject(projectSlug);
|
|
191
|
+
if (proj?.protected === true) {
|
|
192
|
+
throw new Error(`Cannot untag the protected "${projectSlug}" project - its pages would resolve back to core`);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
197
|
+
|
|
198
|
+
Run: `npm test -- --test-name-pattern="protected project"`
|
|
199
|
+
Expected: PASS. Also run the full pre-existing core guard test to confirm no regression:
|
|
200
|
+
`npm test -- --test-name-pattern="refuses to delete core"` → PASS.
|
|
201
|
+
|
|
202
|
+
- [ ] **Step 5: Checkpoint** - pause for review.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### Task 3: Route-level guards + boot wiring
|
|
207
|
+
|
|
208
|
+
**Files:**
|
|
209
|
+
- Modify: `server/routes/api/projects.js`
|
|
210
|
+
- Modify: `server/server.js`
|
|
211
|
+
- Test: `tests/routes/projects.test.js`
|
|
212
|
+
|
|
213
|
+
- [ ] **Step 1: Write the failing test**
|
|
214
|
+
|
|
215
|
+
Open `tests/routes/projects.test.js`, mirror its existing app-bootstrap pattern (it already builds a Fastify instance and authenticates an admin). Add:
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
test('DELETE /api/projects/domma-docs → 403 (protected)', async () => {
|
|
219
|
+
const res = await app.inject({
|
|
220
|
+
method: 'DELETE', url: '/api/projects/domma-docs',
|
|
221
|
+
headers: {authorization: `Bearer ${adminToken}`}
|
|
222
|
+
});
|
|
223
|
+
assert.equal(res.statusCode, 403);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test('POST /api/projects/domma-docs/untag-all → 403 (protected)', async () => {
|
|
227
|
+
const res = await app.inject({
|
|
228
|
+
method: 'POST', url: '/api/projects/domma-docs/untag-all',
|
|
229
|
+
headers: {authorization: `Bearer ${adminToken}`}
|
|
230
|
+
});
|
|
231
|
+
assert.equal(res.statusCode, 403);
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
(If the test file's `before` hook does not already seed the docs project, add `await seedDocsProject();` there, importing it from `../../server/services/projects.js`.)
|
|
236
|
+
|
|
237
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
238
|
+
|
|
239
|
+
Run: `npm test -- tests/routes/projects.test.js`
|
|
240
|
+
Expected: FAIL - delete returns 200/409 (or untag returns 200) instead of 403.
|
|
241
|
+
|
|
242
|
+
- [ ] **Step 3: Write minimal implementation**
|
|
243
|
+
|
|
244
|
+
In `server/routes/api/projects.js`, import `getProject` from the service (add to the existing import block). In the `fastify.delete('/projects/:slug', ...)` handler, after the existing core check:
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
if (request.params.slug === CORE_PROJECT_SLUG) {
|
|
248
|
+
return reply.status(403).send({error: 'Cannot delete the core project'});
|
|
249
|
+
}
|
|
250
|
+
const target = await getProject(request.params.slug);
|
|
251
|
+
if (target?.protected === true) {
|
|
252
|
+
return reply.status(403).send({error: 'This project is protected and cannot be deleted'});
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
In the `fastify.post('/projects/:slug/untag-all', ...)` handler, after its core check:
|
|
257
|
+
|
|
258
|
+
```js
|
|
259
|
+
const target = await getProject(request.params.slug);
|
|
260
|
+
if (target?.protected === true) {
|
|
261
|
+
return reply.status(403).send({error: 'This project is protected and cannot be untagged'});
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
In `server/server.js`: extend the existing import to
|
|
266
|
+
`import {seedCoreProject, seedDocsProject} from './services/projects.js';`
|
|
267
|
+
and add immediately after the `await seedCoreProject();` line:
|
|
268
|
+
|
|
269
|
+
```js
|
|
270
|
+
await seedDocsProject();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
274
|
+
|
|
275
|
+
Run: `npm test -- tests/routes/projects.test.js`
|
|
276
|
+
Expected: PASS.
|
|
277
|
+
|
|
278
|
+
- [ ] **Step 5: Verify boot seeds it live**
|
|
279
|
+
|
|
280
|
+
Run: `curl -s localhost:4096/ >/dev/null; ls content/collections/projects/data.json && grep -c '"domma-docs"' content/collections/projects/data.json`
|
|
281
|
+
Expected: `1` (server has restarted via the owner's running process, or seed ran on next boot). If the running server predates the change, note that the seed applies on its next restart - do NOT restart it yourself; report this to the owner.
|
|
282
|
+
|
|
283
|
+
- [ ] **Step 6: Checkpoint** - pause for review.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Phase 1 - Public rendering polish
|
|
288
|
+
|
|
289
|
+
### Task 4: `.docs-body` styling + code highlighting on public pages
|
|
290
|
+
|
|
291
|
+
**Files:**
|
|
292
|
+
- Modify: `public/css/site.css`
|
|
293
|
+
- Modify: `public/js/site.js`
|
|
294
|
+
|
|
295
|
+
- [ ] **Step 1: Add docs styling**
|
|
296
|
+
|
|
297
|
+
Append to `public/css/site.css`:
|
|
298
|
+
|
|
299
|
+
```css
|
|
300
|
+
/* Domma Docs project - ported documentation pages */
|
|
301
|
+
.docs-body { max-width: 60rem; }
|
|
302
|
+
.docs-body h2 { margin-top: 2rem; }
|
|
303
|
+
.docs-body h3 { margin-top: 1.5rem; }
|
|
304
|
+
.docs-body table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
|
|
305
|
+
.docs-body th, .docs-body td { border: 1px solid var(--dm-border, #ddd); padding: .5rem .75rem; text-align: left; }
|
|
306
|
+
.docs-body pre { overflow-x: auto; }
|
|
307
|
+
.docs-body code { font-size: .9em; }
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
- [ ] **Step 2: Add syntax highlighting to the public render path**
|
|
311
|
+
|
|
312
|
+
In `public/js/site.js`, find where page content is scanned for icons after the body renders (search for `Domma.icons.scan();` near line ~304 and the post-fragment rescan near ~704). Immediately after each `Domma.icons.scan(...)` that runs over rendered page content, add:
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
if (typeof Domma !== 'undefined' && Domma.syntax?.scan) Domma.syntax.scan();
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
- [ ] **Step 3: Verify (browser, live)** - deferred until a pilot page exists (Task 6). No standalone check here.
|
|
319
|
+
|
|
320
|
+
- [ ] **Step 4: Checkpoint** - pause for review.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Phase 2 - Content migration
|
|
325
|
+
|
|
326
|
+
### Task 5: The migration script
|
|
327
|
+
|
|
328
|
+
**Files:**
|
|
329
|
+
- Create: `scripts/migrate-docs.js`
|
|
330
|
+
|
|
331
|
+
- [ ] **Step 1: Write the script**
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
/**
|
|
335
|
+
* One-shot porter: admin documentation screens → public page artefacts under
|
|
336
|
+
* the Domma Docs project. Reads each admin HTML template, strips the admin-only
|
|
337
|
+
* view header, wraps the body in page frontmatter tagged `project: domma-docs`,
|
|
338
|
+
* and writes content/pages/domma-docs/<path>.md. Re-runnable (overwrites).
|
|
339
|
+
*
|
|
340
|
+
* Run: node scripts/migrate-docs.js
|
|
341
|
+
*/
|
|
342
|
+
import {mkdirSync, readFileSync, writeFileSync} from 'node:fs';
|
|
343
|
+
import {dirname, join} from 'node:path';
|
|
344
|
+
|
|
345
|
+
const TPL = 'admin/js/templates/docs';
|
|
346
|
+
const OUT = 'content/pages/domma-docs';
|
|
347
|
+
|
|
348
|
+
// template basename → {path (URL tail = file path), title}
|
|
349
|
+
const MAP = [
|
|
350
|
+
['usage-pages', 'usage/pages', 'Pages'],
|
|
351
|
+
['usage-media', 'usage/media', 'Media'],
|
|
352
|
+
['usage-navigation', 'usage/navigation', 'Navigation'],
|
|
353
|
+
['usage-dconfig', 'usage/dconfig', 'DConfig'],
|
|
354
|
+
['usage-shortcodes', 'usage/shortcodes', 'Shortcodes'],
|
|
355
|
+
['usage-site-settings', 'usage/site-settings', 'Site Settings'],
|
|
356
|
+
['usage-plugins', 'usage/plugins', 'Plugins'],
|
|
357
|
+
['usage-users-roles', 'usage/users-roles', 'Users & Roles'],
|
|
358
|
+
['usage-views', 'usage/views', 'Views'],
|
|
359
|
+
['usage-actions', 'usage/actions', 'Actions'],
|
|
360
|
+
['usage-cta-shortcode', 'usage/cta-shortcode', 'CTA Shortcode'],
|
|
361
|
+
['tutorial-crud', 'tutorials/crud', 'Building a CRUD App'],
|
|
362
|
+
['tutorial-plugin', 'tutorials/plugin', 'Writing a Plugin'],
|
|
363
|
+
['tutorial-forms', 'tutorials/forms', 'Form Follow-Up'],
|
|
364
|
+
['components-reference', 'components', 'Components Reference'],
|
|
365
|
+
['components-howto', 'components/howto', 'Components How-To'],
|
|
366
|
+
['components-walkthrough','components/walkthrough','Components Walkthrough'],
|
|
367
|
+
['components-rules', 'components/rules', 'Components Rules'],
|
|
368
|
+
['api-authentication', 'api/authentication', 'Authentication'],
|
|
369
|
+
['api-pages', 'api/pages', 'Pages API'],
|
|
370
|
+
['api-settings', 'api/settings', 'Settings API'],
|
|
371
|
+
['api-layouts', 'api/layouts', 'Layouts API'],
|
|
372
|
+
['api-navigation', 'api/navigation', 'Navigation API'],
|
|
373
|
+
['api-media', 'api/media', 'Media API'],
|
|
374
|
+
['api-users', 'api/users', 'Users API'],
|
|
375
|
+
['api-plugins', 'api/plugins', 'Plugins API'],
|
|
376
|
+
['api-collections', 'api/collections', 'Collections API'],
|
|
377
|
+
['api-views', 'api/views', 'Views API'],
|
|
378
|
+
['api-actions', 'api/actions', 'Actions API']
|
|
379
|
+
];
|
|
380
|
+
|
|
381
|
+
// Drop the admin-only header block (<div class="view-header"> ... </div>).
|
|
382
|
+
// The header contains no nested <div>, so a non-greedy match to the first
|
|
383
|
+
// </div> is correct.
|
|
384
|
+
function stripHeader(html) {
|
|
385
|
+
return html.replace(/<div class="view-header">[\s\S]*?<\/div>\s*/, '');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function frontmatter(title) {
|
|
389
|
+
return `---\ntitle: ${title}\nlayout: default\nvisibility: public\nproject: domma-docs\n---\n\n`;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
let n = 0;
|
|
393
|
+
for (const [tpl, path, title] of MAP) {
|
|
394
|
+
const src = readFileSync(join(TPL, `${tpl}.html`), 'utf8');
|
|
395
|
+
const body = stripHeader(src).trim();
|
|
396
|
+
const dest = join(OUT, `${path}.md`);
|
|
397
|
+
mkdirSync(dirname(dest), {recursive: true});
|
|
398
|
+
writeFileSync(dest, frontmatter(title) + body + '\n');
|
|
399
|
+
n++;
|
|
400
|
+
}
|
|
401
|
+
console.log(`[migrate-docs] wrote ${n} pages to ${OUT}`);
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
- [ ] **Step 2: Run the script**
|
|
405
|
+
|
|
406
|
+
Run: `node scripts/migrate-docs.js`
|
|
407
|
+
Expected: `[migrate-docs] wrote 29 pages to content/pages/domma-docs`
|
|
408
|
+
|
|
409
|
+
- [ ] **Step 3: Spot-check output**
|
|
410
|
+
|
|
411
|
+
Run: `head -8 content/pages/domma-docs/usage/pages.md`
|
|
412
|
+
Expected: frontmatter with `project: domma-docs`, then the page HTML with the `view-header` gone.
|
|
413
|
+
|
|
414
|
+
- [ ] **Step 4: Checkpoint** - pause for review.
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
### Task 6: Hand-authored landing pages
|
|
419
|
+
|
|
420
|
+
**Files:**
|
|
421
|
+
- Create: `content/pages/domma-docs/index.md`, `usage/index.md`, `tutorials/index.md`, `api/index.md`
|
|
422
|
+
|
|
423
|
+
- [ ] **Step 1: Write the top landing page**
|
|
424
|
+
|
|
425
|
+
`content/pages/domma-docs/index.md`:
|
|
426
|
+
|
|
427
|
+
```markdown
|
|
428
|
+
---
|
|
429
|
+
title: Domma Docs
|
|
430
|
+
layout: default
|
|
431
|
+
visibility: public
|
|
432
|
+
project: domma-docs
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
# Domma CMS Documentation
|
|
436
|
+
|
|
437
|
+
[grid cols="2" gap="3"]
|
|
438
|
+
[col][card title="Usage"]Day-to-day guides for pages, media, navigation, shortcodes, plugins and more. [link href="/domma-docs/usage"]Browse usage →[/link][/card][/col]
|
|
439
|
+
[col][card title="Tutorials"]Step-by-step walkthroughs. [link href="/domma-docs/tutorials"]Browse tutorials →[/link][/card][/col]
|
|
440
|
+
[col][card title="Components"]The component reference and how-to. [link href="/domma-docs/components"]Browse components →[/link][/card][/col]
|
|
441
|
+
[col][card title="API Reference"]REST endpoints for headless use. [link href="/domma-docs/api"]Browse the API →[/link][/card][/col]
|
|
442
|
+
[/grid]
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
- [ ] **Step 2: Write the three group landings**
|
|
446
|
+
|
|
447
|
+
`content/pages/domma-docs/usage/index.md` (links to each usage page):
|
|
448
|
+
|
|
449
|
+
```markdown
|
|
450
|
+
---
|
|
451
|
+
title: Usage
|
|
452
|
+
layout: default
|
|
453
|
+
visibility: public
|
|
454
|
+
project: domma-docs
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
# Usage
|
|
458
|
+
|
|
459
|
+
[listgroup]
|
|
460
|
+
[item][link href="/domma-docs/usage/pages"]Pages[/link][/item]
|
|
461
|
+
[item][link href="/domma-docs/usage/media"]Media[/link][/item]
|
|
462
|
+
[item][link href="/domma-docs/usage/navigation"]Navigation[/link][/item]
|
|
463
|
+
[item][link href="/domma-docs/usage/dconfig"]DConfig[/link][/item]
|
|
464
|
+
[item][link href="/domma-docs/usage/shortcodes"]Shortcodes[/link][/item]
|
|
465
|
+
[item][link href="/domma-docs/usage/site-settings"]Site Settings[/link][/item]
|
|
466
|
+
[item][link href="/domma-docs/usage/plugins"]Plugins[/link][/item]
|
|
467
|
+
[item][link href="/domma-docs/usage/users-roles"]Users & Roles[/link][/item]
|
|
468
|
+
[item][link href="/domma-docs/usage/views"]Views[/link][/item]
|
|
469
|
+
[item][link href="/domma-docs/usage/actions"]Actions[/link][/item]
|
|
470
|
+
[item][link href="/domma-docs/usage/cta-shortcode"]CTA Shortcode[/link][/item]
|
|
471
|
+
[/listgroup]
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
`content/pages/domma-docs/tutorials/index.md`:
|
|
475
|
+
|
|
476
|
+
```markdown
|
|
477
|
+
---
|
|
478
|
+
title: Tutorials
|
|
479
|
+
layout: default
|
|
480
|
+
visibility: public
|
|
481
|
+
project: domma-docs
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
# Tutorials
|
|
485
|
+
|
|
486
|
+
[listgroup]
|
|
487
|
+
[item][link href="/domma-docs/tutorials/crud"]Building a CRUD App[/link][/item]
|
|
488
|
+
[item][link href="/domma-docs/tutorials/plugin"]Writing a Plugin[/link][/item]
|
|
489
|
+
[item][link href="/domma-docs/tutorials/forms"]Form Follow-Up[/link][/item]
|
|
490
|
+
[/listgroup]
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
`content/pages/domma-docs/api/index.md`:
|
|
494
|
+
|
|
495
|
+
```markdown
|
|
496
|
+
---
|
|
497
|
+
title: API Reference
|
|
498
|
+
layout: default
|
|
499
|
+
visibility: public
|
|
500
|
+
project: domma-docs
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
# API Reference
|
|
504
|
+
|
|
505
|
+
[listgroup]
|
|
506
|
+
[item][link href="/domma-docs/api/authentication"]Authentication[/link][/item]
|
|
507
|
+
[item][link href="/domma-docs/api/pages"]Pages[/link][/item]
|
|
508
|
+
[item][link href="/domma-docs/api/settings"]Settings[/link][/item]
|
|
509
|
+
[item][link href="/domma-docs/api/layouts"]Layouts[/link][/item]
|
|
510
|
+
[item][link href="/domma-docs/api/navigation"]Navigation[/link][/item]
|
|
511
|
+
[item][link href="/domma-docs/api/media"]Media[/link][/item]
|
|
512
|
+
[item][link href="/domma-docs/api/users"]Users[/link][/item]
|
|
513
|
+
[item][link href="/domma-docs/api/plugins"]Plugins[/link][/item]
|
|
514
|
+
[item][link href="/domma-docs/api/collections"]Collections[/link][/item]
|
|
515
|
+
[item][link href="/domma-docs/api/views"]Views[/link][/item]
|
|
516
|
+
[item][link href="/domma-docs/api/actions"]Actions[/link][/item]
|
|
517
|
+
[/listgroup]
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
- [ ] **Step 3: Checkpoint** - pause for review.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
### Task 7: Live end-to-end verification of the toggle + pilot pages
|
|
525
|
+
|
|
526
|
+
**Files:** none (verification only). Requires the owner's running server to have picked up the Phase 0 boot change. If it has not restarted, ask the owner to confirm a restart before this task - do not restart it yourself.
|
|
527
|
+
|
|
528
|
+
- [ ] **Step 1: Confirm disabled ⇒ 404 (kill-switch)**
|
|
529
|
+
|
|
530
|
+
With Domma Docs disabled (default), run:
|
|
531
|
+
```
|
|
532
|
+
curl -s -o /dev/null -w "%{http_code}\n" localhost:4096/domma-docs
|
|
533
|
+
curl -s -o /dev/null -w "%{http_code}\n" localhost:4096/domma-docs/usage/shortcodes
|
|
534
|
+
```
|
|
535
|
+
Expected: `404` for both.
|
|
536
|
+
|
|
537
|
+
- [ ] **Step 2: Enable the project**
|
|
538
|
+
|
|
539
|
+
Via the admin Projects UI (or API): set `domma-docs` `enabled: true`. Confirm:
|
|
540
|
+
`curl -s localhost:4096/api/projects | grep -o '"domma-docs"[^}]*"enabled":true' | head -1` → a match.
|
|
541
|
+
|
|
542
|
+
- [ ] **Step 3: Confirm enabled ⇒ 200 + content**
|
|
543
|
+
|
|
544
|
+
```
|
|
545
|
+
curl -s -o /dev/null -w "%{http_code}\n" localhost:4096/domma-docs
|
|
546
|
+
curl -s localhost:4096/domma-docs/usage/shortcodes | grep -c "docs-body"
|
|
547
|
+
```
|
|
548
|
+
Expected: `200`, and the shortcodes page contains `docs-body`.
|
|
549
|
+
|
|
550
|
+
- [ ] **Step 4: Browser fidelity check (pilot pages)** - load in a real browser at `http://192.168.1.4:4096`:
|
|
551
|
+
- `/domma-docs` - landing card grid renders.
|
|
552
|
+
- `/domma-docs/usage/shortcodes` - **critical**: confirm the `[card]`/`[grid]` examples render as *literal code*, not expanded components (validates `scrubCodeRegions` over the ported `<pre>` blocks). Confirm code blocks are syntax-highlighted and icons render.
|
|
553
|
+
- `/domma-docs/api/collections` - tables render with `.docs-body` styling.
|
|
554
|
+
|
|
555
|
+
Report findings explicitly. If any shortcode example is wrongly expanded, fix by escaping brackets within `<pre>` in `scripts/migrate-docs.js` (replace `[` → `[` inside `<pre>…</pre>` regions) and re-run the script.
|
|
556
|
+
|
|
557
|
+
- [ ] **Step 5: Confirm disabling re-hides**
|
|
558
|
+
|
|
559
|
+
Set `domma-docs` `enabled: false`, then repeat Step 1 → expect `404`. Leave it disabled (the default).
|
|
560
|
+
|
|
561
|
+
- [ ] **Step 6: Checkpoint** - report the full enabled/disabled matrix; pause for review.
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## Phase 3 - Retire the admin documentation screens
|
|
566
|
+
|
|
567
|
+
> Only after Task 7 passes - the migration script reads the admin templates, so they must survive until the pages are generated and verified.
|
|
568
|
+
|
|
569
|
+
### Task 8: Remove the admin Documentation menu section
|
|
570
|
+
|
|
571
|
+
**Files:**
|
|
572
|
+
- Modify: `config/menus/admin-sidebar.json`
|
|
573
|
+
- Modify: `server/services/sidebar-migration.js`
|
|
574
|
+
- Test: `tests/services/sidebar-migration.test.js`
|
|
575
|
+
|
|
576
|
+
- [ ] **Step 1: Write the failing test**
|
|
577
|
+
|
|
578
|
+
In `tests/services/sidebar-migration.test.js`, add a test that the migration removes a top-level item whose `text` is `Documentation`. Mirror the file's existing helper for building a menu fixture and invoking the migration. Example shape:
|
|
579
|
+
|
|
580
|
+
```js
|
|
581
|
+
test('migration strips the legacy Documentation section', async () => {
|
|
582
|
+
const menu = {slug: 'admin-sidebar', items: [
|
|
583
|
+
{text: 'Overview', items: []},
|
|
584
|
+
{text: 'Documentation', items: [{text: 'Usage', items: []}]}
|
|
585
|
+
]};
|
|
586
|
+
const out = stripDocumentationSection(menu); // new export
|
|
587
|
+
assert.equal(out.items.some(i => i.text === 'Documentation'), false);
|
|
588
|
+
// idempotent
|
|
589
|
+
assert.deepEqual(stripDocumentationSection(out), out);
|
|
590
|
+
});
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
- [ ] **Step 2: Run test to verify it fails**
|
|
594
|
+
|
|
595
|
+
Run: `npm test -- tests/services/sidebar-migration.test.js`
|
|
596
|
+
Expected: FAIL - `stripDocumentationSection is not exported`.
|
|
597
|
+
|
|
598
|
+
- [ ] **Step 3: Implement + wire**
|
|
599
|
+
|
|
600
|
+
In `server/services/sidebar-migration.js` add and export:
|
|
601
|
+
|
|
602
|
+
```js
|
|
603
|
+
/**
|
|
604
|
+
* Remove the legacy top-level "Documentation" section from a persisted
|
|
605
|
+
* admin-sidebar menu. The docs now live as the Domma Docs project's pages.
|
|
606
|
+
* Idempotent; returns the (possibly unchanged) menu object.
|
|
607
|
+
*
|
|
608
|
+
* @param {{items?: Array<object>}} menu
|
|
609
|
+
* @returns {object}
|
|
610
|
+
*/
|
|
611
|
+
export function stripDocumentationSection(menu) {
|
|
612
|
+
if (!menu || !Array.isArray(menu.items)) return menu;
|
|
613
|
+
const items = menu.items.filter(i => (i?.text || '') !== 'Documentation');
|
|
614
|
+
return items.length === menu.items.length ? menu : {...menu, items};
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Call it in the same place the existing sidebar migrations run at boot (follow the pattern of `ensureSidebarItem`/the migration entry point already in this file): load the `admin-sidebar` menu, apply `stripDocumentationSection`, and persist only if changed.
|
|
619
|
+
|
|
620
|
+
Then remove the `Documentation` object from `config/menus/admin-sidebar.json` (this install's live menu) so fresh boots never seed it.
|
|
621
|
+
|
|
622
|
+
- [ ] **Step 4: Run test to verify it passes**
|
|
623
|
+
|
|
624
|
+
Run: `npm test -- tests/services/sidebar-migration.test.js`
|
|
625
|
+
Expected: PASS.
|
|
626
|
+
|
|
627
|
+
- [ ] **Step 5: Browser check** - load the admin at `http://192.168.1.4:4096/admin` in a real browser; confirm the **Documentation** section is gone from the sidebar and the **Projects** section still renders. Report explicitly.
|
|
628
|
+
|
|
629
|
+
- [ ] **Step 6: Checkpoint** - pause for review.
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
### Task 9: Remove the admin doc routes + views
|
|
634
|
+
|
|
635
|
+
**Files:**
|
|
636
|
+
- Modify: `admin/js/app.js` (remove lines 104-136 - the `/documentation`, `/tutorials*`, `/docs/*` route entries)
|
|
637
|
+
- Modify: `admin/js/views/index.js` (remove imports at lines 21-23 and registrations `documentation:`, `tutorials:`, `...docViews`)
|
|
638
|
+
- Delete: `admin/js/views/documentation.js`, `admin/js/views/tutorials.js`, `admin/js/views/doc-pages.js`
|
|
639
|
+
- Delete: `admin/js/templates/docs/*.html`
|
|
640
|
+
|
|
641
|
+
- [ ] **Step 1: Remove the route block** in `admin/js/app.js` - delete every route object from `{path: '/documentation', ...}` through `{path: '/docs/api/actions', ...}` inclusive. Confirm none remain:
|
|
642
|
+
|
|
643
|
+
Run: `grep -cE "path: '/(docs|tutorials|documentation)" admin/js/app.js`
|
|
644
|
+
Expected: `0`
|
|
645
|
+
|
|
646
|
+
- [ ] **Step 2: Remove the view registrations** in `admin/js/views/index.js` - delete the three imports (`documentationView`, `tutorialsView`, `docViews`) and the three registry lines (`documentation:`, `tutorials:`, `...docViews`). Confirm:
|
|
647
|
+
|
|
648
|
+
Run: `grep -cE "documentationView|tutorialsView|docViews" admin/js/views/index.js`
|
|
649
|
+
Expected: `0`
|
|
650
|
+
|
|
651
|
+
- [ ] **Step 3: Delete the now-orphaned files**
|
|
652
|
+
|
|
653
|
+
Run:
|
|
654
|
+
```
|
|
655
|
+
rm admin/js/views/documentation.js admin/js/views/tutorials.js admin/js/views/doc-pages.js
|
|
656
|
+
rm -r admin/js/templates/docs
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
- [ ] **Step 4: Verify no dangling references**
|
|
660
|
+
|
|
661
|
+
Run: `grep -rnE "doc-pages|templates/docs|tutorialsView|documentationView|docViews|crud-tutorial" admin/js | grep -v "node_modules"`
|
|
662
|
+
Expected: no matches (the `crud-tutorial.js` lib import lived only in `doc-pages.js`; if `crud-tutorial.js` is now unreferenced, delete it too and re-run).
|
|
663
|
+
|
|
664
|
+
- [ ] **Step 5: Browser smoke test** - load `http://192.168.1.4:4096/admin`, navigate a few sections (Dashboard, Pages, Projects). Confirm no console errors from the removed views and that visiting an old hash like `#/docs/usage/pages` lands on the SPA's not-found/route-miss handling rather than throwing. Report explicitly.
|
|
665
|
+
|
|
666
|
+
- [ ] **Step 6: Checkpoint** - pause for review.
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
## Final verification
|
|
671
|
+
|
|
672
|
+
- [ ] **Full test suite**
|
|
673
|
+
|
|
674
|
+
Run: `npm test`
|
|
675
|
+
Expected: all pass (note any pre-existing unrelated failures separately).
|
|
676
|
+
|
|
677
|
+
- [ ] **End-to-end matrix (browser, live `http://192.168.1.4:4096`)** - report each explicitly:
|
|
678
|
+
- Domma Docs **disabled** (default): `/domma-docs/*` → 404; admin sidebar has **no** Documentation section; Projects section present.
|
|
679
|
+
- Domma Docs **enabled**: `/domma-docs` + a usage/api/tutorial page render with styling, highlighting, icons; shortcode examples on the shortcodes page are literal; admin Projects sidebar shows **Domma Docs** with a `Pages (N)` child; the project's delete control is disabled.
|
|
680
|
+
- Toggle back to **disabled**: pages 404 again.
|
|
681
|
+
|
|
682
|
+
- [ ] **Hand off to owner for commit** (this repo's owner commits).
|
|
683
|
+
|
|
684
|
+
---
|
|
685
|
+
|
|
686
|
+
## Spec coverage check
|
|
687
|
+
|
|
688
|
+
- Seed project (slug/name/icon/rootUrl/sortOrder/disabled/protected) → Task 1 ✓
|
|
689
|
+
- Undeletable, toggleable, rootUrl editable (not Core's locks) → Tasks 2-3 ✓
|
|
690
|
+
- Docs as public pages tagged `project: domma-docs`, bodies lifted from templates → Tasks 5-6 ✓
|
|
691
|
+
- Public `.docs-body` CSS + code highlighting → Task 4 ✓
|
|
692
|
+
- Kill-switch (disabled ⇒ 404) reused, not rebuilt → verified Task 7 ✓
|
|
693
|
+
- Retire admin Documentation section/routes/views/templates → Tasks 8-9 ✓
|
|
694
|
+
- Caveat: interactive CRUD scaffolder degrades to static → inherent in Task 5 (no scaffolder mount on public page); confirmed at Task 7 Step 4 ✓
|
|
695
|
+
- Caveat: shortcode examples must stay literal → Task 7 Step 4 explicit check + escape fallback ✓
|