domma-cms 0.38.2 → 0.39.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/CLAUDE.md +20 -110
- package/admin/dist/domma/domma-tools.css +16 -16
- package/admin/dist/domma/domma-tools.min.js +4 -4
- package/admin/index.html +2 -2
- package/admin/js/views/form-editor.js +6 -6
- package/bin/update.js +23 -2
- package/package.json +2 -2
- package/public/css/forms.css +1 -1
- package/public/js/form-logic-engine.js +1 -1
- package/public/js/forms.js +1 -1
- package/public/js/site.js +1 -1
- package/server/templates/page.html +4 -4
package/CLAUDE.md
CHANGED
|
@@ -25,32 +25,9 @@ Domma provides built-in solutions. Never use vanilla JS equivalents.
|
|
|
25
25
|
|
|
26
26
|
## Architecture
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
config.js Config loader: config singleton, getConfig(), saveConfig()
|
|
32
|
-
middleware/auth.js JWT authenticate, requireRole, requireAdmin, canManageUser
|
|
33
|
-
routes/api/ REST API (pages, settings, navigation, media, auth, users, plugins, …)
|
|
34
|
-
routes/public.js Catch-all SSR for public pages; enforces page.visibility
|
|
35
|
-
services/ Core business logic (see Services section below)
|
|
36
|
-
templates/page.html Public page HTML shell ({{headInject}}, {{bodyEndInject}} slots)
|
|
37
|
-
admin/ Domma SPA admin panel (DO NOT modify — upstream-replaced on update)
|
|
38
|
-
public/js/ Public site JS (site.js + component init)
|
|
39
|
-
public/css/ Site stylesheet (site.css is yours to edit)
|
|
40
|
-
bin/ CLI entry point
|
|
41
|
-
scripts/ Setup, reset, seed, fresh, pro, build utilities
|
|
42
|
-
content/pages/ Markdown pages (URL → file mapping below)
|
|
43
|
-
content/media/ Uploaded media
|
|
44
|
-
content/users/ User accounts (JSON)
|
|
45
|
-
content/collections/ Collection entries
|
|
46
|
-
content/blocks/ Reusable content blocks
|
|
47
|
-
content/forms/ Form definitions
|
|
48
|
-
content/versions/ Page version history
|
|
49
|
-
content/custom.css Optional custom CSS (served at /custom.css)
|
|
50
|
-
config/ All configuration JSON (see Config section)
|
|
51
|
-
plugins/ CMS plugins (yours to create/modify)
|
|
52
|
-
docs/ Reference documentation
|
|
53
|
-
```
|
|
28
|
+
**DO NOT modify `server/` or `admin/`** — both are replaced wholesale by the upstream updater.
|
|
29
|
+
Yours to edit: `public/css/site.css`, `content/custom.css`, `plugins/`, and `config/` (see Config
|
|
30
|
+
Reference for which config files the updater merges vs leaves alone).
|
|
54
31
|
|
|
55
32
|
**URL → file mapping:**
|
|
56
33
|
|
|
@@ -76,38 +53,10 @@ Page content here. Shortcodes work anywhere in the body.
|
|
|
76
53
|
|
|
77
54
|
**Page visibility** is enforced server-side in `server/routes/public.js` — unauthenticated users and insufficient role levels receive a 403/redirect.
|
|
78
55
|
|
|
79
|
-
### Shortcodes
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
| `[card]` | Card container (optional title, collapsible, icon) |
|
|
84
|
-
| `[grid cols="N"]` / `[col]` | CSS Grid layout (Domma Grid — NOT `.col` class) |
|
|
85
|
-
| `[row]` / `[col]` | Row/column layout |
|
|
86
|
-
| `[slideover trigger="..." title="..."]` | Slide-over panel |
|
|
87
|
-
| `[dconfig]{...}[/dconfig]` | Declarative page config (JSON) |
|
|
88
|
-
| `[tabs]` / `[tab title="..."]` | Tab panels |
|
|
89
|
-
| `[accordion]` / `[item title="..."]` | Accordion sections |
|
|
90
|
-
| `[carousel]` / `[slide]` | Image/content carousel |
|
|
91
|
-
| `[hero title="..." tagline="..."]` | Hero section |
|
|
92
|
-
| `[table]` | Data table (Markdown table inside) |
|
|
93
|
-
| `[badge variant="..."]` | Badge/label |
|
|
94
|
-
| `[countdown to="..." /]` | Countdown timer |
|
|
95
|
-
| `[timeline]` / `[event]` | Timeline component |
|
|
96
|
-
| `[spacer /]` | Vertical spacer |
|
|
97
|
-
| `[center]` | Centre-align content |
|
|
98
|
-
| `[icon name="..." /]` | Inline icon |
|
|
99
|
-
| `[embed url="..." /]` | Video (YouTube/Vimeo/self-hosted) or iframe embed |
|
|
100
|
-
| `[cta action="..."]` | Collection action trigger (admin) |
|
|
101
|
-
| `[block name="..."]` | Embed a reusable content block |
|
|
102
|
-
| `[view slug="..."]` | Embed a saved view |
|
|
103
|
-
| `[collection slug="..."]` | Render a collection inline |
|
|
104
|
-
| `[text field="..."]` | Output a single text field value |
|
|
105
|
-
| `[button label="..." href="..."]` | Styled button / CTA link |
|
|
106
|
-
| `[link href="..."]` | Styled anchor |
|
|
107
|
-
| `[listgroup]` / `[item]` | List group component |
|
|
108
|
-
| `[form slug="..."]` | Embed a form |
|
|
109
|
-
| `[banner]` | Full-width banner strip |
|
|
110
|
-
| `[celebrate]` | Confetti / effects trigger |
|
|
56
|
+
### Shortcodes
|
|
57
|
+
|
|
58
|
+
~28 shortcode types. **Full list and syntax: `docs/markdown-shortcodes.md`** — read it before writing or
|
|
59
|
+
editing shortcode markup; the nesting rules below are the part the doc does not make obvious.
|
|
111
60
|
|
|
112
61
|
### Shortcode Nesting Rules
|
|
113
62
|
|
|
@@ -140,37 +89,12 @@ Add custom public-site JS to `public/js/site.js` or new files loaded from `publi
|
|
|
140
89
|
|
|
141
90
|
## Core Services (`server/services/`)
|
|
142
91
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
| `userTypes.js` | Role seed, load, invalidate, `getRoleLevel()`, `getPermissionsFor()` |
|
|
150
|
-
| `roles.js` | Role helpers and hierarchy |
|
|
151
|
-
| `userProfiles.js` | User profile CRUD |
|
|
152
|
-
| `permissionRegistry.js` | Central permission map; route guards read this at request time |
|
|
153
|
-
| `rowAccess.js` | Row-level access control for collections |
|
|
154
|
-
| `collections.js` | Collection entry CRUD; delegates I/O to storage adapter |
|
|
155
|
-
| `apiTokens.js` | Project-scoped API tokens (`api-tokens` preset) for the external `/api/v1` surface; SHA-256 hash stored, plaintext shown once |
|
|
156
|
-
| `apiEndpoints.js` | Custom endpoint definitions (`api-endpoints` preset) — registry/matcher/executor for `/api/x/<project><path>` |
|
|
157
|
-
| `adapterRegistry.js` | `getAdapter(slug)` — resolves + caches adapter per collection; `invalidate(slug)` on schema change |
|
|
158
|
-
| `adapters/FileAdapter.js` | Default adapter — plain JSON files |
|
|
159
|
-
| `adapters/MongoAdapter.js` | Optional Pro adapter — native MongoDB driver; `cms_` prefix |
|
|
160
|
-
| `connectionManager.js` | `initialise(cfg)`, `getDb(name)`, `shutdown()` — Mongo connections |
|
|
161
|
-
| `blocks.js` | Reusable block CRUD (`content/blocks/`) |
|
|
162
|
-
| `forms.js` | Form definition CRUD (`content/forms/`) |
|
|
163
|
-
| `views.js` | Saved view CRUD |
|
|
164
|
-
| `versions.js` | Page version history (`content/versions/`) |
|
|
165
|
-
| `actions.js` | Collection action handlers |
|
|
166
|
-
| `hooks.js` | Plugin hook registry (`registerShortcode`, `registerSanitizeRules`, etc.) |
|
|
167
|
-
| `presetCollections.js` | Preset schema seeding and management |
|
|
168
|
-
| `email.js` | SMTP mail sending (uses `config/site.json` SMTP settings) |
|
|
169
|
-
| `images.js` | Image processing / thumbnail generation |
|
|
170
|
-
| `plugins.js` | Plugin discovery, validation, registration, injection snippets |
|
|
171
|
-
| `pluginScaffold.js` | Scaffold new plugins from `plugins/_template` (`POST /api/plugins/scaffold`, pre-enabled, restart to activate) |
|
|
172
|
-
| `pluginFiles.js` | In-admin plugin code editor I/O — list/read/write/delete files confined to `plugins/<name>/`, gated by `plugins.develop` |
|
|
173
|
-
| `cache/index.js` | Pluggable response cache (Memory/None/Redis drivers) with tag-based invalidation. See `docs/cache.md`. |
|
|
92
|
+
Business logic lives in `server/services/` — `ls` it and read the file you need; names are literal
|
|
93
|
+
(`collections.js`, `users.js`, `markdown.js`, `plugins.js`, …). Non-obvious ones:
|
|
94
|
+
|
|
95
|
+
- `permissionRegistry.js` — central permission map; route guards read the **cache at request time**
|
|
96
|
+
- `hooks.js` — plugin hook registry (`registerShortcode`, `registerSanitizeRules`, `registerMenuLocation`, …)
|
|
97
|
+
- `cache/index.js` — pluggable response cache with tag-based invalidation; see `docs/cache.md`
|
|
174
98
|
|
|
175
99
|
## Storage Adapters
|
|
176
100
|
|
|
@@ -198,17 +122,8 @@ Seeded on first run with: `admin`, `manager`, `editor`, `subscriber`.
|
|
|
198
122
|
|
|
199
123
|
## Plugin Development
|
|
200
124
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
```
|
|
204
|
-
plugins/my-plugin/
|
|
205
|
-
plugin.json Required manifest (name, displayName, version, description, author, date, icon)
|
|
206
|
-
plugin.js Default export: Fastify plugin function
|
|
207
|
-
config.js Default export: plain object of config defaults
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
See `docs/plugin-development.md` for full plugin API, hooks, and injection points.
|
|
211
|
-
Each plugin directory has its own `CLAUDE.md` with routes, storage, and gotchas.
|
|
125
|
+
Plugins live in `plugins/<name>/` — see `plugins/CLAUDE.md` (loaded when working there) for the required
|
|
126
|
+
file structure, and `docs/plugin-development.md` for the full API, hooks, and injection points.
|
|
212
127
|
|
|
213
128
|
## Config Reference
|
|
214
129
|
|
|
@@ -290,14 +205,9 @@ The single source of truth is `getProjectForPage(urlPath, frontmatterProject)` i
|
|
|
290
205
|
|
|
291
206
|
**Filtering on list endpoints.** Every artefact list path runs `list.filter(item => canSeeArtefact(user, item))`. Get/write endpoints return 403 when the artefact's project isn't in the user's scope. The Projects section in the admin sidebar always renders — `listProjectsForUser(user)` always includes core, so every site shows at least the Core project.
|
|
292
207
|
|
|
293
|
-
## External API & API tokens
|
|
294
|
-
|
|
295
|
-
Collections are externally consumable at `/api/v1/:slug[/:id]` — a stable alias of `/api/collections/:slug/public[...]` (same handlers). Per-verb access via `schema.api.<verb>.access`: `'public'`, a role name (JWT), or `'token'`. Token mode is **strict** — only a valid `dcms_<64 hex>` Bearer token is accepted (never a JWT), and a token never satisfies a role mode. `schema.api.read.fields` optionally allowlists which `data` fields public/external reads return (admin endpoints unaffected).
|
|
296
|
-
|
|
297
|
-
Tokens live in the `api-tokens` **preset collection** (always file-based and undeletable — both derived automatically from `PRESETS`). Each token is bound to one project (`data.project`, immutable) and only works on collections whose `resolveArtefactProject(schema)` matches; optional `scopes: [{collection, verbs[]}]` narrow it further. Service: `server/services/apiTokens.js` — SHA-256 hash stored, plaintext returned once by `createToken()`, in-memory validate cache invalidated via the `collection:entry*` hooks. Admin routes: `server/routes/api/api-tokens.js` (projects.js DI pattern). Admin UI: System → API Tokens (`admin/js/views/api-tokens.js`). Scaffolder recipes may declare `apiTokens: [{name, scopes?}]` — generated at apply time under the recipe's project, idempotent on re-apply, plaintext surfaced once in `created.apiTokens`.
|
|
298
|
-
|
|
299
|
-
Permission family `api-tokens.{read,create,update,delete}`: custom roles are **not back-filled** (same gotcha as Menus/Projects), but `roles.js seed()` self-heals every BASE role against its seed definition at boot (append-only; root's seed = the full registry, and the base `admin` seed includes `api-tokens` + `api-endpoints` since 0.25.1). A seeded permission removed from a base role is re-added at boot — use a custom role to run with less. `ensureSidebarItem()` in `sidebar-migration.js` appends the System → API Tokens entry on existing installs (no-op when the item's URL already exists anywhere in the persisted menu). Note: `admin/js/views/collection-editor.js` was de-minified (identifiers still mangled) so the API-access tab could gain the Token mode + read-fields input.
|
|
300
|
-
|
|
301
|
-
## Custom API endpoints (API Builder)
|
|
208
|
+
## External API & API tokens, custom API endpoints
|
|
302
209
|
|
|
303
|
-
|
|
210
|
+
The external surface — `/api/v1/:slug` collection access, project-scoped API tokens, and API Builder
|
|
211
|
+
endpoints at `/api/x/<project><path>` — has its own contracts (strict token auth, project binding,
|
|
212
|
+
read-field allowlists, cross-project refusals). Full detail in the **`domma-api-surface` skill**
|
|
213
|
+
(`.claude/skills/domma-api-surface/SKILL.md`) — load it before touching any of that.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Domma Tools CSS v0.
|
|
2
|
+
* Domma Tools CSS v0.39.0
|
|
3
3
|
* Dynamic Object Manipulation & Modeling API
|
|
4
4
|
* (c) 2026 Darryl Waterhouse & DCBW-IT
|
|
5
|
-
* Built: 2026-
|
|
6
|
-
* Commit:
|
|
5
|
+
* Built: 2026-08-09T13:58:02.916Z
|
|
6
|
+
* Commit: 757ca75
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/*!
|
|
@@ -1260,7 +1260,7 @@
|
|
|
1260
1260
|
display: flex;
|
|
1261
1261
|
flex-direction: column;
|
|
1262
1262
|
height: 100%;
|
|
1263
|
-
background: var(--dm-
|
|
1263
|
+
background: var(--dm-background);
|
|
1264
1264
|
color: var(--dm-text);
|
|
1265
1265
|
font-family: var(--dm-font-sans);
|
|
1266
1266
|
border: 1px solid var(--dm-border);
|
|
@@ -1274,7 +1274,7 @@
|
|
|
1274
1274
|
justify-content: space-between;
|
|
1275
1275
|
align-items: center;
|
|
1276
1276
|
padding: 1rem;
|
|
1277
|
-
background: var(--dm-
|
|
1277
|
+
background: var(--dm-surface-secondary);
|
|
1278
1278
|
border-bottom: 1px solid var(--dm-border);
|
|
1279
1279
|
gap: 1rem;
|
|
1280
1280
|
}
|
|
@@ -1301,7 +1301,7 @@
|
|
|
1301
1301
|
padding: 0.5rem;
|
|
1302
1302
|
border: 1px solid var(--dm-border);
|
|
1303
1303
|
border-radius: var(--dm-radius-sm);
|
|
1304
|
-
background: var(--dm-
|
|
1304
|
+
background: var(--dm-background);
|
|
1305
1305
|
color: var(--dm-text);
|
|
1306
1306
|
font-size: 0.875rem;
|
|
1307
1307
|
width: 200px;
|
|
@@ -1498,7 +1498,7 @@
|
|
|
1498
1498
|
|
|
1499
1499
|
/* Field Cards */
|
|
1500
1500
|
.sb-field-card {
|
|
1501
|
-
background: var(--dm-
|
|
1501
|
+
background: var(--dm-surface-secondary);
|
|
1502
1502
|
border: 2px solid var(--dm-border);
|
|
1503
1503
|
border-radius: var(--dm-radius-md);
|
|
1504
1504
|
padding: 1rem;
|
|
@@ -1546,7 +1546,7 @@
|
|
|
1546
1546
|
.sb-field-type {
|
|
1547
1547
|
font-size: 0.75rem;
|
|
1548
1548
|
color: var(--dm-text-secondary);
|
|
1549
|
-
background: var(--dm-
|
|
1549
|
+
background: var(--dm-background);
|
|
1550
1550
|
padding: 0.25rem 0.5rem;
|
|
1551
1551
|
border-radius: var(--dm-radius-sm);
|
|
1552
1552
|
}
|
|
@@ -1583,7 +1583,7 @@
|
|
|
1583
1583
|
.sb-field-controls button {
|
|
1584
1584
|
flex: 1;
|
|
1585
1585
|
padding: 0.25rem 0.5rem;
|
|
1586
|
-
background: var(--dm-
|
|
1586
|
+
background: var(--dm-background);
|
|
1587
1587
|
border: 1px solid var(--dm-border);
|
|
1588
1588
|
border-radius: var(--dm-radius-sm);
|
|
1589
1589
|
color: var(--dm-text);
|
|
@@ -1930,7 +1930,7 @@
|
|
|
1930
1930
|
border-left: 1px solid var(--dm-border);
|
|
1931
1931
|
overflow-y: auto;
|
|
1932
1932
|
padding: 1rem;
|
|
1933
|
-
background: var(--dm-
|
|
1933
|
+
background: var(--dm-background);
|
|
1934
1934
|
}
|
|
1935
1935
|
|
|
1936
1936
|
.sb-state-title {
|
|
@@ -1946,7 +1946,7 @@
|
|
|
1946
1946
|
font-family: var(--dm-font-mono);
|
|
1947
1947
|
font-size: 0.75rem;
|
|
1948
1948
|
color: var(--dm-text);
|
|
1949
|
-
background: var(--dm-
|
|
1949
|
+
background: var(--dm-surface-secondary);
|
|
1950
1950
|
padding: 0.75rem;
|
|
1951
1951
|
border-radius: var(--dm-radius-sm);
|
|
1952
1952
|
overflow-x: auto;
|
|
@@ -1970,7 +1970,7 @@
|
|
|
1970
1970
|
padding: 0.5rem 1rem;
|
|
1971
1971
|
border: 1px solid var(--dm-border);
|
|
1972
1972
|
border-radius: var(--dm-radius-sm);
|
|
1973
|
-
background: var(--dm-
|
|
1973
|
+
background: var(--dm-background);
|
|
1974
1974
|
color: var(--dm-text);
|
|
1975
1975
|
cursor: pointer;
|
|
1976
1976
|
font-size: 0.875rem;
|
|
@@ -2180,7 +2180,7 @@
|
|
|
2180
2180
|
}
|
|
2181
2181
|
|
|
2182
2182
|
.sb-export-output {
|
|
2183
|
-
background: var(--dm-
|
|
2183
|
+
background: var(--dm-surface-secondary);
|
|
2184
2184
|
border: 1px solid var(--dm-border);
|
|
2185
2185
|
border-radius: var(--dm-radius-md);
|
|
2186
2186
|
padding: 1rem;
|
|
@@ -2203,7 +2203,7 @@
|
|
|
2203
2203
|
padding: 1rem;
|
|
2204
2204
|
border: 1px solid var(--dm-border);
|
|
2205
2205
|
border-radius: var(--dm-radius-md);
|
|
2206
|
-
background: var(--dm-
|
|
2206
|
+
background: var(--dm-surface-secondary);
|
|
2207
2207
|
color: var(--dm-text);
|
|
2208
2208
|
font-family: var(--dm-font-mono);
|
|
2209
2209
|
font-size: 0.875rem;
|
|
@@ -2228,7 +2228,7 @@
|
|
|
2228
2228
|
justify-content: space-between;
|
|
2229
2229
|
align-items: center;
|
|
2230
2230
|
padding: 1rem;
|
|
2231
|
-
background: var(--dm-
|
|
2231
|
+
background: var(--dm-surface-secondary);
|
|
2232
2232
|
border: 1px solid var(--dm-border);
|
|
2233
2233
|
border-radius: var(--dm-radius-md);
|
|
2234
2234
|
}
|
|
@@ -2248,7 +2248,7 @@
|
|
|
2248
2248
|
padding: 0.75rem;
|
|
2249
2249
|
border: 1px solid var(--dm-border);
|
|
2250
2250
|
border-radius: var(--dm-radius-sm);
|
|
2251
|
-
background: var(--dm-
|
|
2251
|
+
background: var(--dm-background);
|
|
2252
2252
|
color: var(--dm-text);
|
|
2253
2253
|
font-size: 1rem;
|
|
2254
2254
|
}
|