domma-cms 0.9.6 → 0.9.10
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/admin/js/app.js +2 -2
- package/admin/js/lib/card-builder.js +7 -0
- package/admin/js/templates/api-reference.html +943 -1107
- package/admin/js/templates/documentation.html +828 -655
- package/admin/js/templates/tutorials.html +202 -177
- package/admin/js/views/api-reference.js +1 -1
- package/admin/js/views/documentation.js +1 -1
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/page-editor.js +4 -4
- package/admin/js/views/tutorials.js +1 -1
- package/config/site.json +1 -1
- package/package.json +1 -1
- package/plugins/notes/admin/views/notes.js +24 -26
- package/plugins/todo/admin/views/todo.js +32 -34
- package/public/css/site.css +1 -1
- package/server/services/markdown.js +609 -79
|
@@ -75,185 +75,197 @@
|
|
|
75
75
|
<code>Authorization</code> header unless noted otherwise. Content type for request bodies is
|
|
76
76
|
<code>application/json</code>. Tokens are obtained via <code>POST /api/auth/login</code>.
|
|
77
77
|
</p>
|
|
78
|
-
|
|
79
|
-
Base URL: <code>http://your-domain/api</code>
|
|
80
|
-
</p>
|
|
78
|
+
<p>Base URL: <code>http://your-domain/api</code></p>
|
|
81
79
|
</div>
|
|
82
80
|
</div>
|
|
83
81
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
<div class="tabs" id="api-tabs">
|
|
83
|
+
<div class="tab-list" style="flex-wrap: wrap;">
|
|
84
|
+
<button class="tab-item active">Authentication</button>
|
|
85
|
+
<button class="tab-item">Pages</button>
|
|
86
|
+
<button class="tab-item">Settings</button>
|
|
87
|
+
<button class="tab-item">Layouts</button>
|
|
88
|
+
<button class="tab-item">Navigation</button>
|
|
89
|
+
<button class="tab-item">Media</button>
|
|
90
|
+
<button class="tab-item">Users</button>
|
|
91
|
+
<button class="tab-item">Plugins</button>
|
|
92
|
+
<button class="tab-item">Collections</button>
|
|
93
|
+
<button class="tab-item">Views API</button>
|
|
94
|
+
<button class="tab-item">Actions API</button>
|
|
89
95
|
</div>
|
|
90
|
-
|
|
96
|
+
<div class="tab-content">
|
|
97
|
+
|
|
98
|
+
<!-- Authentication -->
|
|
99
|
+
<div class="tab-panel active docs-body">
|
|
91
100
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
<h3><span class="method-badge method-get">GET</span><span
|
|
102
|
+
class="endpoint-path">/api/auth/setup-status</span></h3>
|
|
103
|
+
<p class="auth-note">No authentication required.</p>
|
|
104
|
+
<p>Check whether the CMS has been set up. Returns <code>{ needsSetup: true }</code> when no users
|
|
105
|
+
exist.</p>
|
|
106
|
+
<pre class="code-block"><code>// Response
|
|
97
107
|
{ "needsSetup": false }</code></pre>
|
|
98
108
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
109
|
+
<h3><span class="method-badge method-post">POST</span><span
|
|
110
|
+
class="endpoint-path">/api/auth/setup</span></h3>
|
|
111
|
+
<p class="auth-note">No authentication required. Only succeeds when zero users exist.</p>
|
|
112
|
+
<p>Create the initial admin account. Blocked once any user exists (returns 403).</p>
|
|
113
|
+
<table class="table table-sm">
|
|
114
|
+
<thead>
|
|
115
|
+
<tr>
|
|
116
|
+
<th>Field</th>
|
|
117
|
+
<th>Type</th>
|
|
118
|
+
<th>Description</th>
|
|
119
|
+
</tr>
|
|
120
|
+
</thead>
|
|
121
|
+
<tbody>
|
|
122
|
+
<tr>
|
|
123
|
+
<td><code>name</code></td>
|
|
124
|
+
<td>string</td>
|
|
125
|
+
<td>Display name</td>
|
|
126
|
+
</tr>
|
|
127
|
+
<tr>
|
|
128
|
+
<td><code>email</code></td>
|
|
129
|
+
<td>string</td>
|
|
130
|
+
<td>Email address</td>
|
|
131
|
+
</tr>
|
|
132
|
+
<tr>
|
|
133
|
+
<td><code>password</code></td>
|
|
134
|
+
<td>string</td>
|
|
135
|
+
<td>Minimum 8 characters</td>
|
|
136
|
+
</tr>
|
|
137
|
+
</tbody>
|
|
138
|
+
</table>
|
|
139
|
+
<pre class="code-block"><code>// Response 201
|
|
129
140
|
{ "token": "eyJ...", "refreshToken": "eyJ...", "user": { "id": "...", "name": "...", "email": "...", "role": "admin" } }</code></pre>
|
|
130
141
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
142
|
+
<h3><span class="method-badge method-post">POST</span><span
|
|
143
|
+
class="endpoint-path">/api/auth/login</span></h3>
|
|
144
|
+
<p class="auth-note">No authentication required.</p>
|
|
145
|
+
<p>Authenticate with email and password. Returns access and refresh tokens.</p>
|
|
146
|
+
<table class="table table-sm">
|
|
147
|
+
<thead>
|
|
148
|
+
<tr>
|
|
149
|
+
<th>Field</th>
|
|
150
|
+
<th>Type</th>
|
|
151
|
+
<th>Description</th>
|
|
152
|
+
</tr>
|
|
153
|
+
</thead>
|
|
154
|
+
<tbody>
|
|
155
|
+
<tr>
|
|
156
|
+
<td><code>email</code></td>
|
|
157
|
+
<td>string</td>
|
|
158
|
+
<td>User email</td>
|
|
159
|
+
</tr>
|
|
160
|
+
<tr>
|
|
161
|
+
<td><code>password</code></td>
|
|
162
|
+
<td>string</td>
|
|
163
|
+
<td>User password</td>
|
|
164
|
+
</tr>
|
|
165
|
+
</tbody>
|
|
166
|
+
</table>
|
|
167
|
+
<pre class="code-block"><code>// Response 200
|
|
156
168
|
{ "token": "eyJ...", "refreshToken": "eyJ...", "user": { "id": "uuid", "name": "Alice", "email": "alice@example.com", "role": "admin" } }
|
|
157
169
|
|
|
158
170
|
// Error 401
|
|
159
171
|
{ "error": "Invalid credentials" }</code></pre>
|
|
160
172
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
173
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/auth/me</span>
|
|
174
|
+
</h3>
|
|
175
|
+
<p class="auth-note">Requires Bearer token.</p>
|
|
176
|
+
<p>Return the authenticated user's profile.</p>
|
|
177
|
+
<pre class="code-block"><code>// Response 200
|
|
165
178
|
{ "id": "uuid", "name": "Alice", "email": "alice@example.com", "role": "admin", "isActive": true }</code></pre>
|
|
166
179
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
<h3><span class="method-badge method-post">POST</span><span
|
|
181
|
+
class="endpoint-path">/api/auth/logout</span></h3>
|
|
182
|
+
<p class="auth-note">No authentication required. Safe to call without a token.</p>
|
|
183
|
+
<p>Blacklists the provided refresh token. The in-memory blacklist is cleared on server restart.</p>
|
|
184
|
+
<table class="table table-sm">
|
|
185
|
+
<thead>
|
|
186
|
+
<tr>
|
|
187
|
+
<th>Field</th>
|
|
188
|
+
<th>Type</th>
|
|
189
|
+
<th>Description</th>
|
|
190
|
+
</tr>
|
|
191
|
+
</thead>
|
|
192
|
+
<tbody>
|
|
193
|
+
<tr>
|
|
194
|
+
<td><code>refreshToken</code></td>
|
|
195
|
+
<td>string</td>
|
|
196
|
+
<td>The refresh token to revoke (optional)</td>
|
|
197
|
+
</tr>
|
|
198
|
+
</tbody>
|
|
199
|
+
</table>
|
|
200
|
+
<pre class="code-block"><code>// Response 200
|
|
187
201
|
{ "ok": true }</code></pre>
|
|
188
202
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
<h3><span class="method-badge method-post">POST</span><span
|
|
204
|
+
class="endpoint-path">/api/auth/refresh</span></h3>
|
|
205
|
+
<p class="auth-note">No authentication required. Provide a valid refresh token.</p>
|
|
206
|
+
<p>Exchange a refresh token for a new access token.</p>
|
|
207
|
+
<table class="table table-sm">
|
|
208
|
+
<thead>
|
|
209
|
+
<tr>
|
|
210
|
+
<th>Field</th>
|
|
211
|
+
<th>Type</th>
|
|
212
|
+
<th>Description</th>
|
|
213
|
+
</tr>
|
|
214
|
+
</thead>
|
|
215
|
+
<tbody>
|
|
216
|
+
<tr>
|
|
217
|
+
<td><code>refreshToken</code></td>
|
|
218
|
+
<td>string</td>
|
|
219
|
+
<td>A valid, non-revoked refresh token</td>
|
|
220
|
+
</tr>
|
|
221
|
+
</tbody>
|
|
222
|
+
</table>
|
|
223
|
+
<pre class="code-block"><code>// Response 200
|
|
209
224
|
{ "token": "eyJ..." }
|
|
210
225
|
|
|
211
226
|
// Error 401
|
|
212
227
|
{ "error": "Invalid or expired refresh token" }</code></pre>
|
|
213
228
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
</tr>
|
|
242
|
-
</tbody>
|
|
243
|
-
</table>
|
|
244
|
-
<pre class="code-block"><code>// Response 200
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
<!-- Pages -->
|
|
232
|
+
<div class="tab-panel docs-body">
|
|
233
|
+
|
|
234
|
+
<h3><span class="method-badge method-post">POST</span><span
|
|
235
|
+
class="endpoint-path">/api/pages/preview</span></h3>
|
|
236
|
+
<p class="auth-note">Requires Bearer token + <code>pages</code> permission.</p>
|
|
237
|
+
<p>Render Markdown to HTML (shortcodes processed, no frontmatter). Useful for live editor
|
|
238
|
+
previews.</p>
|
|
239
|
+
<table class="table table-sm">
|
|
240
|
+
<thead>
|
|
241
|
+
<tr>
|
|
242
|
+
<th>Field</th>
|
|
243
|
+
<th>Type</th>
|
|
244
|
+
<th>Description</th>
|
|
245
|
+
</tr>
|
|
246
|
+
</thead>
|
|
247
|
+
<tbody>
|
|
248
|
+
<tr>
|
|
249
|
+
<td><code>markdown</code></td>
|
|
250
|
+
<td>string</td>
|
|
251
|
+
<td>Markdown string to render</td>
|
|
252
|
+
</tr>
|
|
253
|
+
</tbody>
|
|
254
|
+
</table>
|
|
255
|
+
<pre class="code-block"><code>// Response 200
|
|
245
256
|
{ "html": "<p>Hello <strong>world</strong></p>" }</code></pre>
|
|
246
257
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
258
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/pages/tags</span>
|
|
259
|
+
</h3>
|
|
260
|
+
<p class="auth-note">Requires Bearer token + <code>pages</code> permission.</p>
|
|
261
|
+
<p>Aggregate all unique tags across every page, sorted alphabetically.</p>
|
|
262
|
+
<pre class="code-block"><code>// Response 200
|
|
251
263
|
{ "tags": ["guide", "news", "tutorial"] }</code></pre>
|
|
252
264
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
265
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/pages</span></h3>
|
|
266
|
+
<p class="auth-note">Requires Bearer token + <code>pages</code> permission.</p>
|
|
267
|
+
<p>List all pages with their metadata. Body content is excluded.</p>
|
|
268
|
+
<pre class="code-block"><code>// Response 200
|
|
257
269
|
[
|
|
258
270
|
{
|
|
259
271
|
"urlPath": "/about",
|
|
@@ -261,94 +273,87 @@
|
|
|
261
273
|
"slug": "about",
|
|
262
274
|
"status": "published",
|
|
263
275
|
"layout": "default",
|
|
264
|
-
"showInNav": true,
|
|
265
|
-
"sortOrder": 1,
|
|
266
|
-
"category": null,
|
|
267
|
-
"visibility": "public",
|
|
268
276
|
"tags": [],
|
|
269
277
|
"updatedAt": "2024-01-15T10:30:00.000Z",
|
|
270
278
|
"createdAt": "2024-01-01T09:00:00.000Z"
|
|
271
279
|
}
|
|
272
280
|
]</code></pre>
|
|
273
281
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
"body": "## Our Story\n\nWe started...",
|
|
283
|
-
"status": "published",
|
|
284
|
-
...
|
|
285
|
-
}
|
|
282
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/pages/*</span>
|
|
283
|
+
</h3>
|
|
284
|
+
<p class="auth-note">Requires Bearer token + <code>pages</code> permission. The <code>*</code> is the
|
|
285
|
+
URL path,
|
|
286
|
+
e.g. <code>/api/pages/about</code>.</p>
|
|
287
|
+
<p>Retrieve a single page including its frontmatter and full body content.</p>
|
|
288
|
+
<pre class="code-block"><code>// Response 200
|
|
289
|
+
{ "urlPath": "/about", "title": "About Us", "body": "## Our Story\n\nWe started...", ... }
|
|
286
290
|
|
|
287
291
|
// Error 404
|
|
288
292
|
{ "error": "Page not found" }</code></pre>
|
|
289
293
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
294
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/pages</span>
|
|
295
|
+
</h3>
|
|
296
|
+
<p class="auth-note">Requires Bearer token + <code>pages</code> permission.</p>
|
|
297
|
+
<p>Create a new page. Fails with 409 if a page already exists at the given path.</p>
|
|
298
|
+
<table class="table table-sm">
|
|
299
|
+
<thead>
|
|
300
|
+
<tr>
|
|
301
|
+
<th>Field</th>
|
|
302
|
+
<th>Type</th>
|
|
303
|
+
<th>Description</th>
|
|
304
|
+
</tr>
|
|
305
|
+
</thead>
|
|
306
|
+
<tbody>
|
|
307
|
+
<tr>
|
|
308
|
+
<td><code>urlPath</code></td>
|
|
309
|
+
<td>string</td>
|
|
310
|
+
<td>Required. Public URL path e.g. <code>/about</code></td>
|
|
311
|
+
</tr>
|
|
312
|
+
<tr>
|
|
313
|
+
<td><code>frontmatter</code></td>
|
|
314
|
+
<td>object</td>
|
|
315
|
+
<td>YAML frontmatter fields (title, status, etc.)</td>
|
|
316
|
+
</tr>
|
|
317
|
+
<tr>
|
|
318
|
+
<td><code>body</code></td>
|
|
319
|
+
<td>string</td>
|
|
320
|
+
<td>Markdown content</td>
|
|
321
|
+
</tr>
|
|
322
|
+
</tbody>
|
|
323
|
+
</table>
|
|
324
|
+
<pre class="code-block"><code>// Response 201 — returns the created page object</code></pre>
|
|
325
|
+
|
|
326
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/pages/*</span>
|
|
327
|
+
</h3>
|
|
328
|
+
<p class="auth-note">Requires Bearer token + <code>pages</code> permission.</p>
|
|
329
|
+
<p>Update an existing page. Optionally rename it to a new URL path.</p>
|
|
330
|
+
<table class="table table-sm">
|
|
331
|
+
<thead>
|
|
332
|
+
<tr>
|
|
333
|
+
<th>Field</th>
|
|
334
|
+
<th>Type</th>
|
|
335
|
+
<th>Description</th>
|
|
336
|
+
</tr>
|
|
337
|
+
</thead>
|
|
338
|
+
<tbody>
|
|
339
|
+
<tr>
|
|
340
|
+
<td><code>frontmatter</code></td>
|
|
341
|
+
<td>object</td>
|
|
342
|
+
<td>Updated frontmatter fields</td>
|
|
343
|
+
</tr>
|
|
344
|
+
<tr>
|
|
345
|
+
<td><code>body</code></td>
|
|
346
|
+
<td>string</td>
|
|
347
|
+
<td>Updated Markdown content</td>
|
|
348
|
+
</tr>
|
|
349
|
+
<tr>
|
|
350
|
+
<td><code>newUrlPath</code></td>
|
|
351
|
+
<td>string</td>
|
|
352
|
+
<td>Optional. Rename the page to a different URL path</td>
|
|
353
|
+
</tr>
|
|
354
|
+
</tbody>
|
|
355
|
+
</table>
|
|
356
|
+
<pre class="code-block"><code>// Response 200 — returns the updated page object
|
|
352
357
|
|
|
353
358
|
// Error 404
|
|
354
359
|
{ "error": "Page not found" }
|
|
@@ -356,449 +361,398 @@
|
|
|
356
361
|
// Error 409
|
|
357
362
|
{ "error": "A page already exists at that path" }</code></pre>
|
|
358
363
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
364
|
+
<h3><span class="method-badge method-delete">DELETE</span><span
|
|
365
|
+
class="endpoint-path">/api/pages/*</span></h3>
|
|
366
|
+
<p class="auth-note">Requires Bearer token + <code>pages</code> permission.</p>
|
|
367
|
+
<p>Delete a page and its source file.</p>
|
|
368
|
+
<pre class="code-block"><code>// Response 200
|
|
363
369
|
{ "success": true }
|
|
364
370
|
|
|
365
371
|
// Error 404
|
|
366
372
|
{ "error": "Page not found" }</code></pre>
|
|
367
373
|
|
|
368
|
-
|
|
369
|
-
</div>
|
|
374
|
+
</div>
|
|
370
375
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
<div class="card-header" role="button" tabindex="0">
|
|
374
|
-
<div class="card-header-content"><h2><span data-icon="settings"></span> Settings</h2></div>
|
|
375
|
-
<span class="card-collapse-icon" data-icon="chevron-down"></span>
|
|
376
|
-
</div>
|
|
377
|
-
<div class="card-body docs-body">
|
|
376
|
+
<!-- Settings -->
|
|
377
|
+
<div class="tab-panel docs-body">
|
|
378
378
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
"adminTheme": "charcoal-dark",
|
|
386
|
-
"smtp": { "host": "smtp.example.com", "port": 587, ... },
|
|
387
|
-
...
|
|
388
|
-
}</code></pre>
|
|
379
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/settings</span>
|
|
380
|
+
</h3>
|
|
381
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> permission.</p>
|
|
382
|
+
<p>Return the full site settings object from <code>config/site.json</code>.</p>
|
|
383
|
+
<pre class="code-block"><code>// Response 200
|
|
384
|
+
{ "siteName": "My Site", "adminTheme": "charcoal-dark", "smtp": { ... }, ... }</code></pre>
|
|
389
385
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
386
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/settings</span>
|
|
387
|
+
</h3>
|
|
388
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> permission.</p>
|
|
389
|
+
<p>Replace the site settings object. Send the full merged object — partial updates overwrite the
|
|
390
|
+
entire config.</p>
|
|
391
|
+
<pre class="code-block"><code>// Request body — full site settings object
|
|
395
392
|
{ "siteName": "My Site", "adminTheme": "ocean-dark", ... }
|
|
396
393
|
|
|
397
394
|
// Response 200
|
|
398
395
|
{ "success": true }</code></pre>
|
|
399
396
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
397
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/settings/test-email</span>
|
|
398
|
+
</h3>
|
|
399
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> permission.</p>
|
|
400
|
+
<p>Send a test email using the stored SMTP configuration.</p>
|
|
401
|
+
<table class="table table-sm">
|
|
402
|
+
<thead>
|
|
403
|
+
<tr>
|
|
404
|
+
<th>Field</th>
|
|
405
|
+
<th>Type</th>
|
|
406
|
+
<th>Description</th>
|
|
407
|
+
</tr>
|
|
408
|
+
</thead>
|
|
409
|
+
<tbody>
|
|
410
|
+
<tr>
|
|
411
|
+
<td><code>to</code></td>
|
|
412
|
+
<td>string</td>
|
|
413
|
+
<td>Optional. Recipient address. Defaults to the configured From Address.</td>
|
|
414
|
+
</tr>
|
|
415
|
+
</tbody>
|
|
416
|
+
</table>
|
|
417
|
+
<pre class="code-block"><code>// Response 200
|
|
421
418
|
{ "success": true, "message": "Test email sent to alice@example.com" }
|
|
422
419
|
|
|
423
420
|
// Error 400
|
|
424
421
|
{ "error": "SMTP is not configured. Save your SMTP settings first." }</code></pre>
|
|
425
422
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
<pre class="code-block"><code>// Response 200
|
|
423
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/settings/custom-css</span>
|
|
424
|
+
</h3>
|
|
425
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> permission.</p>
|
|
426
|
+
<p>Return the current custom CSS from <code>content/custom.css</code>.</p>
|
|
427
|
+
<pre class="code-block"><code>// Response 200
|
|
432
428
|
{ "css": "body { font-family: sans-serif; }" }</code></pre>
|
|
433
429
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
430
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/settings/custom-css</span>
|
|
431
|
+
</h3>
|
|
432
|
+
<p class="auth-note">Requires Bearer token + <code>settings</code> permission.</p>
|
|
433
|
+
<p>Write CSS to <code>content/custom.css</code>. Maximum size is 100 KB.</p>
|
|
434
|
+
<table class="table table-sm">
|
|
435
|
+
<thead>
|
|
436
|
+
<tr>
|
|
437
|
+
<th>Field</th>
|
|
438
|
+
<th>Type</th>
|
|
439
|
+
<th>Description</th>
|
|
440
|
+
</tr>
|
|
441
|
+
</thead>
|
|
442
|
+
<tbody>
|
|
443
|
+
<tr>
|
|
444
|
+
<td><code>css</code></td>
|
|
445
|
+
<td>string</td>
|
|
446
|
+
<td>CSS string (max 100 KB)</td>
|
|
447
|
+
</tr>
|
|
448
|
+
</tbody>
|
|
449
|
+
</table>
|
|
450
|
+
<pre class="code-block"><code>// Response 200
|
|
455
451
|
{ "success": true }</code></pre>
|
|
456
452
|
|
|
457
|
-
|
|
458
|
-
</div>
|
|
453
|
+
</div>
|
|
459
454
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
<div class="card-header" role="button" tabindex="0">
|
|
463
|
-
<div class="card-header-content"><h2><span data-icon="layout"></span> Layouts</h2></div>
|
|
464
|
-
<span class="card-collapse-icon" data-icon="chevron-down"></span>
|
|
465
|
-
</div>
|
|
466
|
-
<div class="card-body docs-body">
|
|
455
|
+
<!-- Layouts -->
|
|
456
|
+
<div class="tab-panel docs-body">
|
|
467
457
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
458
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/layouts</span>
|
|
459
|
+
</h3>
|
|
460
|
+
<p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
|
|
461
|
+
<p>Return all layout presets from <code>config/presets.json</code>.</p>
|
|
462
|
+
<pre class="code-block"><code>// Response 200
|
|
472
463
|
{
|
|
473
464
|
"default": { "label": "Default", "sections": [...] },
|
|
474
465
|
"full-width": { "label": "Full Width", "sections": [...] }
|
|
475
466
|
}</code></pre>
|
|
476
467
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
468
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/layouts</span>
|
|
469
|
+
</h3>
|
|
470
|
+
<p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
|
|
471
|
+
<p>Replace the entire layout presets object.</p>
|
|
472
|
+
<pre class="code-block"><code>// Response 200
|
|
481
473
|
{ "success": true }</code></pre>
|
|
482
474
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
475
|
+
<h3><span class="method-badge method-get">GET</span><span
|
|
476
|
+
class="endpoint-path">/api/layouts/options</span></h3>
|
|
477
|
+
<p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
|
|
478
|
+
<p>Return layout display options stored in <code>config/site.json</code> under
|
|
479
|
+
<code>layoutOptions</code>.</p>
|
|
480
|
+
<pre class="code-block"><code>// Response 200
|
|
488
481
|
{ "spacerSize": 8 }</code></pre>
|
|
489
482
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
483
|
+
<h3><span class="method-badge method-put">PUT</span><span
|
|
484
|
+
class="endpoint-path">/api/layouts/options</span></h3>
|
|
485
|
+
<p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
|
|
486
|
+
<p>Merge layout option updates into the existing options. Existing keys not included are
|
|
487
|
+
preserved.</p>
|
|
488
|
+
<table class="table table-sm">
|
|
489
|
+
<thead>
|
|
490
|
+
<tr>
|
|
491
|
+
<th>Field</th>
|
|
492
|
+
<th>Type</th>
|
|
493
|
+
<th>Description</th>
|
|
494
|
+
</tr>
|
|
495
|
+
</thead>
|
|
496
|
+
<tbody>
|
|
497
|
+
<tr>
|
|
498
|
+
<td><code>spacerSize</code></td>
|
|
499
|
+
<td>number</td>
|
|
500
|
+
<td>Default spacer block size in pixels</td>
|
|
501
|
+
</tr>
|
|
502
|
+
</tbody>
|
|
503
|
+
</table>
|
|
504
|
+
<pre class="code-block"><code>// Response 200
|
|
511
505
|
{ "success": true }</code></pre>
|
|
512
506
|
|
|
513
|
-
|
|
514
|
-
</div>
|
|
507
|
+
</div>
|
|
515
508
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
<div class="card-header" role="button" tabindex="0">
|
|
519
|
-
<div class="card-header-content"><h2><span data-icon="menu"></span> Navigation</h2></div>
|
|
520
|
-
<span class="card-collapse-icon" data-icon="chevron-down"></span>
|
|
521
|
-
</div>
|
|
522
|
-
<div class="card-body docs-body">
|
|
509
|
+
<!-- Navigation -->
|
|
510
|
+
<div class="tab-panel docs-body">
|
|
523
511
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
512
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/navigation</span>
|
|
513
|
+
</h3>
|
|
514
|
+
<p class="auth-note">Requires Bearer token + <code>navigation</code> permission.</p>
|
|
515
|
+
<p>Return the navigation configuration from <code>config/navigation.json</code>.</p>
|
|
516
|
+
<pre class="code-block"><code>// Response 200
|
|
528
517
|
{
|
|
529
518
|
"items": [
|
|
530
519
|
{ "label": "Home", "url": "/" },
|
|
531
520
|
{ "label": "About", "url": "/about" },
|
|
532
|
-
{
|
|
533
|
-
"label": "Resources",
|
|
534
|
-
"items": [
|
|
535
|
-
{ "label": "Blog", "url": "/blog" }
|
|
536
|
-
]
|
|
537
|
-
}
|
|
521
|
+
{ "label": "Resources", "items": [ { "label": "Blog", "url": "/blog" } ] }
|
|
538
522
|
]
|
|
539
523
|
}</code></pre>
|
|
540
524
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
{ "label": "About", "url": "/about" }
|
|
550
|
-
]
|
|
551
|
-
}
|
|
525
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/navigation</span>
|
|
526
|
+
</h3>
|
|
527
|
+
<p class="auth-note">Requires Bearer token + <code>navigation</code> permission.</p>
|
|
528
|
+
<p>Replace the navigation config. Sub-items must use the <code>items</code> key (the server normalises
|
|
529
|
+
<code>children</code>
|
|
530
|
+
to <code>items</code> automatically).</p>
|
|
531
|
+
<pre class="code-block"><code>// Request body
|
|
532
|
+
{ "items": [ { "label": "Home", "url": "/" }, { "label": "About", "url": "/about" } ] }
|
|
552
533
|
|
|
553
534
|
// Response 200
|
|
554
535
|
{ "success": true }</code></pre>
|
|
555
536
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
<th>Type</th>
|
|
597
|
-
<th>Description</th>
|
|
598
|
-
</tr>
|
|
599
|
-
</thead>
|
|
600
|
-
<tbody>
|
|
601
|
-
<tr>
|
|
602
|
-
<td><code>newName</code></td>
|
|
603
|
-
<td>string</td>
|
|
604
|
-
<td>New filename (will be sanitised)</td>
|
|
605
|
-
</tr>
|
|
606
|
-
</tbody>
|
|
607
|
-
</table>
|
|
608
|
-
<pre class="code-block"><code>// Response 200
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<!-- Media -->
|
|
540
|
+
<div class="tab-panel docs-body">
|
|
541
|
+
|
|
542
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/media</span></h3>
|
|
543
|
+
<p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
|
|
544
|
+
<p>List all media files in the uploads directory.</p>
|
|
545
|
+
<pre class="code-block"><code>// Response 200
|
|
546
|
+
[ { "name": "hero.jpg", "url": "/media/hero.jpg", "size": 204800, "mime": "image/jpeg" } ]</code></pre>
|
|
547
|
+
|
|
548
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/media</span>
|
|
549
|
+
</h3>
|
|
550
|
+
<p class="auth-note">Requires Bearer token + <code>media</code> permission. Content-Type: <code>multipart/form-data</code>.
|
|
551
|
+
</p>
|
|
552
|
+
<p>Upload one or more files. Returns a single object for one file, or an array for multiple.</p>
|
|
553
|
+
<pre class="code-block"><code>// Response 201 (single)
|
|
554
|
+
{ "name": "photo.jpg", "url": "/media/photo.jpg", "size": 98304, "mime": "image/jpeg" }</code></pre>
|
|
555
|
+
|
|
556
|
+
<h3><span class="method-badge method-patch">PATCH</span><span
|
|
557
|
+
class="endpoint-path">/api/media/:name</span></h3>
|
|
558
|
+
<p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
|
|
559
|
+
<p>Rename a media file. Fails with 409 if the new name already exists.</p>
|
|
560
|
+
<table class="table table-sm">
|
|
561
|
+
<thead>
|
|
562
|
+
<tr>
|
|
563
|
+
<th>Field</th>
|
|
564
|
+
<th>Type</th>
|
|
565
|
+
<th>Description</th>
|
|
566
|
+
</tr>
|
|
567
|
+
</thead>
|
|
568
|
+
<tbody>
|
|
569
|
+
<tr>
|
|
570
|
+
<td><code>newName</code></td>
|
|
571
|
+
<td>string</td>
|
|
572
|
+
<td>New filename (will be sanitised)</td>
|
|
573
|
+
</tr>
|
|
574
|
+
</tbody>
|
|
575
|
+
</table>
|
|
576
|
+
<pre class="code-block"><code>// Response 200
|
|
609
577
|
{ "name": "new-photo.jpg", "url": "/media/new-photo.jpg", ... }</code></pre>
|
|
610
578
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
579
|
+
<h3><span class="method-badge method-delete">DELETE</span><span
|
|
580
|
+
class="endpoint-path">/api/media/:name</span></h3>
|
|
581
|
+
<p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
|
|
582
|
+
<p>Delete a media file from the uploads directory.</p>
|
|
583
|
+
<pre class="code-block"><code>// Response 200
|
|
616
584
|
{ "success": true }</code></pre>
|
|
617
585
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
{ "width": 1920, "height": 1080, "format": "jpeg", "size": 204800 }
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
</table>
|
|
655
|
-
<pre class="code-block"><code>// Request body example
|
|
656
|
-
{
|
|
657
|
-
"operations": { "resize": { "width": 800, "height": 600 }, "format": "webp" },
|
|
658
|
-
"saveAs": "hero-800.webp"
|
|
659
|
-
}
|
|
586
|
+
<h3><span class="method-badge method-get">GET</span><span
|
|
587
|
+
class="endpoint-path">/api/media/:name/info</span></h3>
|
|
588
|
+
<p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
|
|
589
|
+
<p>Return image metadata (dimensions, format, file size) for editable image formats (JPEG, PNG, WebP,
|
|
590
|
+
GIF, TIFF).</p>
|
|
591
|
+
<pre class="code-block"><code>// Response 200
|
|
592
|
+
{ "width": 1920, "height": 1080, "format": "jpeg", "size": 204800 }</code></pre>
|
|
593
|
+
|
|
594
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/media/:name/transform</span>
|
|
595
|
+
</h3>
|
|
596
|
+
<p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
|
|
597
|
+
<p>Apply image transformations (resize, crop, rotate, watermark, etc.) and optionally save to a new
|
|
598
|
+
filename.</p>
|
|
599
|
+
<table class="table table-sm">
|
|
600
|
+
<thead>
|
|
601
|
+
<tr>
|
|
602
|
+
<th>Field</th>
|
|
603
|
+
<th>Type</th>
|
|
604
|
+
<th>Description</th>
|
|
605
|
+
</tr>
|
|
606
|
+
</thead>
|
|
607
|
+
<tbody>
|
|
608
|
+
<tr>
|
|
609
|
+
<td><code>operations</code></td>
|
|
610
|
+
<td>object</td>
|
|
611
|
+
<td>Transformation operations to apply</td>
|
|
612
|
+
</tr>
|
|
613
|
+
<tr>
|
|
614
|
+
<td><code>saveAs</code></td>
|
|
615
|
+
<td>string</td>
|
|
616
|
+
<td>Optional. Output filename. Defaults to overwriting the source.</td>
|
|
617
|
+
</tr>
|
|
618
|
+
</tbody>
|
|
619
|
+
</table>
|
|
620
|
+
<pre class="code-block"><code>// Request body
|
|
621
|
+
{ "operations": { "resize": { "width": 800, "height": 600 }, "format": "webp" }, "saveAs": "hero-800.webp" }
|
|
660
622
|
|
|
661
623
|
// Response 200
|
|
662
624
|
{ "name": "hero-800.webp", "url": "/media/hero-800.webp", ... }</code></pre>
|
|
663
625
|
|
|
664
|
-
|
|
665
|
-
</div>
|
|
626
|
+
</div>
|
|
666
627
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
<div class="card-header" role="button" tabindex="0">
|
|
670
|
-
<div class="card-header-content"><h2><span data-icon="users"></span> Users</h2></div>
|
|
671
|
-
<span class="card-collapse-icon" data-icon="chevron-down"></span>
|
|
672
|
-
</div>
|
|
673
|
-
<div class="card-body docs-body">
|
|
628
|
+
<!-- Users -->
|
|
629
|
+
<div class="tab-panel docs-body">
|
|
674
630
|
|
|
675
|
-
|
|
676
|
-
|
|
631
|
+
<p>Role hierarchy governs which users can manage other users. A manager cannot create, edit, or delete
|
|
632
|
+
an admin.
|
|
633
|
+
Self-deletion is always blocked.</p>
|
|
677
634
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
[
|
|
683
|
-
{ "id": "uuid", "name": "Alice", "email": "alice@example.com", "role": "admin", "isActive": true }
|
|
684
|
-
]</code></pre>
|
|
635
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/users</span></h3>
|
|
636
|
+
<p class="auth-note">Requires Bearer token + <code>users</code> permission (admin or manager).</p>
|
|
637
|
+
<p>Return all users. Passwords are stripped from the response.</p>
|
|
638
|
+
<pre class="code-block"><code>// Response 200
|
|
639
|
+
[ { "id": "uuid", "name": "Alice", "email": "alice@example.com", "role": "admin", "isActive": true } ]</code></pre>
|
|
685
640
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
641
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/users/:id</span>
|
|
642
|
+
</h3>
|
|
643
|
+
<p class="auth-note">Requires Bearer token. Accessible to the user themselves, or a user with <code>users</code>
|
|
644
|
+
permission.</p>
|
|
645
|
+
<p>Return a single user by ID.</p>
|
|
646
|
+
<pre class="code-block"><code>// Response 200
|
|
691
647
|
{ "id": "uuid", "name": "Alice", "email": "alice@example.com", "role": "admin", "isActive": true }
|
|
692
648
|
|
|
693
649
|
// Error 404
|
|
694
650
|
{ "error": "User not found" }</code></pre>
|
|
695
651
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
652
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/users</span>
|
|
653
|
+
</h3>
|
|
654
|
+
<p class="auth-note">Requires Bearer token + <code>users</code> permission.</p>
|
|
655
|
+
<p>Create a new user. The actor cannot assign a role higher than their own level.</p>
|
|
656
|
+
<table class="table table-sm">
|
|
657
|
+
<thead>
|
|
658
|
+
<tr>
|
|
659
|
+
<th>Field</th>
|
|
660
|
+
<th>Type</th>
|
|
661
|
+
<th>Description</th>
|
|
662
|
+
</tr>
|
|
663
|
+
</thead>
|
|
664
|
+
<tbody>
|
|
665
|
+
<tr>
|
|
666
|
+
<td><code>name</code></td>
|
|
667
|
+
<td>string</td>
|
|
668
|
+
<td>Display name</td>
|
|
669
|
+
</tr>
|
|
670
|
+
<tr>
|
|
671
|
+
<td><code>email</code></td>
|
|
672
|
+
<td>string</td>
|
|
673
|
+
<td>Unique email address</td>
|
|
674
|
+
</tr>
|
|
675
|
+
<tr>
|
|
676
|
+
<td><code>password</code></td>
|
|
677
|
+
<td>string</td>
|
|
678
|
+
<td>Minimum 8 characters</td>
|
|
679
|
+
</tr>
|
|
680
|
+
<tr>
|
|
681
|
+
<td><code>role</code></td>
|
|
682
|
+
<td>string</td>
|
|
683
|
+
<td>Optional. Defaults to <code>editor</code>.</td>
|
|
684
|
+
</tr>
|
|
685
|
+
</tbody>
|
|
686
|
+
</table>
|
|
687
|
+
<pre class="code-block"><code>// Response 201
|
|
731
688
|
{ "id": "uuid", "name": "Bob", "email": "bob@example.com", "role": "editor", "isActive": true }
|
|
732
689
|
|
|
733
690
|
// Error 409
|
|
734
691
|
{ "error": "Email already in use" }</code></pre>
|
|
735
692
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
693
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/users/:id</span>
|
|
694
|
+
</h3>
|
|
695
|
+
<p class="auth-note">Requires Bearer token + <code>users</code> permission.</p>
|
|
696
|
+
<p>Update a user's details. Managers cannot edit admins. Role escalation beyond the actor's own level
|
|
697
|
+
is blocked.</p>
|
|
698
|
+
<table class="table table-sm">
|
|
699
|
+
<thead>
|
|
700
|
+
<tr>
|
|
701
|
+
<th>Field</th>
|
|
702
|
+
<th>Type</th>
|
|
703
|
+
<th>Description</th>
|
|
704
|
+
</tr>
|
|
705
|
+
</thead>
|
|
706
|
+
<tbody>
|
|
707
|
+
<tr>
|
|
708
|
+
<td><code>name</code></td>
|
|
709
|
+
<td>string</td>
|
|
710
|
+
<td>New display name</td>
|
|
711
|
+
</tr>
|
|
712
|
+
<tr>
|
|
713
|
+
<td><code>email</code></td>
|
|
714
|
+
<td>string</td>
|
|
715
|
+
<td>New email address</td>
|
|
716
|
+
</tr>
|
|
717
|
+
<tr>
|
|
718
|
+
<td><code>password</code></td>
|
|
719
|
+
<td>string</td>
|
|
720
|
+
<td>New password (min 8 chars)</td>
|
|
721
|
+
</tr>
|
|
722
|
+
<tr>
|
|
723
|
+
<td><code>role</code></td>
|
|
724
|
+
<td>string</td>
|
|
725
|
+
<td>New role</td>
|
|
726
|
+
</tr>
|
|
727
|
+
<tr>
|
|
728
|
+
<td><code>isActive</code></td>
|
|
729
|
+
<td>boolean</td>
|
|
730
|
+
<td>Enable or disable the account</td>
|
|
731
|
+
</tr>
|
|
732
|
+
</tbody>
|
|
733
|
+
</table>
|
|
734
|
+
<pre class="code-block"><code>// Response 200 — returns the updated user object</code></pre>
|
|
735
|
+
|
|
736
|
+
<h3><span class="method-badge method-delete">DELETE</span><span
|
|
737
|
+
class="endpoint-path">/api/users/:id</span></h3>
|
|
738
|
+
<p class="auth-note">Requires Bearer token + <code>users</code> permission.</p>
|
|
739
|
+
<p>Delete a user. Cannot delete your own account or a user with a higher role level.</p>
|
|
740
|
+
<pre class="code-block"><code>// Response 200
|
|
782
741
|
{ "success": true }
|
|
783
742
|
|
|
784
743
|
// Error 403
|
|
785
744
|
{ "error": "You cannot delete your own account" }</code></pre>
|
|
786
745
|
|
|
787
|
-
|
|
788
|
-
</div>
|
|
746
|
+
</div>
|
|
789
747
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
<div class="card-header" role="button" tabindex="0">
|
|
793
|
-
<div class="card-header-content"><h2><span data-icon="package"></span> Plugins</h2></div>
|
|
794
|
-
<span class="card-collapse-icon" data-icon="chevron-down"></span>
|
|
795
|
-
</div>
|
|
796
|
-
<div class="card-body docs-body">
|
|
748
|
+
<!-- Plugins -->
|
|
749
|
+
<div class="tab-panel docs-body">
|
|
797
750
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
751
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/plugins</span>
|
|
752
|
+
</h3>
|
|
753
|
+
<p class="auth-note">Requires Bearer token + admin role.</p>
|
|
754
|
+
<p>List all discovered plugins with their current enabled state and settings.</p>
|
|
755
|
+
<pre class="code-block"><code>// Response 200
|
|
802
756
|
[
|
|
803
757
|
{
|
|
804
758
|
"name": "form-builder",
|
|
@@ -813,596 +767,478 @@
|
|
|
813
767
|
}
|
|
814
768
|
]</code></pre>
|
|
815
769
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
770
|
+
<h3><span class="method-badge method-put">PUT</span><span
|
|
771
|
+
class="endpoint-path">/api/plugins/:name</span></h3>
|
|
772
|
+
<p class="auth-note">Requires Bearer token + admin role.</p>
|
|
773
|
+
<p>Enable or disable a plugin, or update its settings.</p>
|
|
774
|
+
<table class="table table-sm">
|
|
775
|
+
<thead>
|
|
776
|
+
<tr>
|
|
777
|
+
<th>Field</th>
|
|
778
|
+
<th>Type</th>
|
|
779
|
+
<th>Description</th>
|
|
780
|
+
</tr>
|
|
781
|
+
</thead>
|
|
782
|
+
<tbody>
|
|
783
|
+
<tr>
|
|
784
|
+
<td><code>enabled</code></td>
|
|
785
|
+
<td>boolean</td>
|
|
786
|
+
<td>Whether the plugin is active</td>
|
|
787
|
+
</tr>
|
|
788
|
+
<tr>
|
|
789
|
+
<td><code>settings</code></td>
|
|
790
|
+
<td>object</td>
|
|
791
|
+
<td>Plugin-specific settings object</td>
|
|
792
|
+
</tr>
|
|
793
|
+
</tbody>
|
|
794
|
+
</table>
|
|
795
|
+
<pre class="code-block"><code>// Response 200
|
|
842
796
|
{ "success": true }
|
|
843
797
|
|
|
844
798
|
// Error 404
|
|
845
799
|
{ "error": "Plugin not found" }</code></pre>
|
|
846
800
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
801
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/plugins/admin-config</span>
|
|
802
|
+
</h3>
|
|
803
|
+
<p class="auth-note">Requires Bearer token (any role).</p>
|
|
804
|
+
<p>Return the merged admin configuration for all enabled plugins — sidebar items, SPA routes, and view
|
|
805
|
+
entry points.</p>
|
|
806
|
+
<pre class="code-block"><code>// Response 200
|
|
853
807
|
{
|
|
854
|
-
"sidebar": [
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
"routes": [
|
|
858
|
-
{ "path": "/form-settings", "view": "formSettings", "title": "Form Settings - Domma CMS" }
|
|
859
|
-
],
|
|
860
|
-
"views": {
|
|
861
|
-
"formSettings": { "entry": "form-builder/admin/views/settings.js", "exportName": "formSettingsView" }
|
|
862
|
-
}
|
|
808
|
+
"sidebar": [ { "id": "form-builder", "text": "Form Settings", "icon": "clipboard", "url": "#/form-settings" } ],
|
|
809
|
+
"routes": [ { "path": "/form-settings", "view": "formSettings", "title": "Form Settings - Domma CMS" } ],
|
|
810
|
+
"views": { "formSettings": { "entry": "form-builder/admin/views/settings.js", "exportName": "formSettingsView" } }
|
|
863
811
|
}</code></pre>
|
|
864
812
|
|
|
865
|
-
|
|
866
|
-
</div>
|
|
813
|
+
</div>
|
|
867
814
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
<div class="card-header" role="button" tabindex="0">
|
|
871
|
-
<div class="card-header-content"><h2><span data-icon="database"></span> Collections</h2></div>
|
|
872
|
-
<span class="card-collapse-icon" data-icon="chevron-down"></span>
|
|
873
|
-
</div>
|
|
874
|
-
<div class="card-body docs-body">
|
|
815
|
+
<!-- Collections -->
|
|
816
|
+
<div class="tab-panel docs-body">
|
|
875
817
|
|
|
876
|
-
|
|
877
|
-
|
|
818
|
+
<p>Collections have two access planes: <strong>admin endpoints</strong> (authenticated, role-gated)
|
|
819
|
+
and <strong>public
|
|
820
|
+
endpoints</strong> (access level configured per collection).</p>
|
|
878
821
|
|
|
879
|
-
|
|
880
|
-
|
|
822
|
+
<h3 style="margin-top:16px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
823
|
+
Schema Management</h3>
|
|
881
824
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
]</code></pre>
|
|
825
|
+
<h3><span class="method-badge method-get">GET</span><span
|
|
826
|
+
class="endpoint-path">/api/collections</span></h3>
|
|
827
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
828
|
+
<p>List all collection schemas (metadata only, no entries).</p>
|
|
829
|
+
<pre class="code-block"><code>// Response 200
|
|
830
|
+
[ { "slug": "blog", "title": "Blog Posts", "description": "...", "fields": [...] } ]</code></pre>
|
|
889
831
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
832
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/pro-status</span>
|
|
833
|
+
</h3>
|
|
834
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
835
|
+
<p>Check whether the Pro (MongoDB) storage adapter is available.</p>
|
|
836
|
+
<pre class="code-block"><code>// Response 200 (free)
|
|
895
837
|
{ "pro": false, "connections": [] }
|
|
896
838
|
|
|
897
839
|
// Response 200 (pro)
|
|
898
840
|
{ "pro": true, "connections": ["default", "analytics"] }</code></pre>
|
|
899
841
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
{
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
</p>
|
|
914
|
-
<table class="table table-sm">
|
|
915
|
-
<thead>
|
|
916
|
-
<tr>
|
|
917
|
-
<th>Field</th>
|
|
918
|
-
<th>Type</th>
|
|
919
|
-
<th>Description</th>
|
|
920
|
-
</tr>
|
|
921
|
-
</thead>
|
|
922
|
-
<tbody>
|
|
923
|
-
<tr>
|
|
924
|
-
<td><code>{name}</code></td>
|
|
925
|
-
<td>object</td>
|
|
926
|
-
<td>Named connection with <code>type</code>, <code>uri</code>, <code>database</code></td>
|
|
927
|
-
</tr>
|
|
928
|
-
</tbody>
|
|
929
|
-
</table>
|
|
930
|
-
<pre class="code-block"><code>// Response 200
|
|
842
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/connections</span>
|
|
843
|
+
</h3>
|
|
844
|
+
<p class="auth-note">Requires Bearer token + admin role.</p>
|
|
845
|
+
<p>Return configured MongoDB connections from <code>config/connections.json</code>.</p>
|
|
846
|
+
<pre class="code-block"><code>// Response 200
|
|
847
|
+
{ "default": { "type": "mongodb", "uri": "mongodb://localhost:27017", "database": "my_cms" } }</code></pre>
|
|
848
|
+
|
|
849
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/connections</span>
|
|
850
|
+
</h3>
|
|
851
|
+
<p class="auth-note">Requires Bearer token + admin role.</p>
|
|
852
|
+
<p>Save MongoDB connection definitions. Each connection requires <code>type</code>, <code>uri</code>,
|
|
853
|
+
and <code>database</code>.</p>
|
|
854
|
+
<pre class="code-block"><code>// Response 200
|
|
931
855
|
{ "success": true }
|
|
932
856
|
|
|
933
857
|
// Error 400
|
|
934
858
|
{ "error": "Connection \"default\" requires type, uri, and database" }</code></pre>
|
|
935
859
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
860
|
+
<h3><span class="method-badge method-post">POST</span><span
|
|
861
|
+
class="endpoint-path">/api/collections</span></h3>
|
|
862
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
863
|
+
<p>Create a new collection. A <code>slug</code> is auto-generated from the title if not provided.</p>
|
|
864
|
+
<table class="table table-sm">
|
|
865
|
+
<thead>
|
|
866
|
+
<tr>
|
|
867
|
+
<th>Field</th>
|
|
868
|
+
<th>Type</th>
|
|
869
|
+
<th>Description</th>
|
|
870
|
+
</tr>
|
|
871
|
+
</thead>
|
|
872
|
+
<tbody>
|
|
873
|
+
<tr>
|
|
874
|
+
<td><code>title</code></td>
|
|
875
|
+
<td>string</td>
|
|
876
|
+
<td>Required. Human-readable collection name</td>
|
|
877
|
+
</tr>
|
|
878
|
+
<tr>
|
|
879
|
+
<td><code>slug</code></td>
|
|
880
|
+
<td>string</td>
|
|
881
|
+
<td>Optional. URL-safe identifier. Auto-generated if omitted.</td>
|
|
882
|
+
</tr>
|
|
883
|
+
<tr>
|
|
884
|
+
<td><code>description</code></td>
|
|
885
|
+
<td>string</td>
|
|
886
|
+
<td>Optional description</td>
|
|
887
|
+
</tr>
|
|
888
|
+
<tr>
|
|
889
|
+
<td><code>fields</code></td>
|
|
890
|
+
<td>array</td>
|
|
891
|
+
<td>Field definitions</td>
|
|
892
|
+
</tr>
|
|
893
|
+
<tr>
|
|
894
|
+
<td><code>api</code></td>
|
|
895
|
+
<td>object</td>
|
|
896
|
+
<td>Public API access config per operation</td>
|
|
897
|
+
</tr>
|
|
898
|
+
<tr>
|
|
899
|
+
<td><code>storage</code></td>
|
|
900
|
+
<td>object</td>
|
|
901
|
+
<td>Optional Pro: <code>{ "adapter": "mongodb", "connection": "default" }</code></td>
|
|
902
|
+
</tr>
|
|
903
|
+
</tbody>
|
|
904
|
+
</table>
|
|
905
|
+
<pre class="code-block"><code>// Response 201 — returns the created schema object
|
|
981
906
|
|
|
982
907
|
// Error 409
|
|
983
908
|
{ "error": "A collection with that slug already exists" }</code></pre>
|
|
984
909
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
// Error 404
|
|
1001
|
-
{ "error": "Collection not found" }</code></pre>
|
|
1002
|
-
|
|
1003
|
-
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug</span>
|
|
1004
|
-
</h3>
|
|
1005
|
-
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
1006
|
-
<p>Update a collection schema.</p>
|
|
1007
|
-
<pre class="code-block"><code>// Response 200 — returns the updated schema
|
|
1008
|
-
|
|
1009
|
-
// Error 404
|
|
1010
|
-
{ "error": "Collection not found" }</code></pre>
|
|
1011
|
-
|
|
1012
|
-
<h3><span class="method-badge method-delete">DELETE</span><span
|
|
1013
|
-
class="endpoint-path">/api/collections/:slug</span></h3>
|
|
1014
|
-
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
1015
|
-
<p>Delete a collection and all its entries. Preset collections (e.g. <code>roles</code>) cannot be deleted.
|
|
1016
|
-
</p>
|
|
1017
|
-
<pre class="code-block"><code>// Response 200
|
|
910
|
+
<h3><span class="method-badge method-get">GET</span><span
|
|
911
|
+
class="endpoint-path">/api/collections/:slug</span></h3>
|
|
912
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
913
|
+
<p>Return the schema for a single collection by slug.</p>
|
|
914
|
+
|
|
915
|
+
<h3><span class="method-badge method-put">PUT</span><span
|
|
916
|
+
class="endpoint-path">/api/collections/:slug</span></h3>
|
|
917
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
918
|
+
<p>Update a collection schema.</p>
|
|
919
|
+
|
|
920
|
+
<h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug</span>
|
|
921
|
+
</h3>
|
|
922
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
923
|
+
<p>Delete a collection and all its entries. Preset collections cannot be deleted.</p>
|
|
924
|
+
<pre class="code-block"><code>// Response 200
|
|
1018
925
|
{ "success": true }
|
|
1019
926
|
|
|
1020
927
|
// Error 403
|
|
1021
928
|
{ "error": "Cannot delete a preset collection" }</code></pre>
|
|
1022
929
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
{
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
<tr>
|
|
1091
|
-
<th>Field</th>
|
|
1092
|
-
<th>Type</th>
|
|
1093
|
-
<th>Description</th>
|
|
1094
|
-
</tr>
|
|
1095
|
-
</thead>
|
|
1096
|
-
<tbody>
|
|
1097
|
-
<tr>
|
|
1098
|
-
<td><code>data</code></td>
|
|
1099
|
-
<td>object</td>
|
|
1100
|
-
<td>Entry field values keyed by field name</td>
|
|
1101
|
-
</tr>
|
|
1102
|
-
</tbody>
|
|
1103
|
-
</table>
|
|
1104
|
-
<pre class="code-block"><code>// Response 201 — returns the created entry</code></pre>
|
|
1105
|
-
|
|
1106
|
-
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
|
|
1107
|
-
</h3>
|
|
1108
|
-
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
1109
|
-
<p>Update an entry. Data is validated against the schema.</p>
|
|
1110
|
-
<pre class="code-block"><code>// Response 200 — returns the updated entry
|
|
1111
|
-
|
|
1112
|
-
// Error 404
|
|
1113
|
-
{ "error": "Entry not found" }</code></pre>
|
|
1114
|
-
|
|
1115
|
-
<h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
|
|
1116
|
-
</h3>
|
|
1117
|
-
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
1118
|
-
<p>Delete a single entry. Deleting the root admin role from <code>roles</code> is blocked.</p>
|
|
1119
|
-
<pre class="code-block"><code>// Response 200
|
|
930
|
+
<h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
931
|
+
Admin Entry CRUD</h3>
|
|
932
|
+
|
|
933
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/entries</span>
|
|
934
|
+
</h3>
|
|
935
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
936
|
+
<p>List entries with pagination, sorting, and full-text search.</p>
|
|
937
|
+
<table class="table table-sm">
|
|
938
|
+
<thead>
|
|
939
|
+
<tr>
|
|
940
|
+
<th>Query param</th>
|
|
941
|
+
<th>Default</th>
|
|
942
|
+
<th>Description</th>
|
|
943
|
+
</tr>
|
|
944
|
+
</thead>
|
|
945
|
+
<tbody>
|
|
946
|
+
<tr>
|
|
947
|
+
<td><code>page</code></td>
|
|
948
|
+
<td>1</td>
|
|
949
|
+
<td>Page number</td>
|
|
950
|
+
</tr>
|
|
951
|
+
<tr>
|
|
952
|
+
<td><code>limit</code></td>
|
|
953
|
+
<td>50</td>
|
|
954
|
+
<td>Entries per page</td>
|
|
955
|
+
</tr>
|
|
956
|
+
<tr>
|
|
957
|
+
<td><code>sort</code></td>
|
|
958
|
+
<td>createdAt</td>
|
|
959
|
+
<td>Field to sort by</td>
|
|
960
|
+
</tr>
|
|
961
|
+
<tr>
|
|
962
|
+
<td><code>order</code></td>
|
|
963
|
+
<td>desc</td>
|
|
964
|
+
<td><code>asc</code> or <code>desc</code></td>
|
|
965
|
+
</tr>
|
|
966
|
+
<tr>
|
|
967
|
+
<td><code>search</code></td>
|
|
968
|
+
<td>—</td>
|
|
969
|
+
<td>Full-text search query</td>
|
|
970
|
+
</tr>
|
|
971
|
+
</tbody>
|
|
972
|
+
</table>
|
|
973
|
+
<pre class="code-block"><code>// Response 200
|
|
974
|
+
{ "entries": [ { "id": "uuid", "data": { ... }, "createdAt": "...", "updatedAt": "..." } ], "total": 42, "page": 1, "limit": 50 }</code></pre>
|
|
975
|
+
|
|
976
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
|
|
977
|
+
</h3>
|
|
978
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
979
|
+
<p>Return a single entry by ID.</p>
|
|
980
|
+
|
|
981
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/entries</span>
|
|
982
|
+
</h3>
|
|
983
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
984
|
+
<p>Create a new entry. Data is validated against the collection schema.</p>
|
|
985
|
+
<pre class="code-block"><code>// Response 201 — returns the created entry</code></pre>
|
|
986
|
+
|
|
987
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
|
|
988
|
+
</h3>
|
|
989
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
990
|
+
<p>Update an entry. Data is validated against the schema.</p>
|
|
991
|
+
|
|
992
|
+
<h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
|
|
993
|
+
</h3>
|
|
994
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
995
|
+
<p>Delete a single entry.</p>
|
|
996
|
+
<pre class="code-block"><code>// Response 200
|
|
1120
997
|
{ "success": true }</code></pre>
|
|
1121
998
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
999
|
+
<h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/entries</span>
|
|
1000
|
+
</h3>
|
|
1001
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
1002
|
+
<p>Clear all entries from a collection. Irreversible.</p>
|
|
1003
|
+
<pre class="code-block"><code>// Response 200
|
|
1127
1004
|
{ "success": true }</code></pre>
|
|
1128
1005
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1006
|
+
<h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
1007
|
+
Export & Import</h3>
|
|
1008
|
+
|
|
1009
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/export</span>
|
|
1010
|
+
</h3>
|
|
1011
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
1012
|
+
<p>Download all entries as a file attachment.</p>
|
|
1013
|
+
<table class="table table-sm">
|
|
1014
|
+
<thead>
|
|
1015
|
+
<tr>
|
|
1016
|
+
<th>Query param</th>
|
|
1017
|
+
<th>Values</th>
|
|
1018
|
+
<th>Description</th>
|
|
1019
|
+
</tr>
|
|
1020
|
+
</thead>
|
|
1021
|
+
<tbody>
|
|
1022
|
+
<tr>
|
|
1023
|
+
<td><code>format</code></td>
|
|
1024
|
+
<td><code>json</code> (default), <code>csv</code></td>
|
|
1025
|
+
<td>Export format</td>
|
|
1026
|
+
</tr>
|
|
1027
|
+
</tbody>
|
|
1028
|
+
</table>
|
|
1029
|
+
<pre class="code-block"><code>// Response 200 — file download
|
|
1153
1030
|
// Content-Disposition: attachment; filename="blog-entries.json"</code></pre>
|
|
1154
1031
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1032
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/import</span>
|
|
1033
|
+
</h3>
|
|
1034
|
+
<p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
|
|
1035
|
+
<p>Bulk-import entries from a JSON array. Existing entries are not removed.</p>
|
|
1036
|
+
<table class="table table-sm">
|
|
1037
|
+
<thead>
|
|
1038
|
+
<tr>
|
|
1039
|
+
<th>Field</th>
|
|
1040
|
+
<th>Type</th>
|
|
1041
|
+
<th>Description</th>
|
|
1042
|
+
</tr>
|
|
1043
|
+
</thead>
|
|
1044
|
+
<tbody>
|
|
1045
|
+
<tr>
|
|
1046
|
+
<td><code>entries</code></td>
|
|
1047
|
+
<td>array</td>
|
|
1048
|
+
<td>Array of entry objects with a <code>data</code> field each</td>
|
|
1049
|
+
</tr>
|
|
1050
|
+
</tbody>
|
|
1051
|
+
</table>
|
|
1052
|
+
<pre class="code-block"><code>// Request body
|
|
1176
1053
|
{ "entries": [ { "data": { "title": "Post 1" } }, { "data": { "title": "Post 2" } } ] }
|
|
1177
1054
|
|
|
1178
1055
|
// Response 201
|
|
1179
1056
|
{ "imported": 2, "skipped": 0 }</code></pre>
|
|
1180
1057
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1058
|
+
<h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
1059
|
+
Public Access</h3>
|
|
1183
1060
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
(no auth), or restricted to a minimum role level.</p>
|
|
1061
|
+
<p>Public endpoints respect the per-collection <code>api</code> config. Each operation can be <strong>disabled</strong>,
|
|
1062
|
+
<strong>public</strong> (no auth), or restricted to a minimum role level.</p>
|
|
1187
1063
|
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1064
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/public</span>
|
|
1065
|
+
</h3>
|
|
1066
|
+
<p class="auth-note">Access level: per collection <code>api.read</code> config.</p>
|
|
1067
|
+
<p>List entries publicly. Supports the same pagination and search query params as the admin
|
|
1068
|
+
endpoint.</p>
|
|
1192
1069
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1070
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/public/:id</span>
|
|
1071
|
+
</h3>
|
|
1072
|
+
<p class="auth-note">Access level: per collection <code>api.read</code> config.</p>
|
|
1073
|
+
<p>Return a single entry publicly by ID.</p>
|
|
1197
1074
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1075
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/public</span>
|
|
1076
|
+
</h3>
|
|
1077
|
+
<p class="auth-note">Access level: per collection <code>api.create</code> config.</p>
|
|
1078
|
+
<p>Create an entry publicly (e.g. form submissions). Entry is tagged with <code>source: "api"</code>.
|
|
1079
|
+
</p>
|
|
1202
1080
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1081
|
+
<h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/public/:id</span>
|
|
1082
|
+
</h3>
|
|
1083
|
+
<p class="auth-note">Access level: per collection <code>api.update</code> config.</p>
|
|
1084
|
+
<p>Update an entry publicly.</p>
|
|
1207
1085
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1086
|
+
<h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/public/:id</span>
|
|
1087
|
+
</h3>
|
|
1088
|
+
<p class="auth-note">Access level: per collection <code>api.delete</code> config.</p>
|
|
1089
|
+
<p>Delete an entry publicly.</p>
|
|
1212
1090
|
|
|
1213
|
-
|
|
1214
|
-
</div>
|
|
1091
|
+
</div>
|
|
1215
1092
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
<div class="card-header" role="button" tabindex="0">
|
|
1219
|
-
<div class="card-header-content">
|
|
1220
|
-
<h2><span data-icon="eye"></span> Views API
|
|
1221
|
-
<span class="badge badge-warning" style="font-size:.7rem;margin-left:.4rem;">Pro</span>
|
|
1222
|
-
</h2>
|
|
1223
|
-
</div>
|
|
1224
|
-
<span class="card-collapse-icon" data-icon="chevron-down"></span>
|
|
1225
|
-
</div>
|
|
1226
|
-
<div class="card-body docs-body">
|
|
1227
|
-
<p>Views require a MongoDB connection. All admin endpoints require authentication and the
|
|
1228
|
-
<code>views</code> permission. View configs are stored in the <code>cms__views</code> MongoDB collection
|
|
1229
|
-
on the <code>default</code> connection.</p>
|
|
1093
|
+
<!-- Views API -->
|
|
1094
|
+
<div class="tab-panel docs-body">
|
|
1230
1095
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1096
|
+
<p>Views require a MongoDB connection. All admin endpoints require authentication and the
|
|
1097
|
+
<code>views</code> permission. View configs are stored in the <code>cms__views</code> MongoDB
|
|
1098
|
+
collection.</p>
|
|
1233
1099
|
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
<p>List all view configs, sorted by creation date descending.</p>
|
|
1100
|
+
<h3 style="margin-top:16px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
1101
|
+
Admin Endpoints</h3>
|
|
1237
1102
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1103
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/views</span></h3>
|
|
1104
|
+
<p class="auth-note">Requires: <code>views</code> permission</p>
|
|
1105
|
+
<p>List all view configs, sorted by creation date descending.</p>
|
|
1106
|
+
|
|
1107
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/views</span>
|
|
1108
|
+
</h3>
|
|
1109
|
+
<p class="auth-note">Requires: <code>views</code> permission</p>
|
|
1110
|
+
<p>Create a new view config. Returns <code>201</code> on success.</p>
|
|
1111
|
+
<pre class="code-block"><code>{
|
|
1242
1112
|
"title": "Active Premium Users",
|
|
1243
|
-
"slug": "active-premium-users",
|
|
1244
|
-
"description": "...",
|
|
1113
|
+
"slug": "active-premium-users",
|
|
1245
1114
|
"connection": "default",
|
|
1246
1115
|
"pipeline": {
|
|
1247
|
-
"source": "users",
|
|
1116
|
+
"source": "users",
|
|
1248
1117
|
"stages": [
|
|
1249
1118
|
{ "type": "$match", "config": { "data.status": "active" } },
|
|
1250
1119
|
{ "type": "$sort", "config": { "meta.createdAt": -1 } },
|
|
1251
1120
|
{ "type": "$project", "config": { "data.name": 1, "data.email": 1 } }
|
|
1252
1121
|
]
|
|
1253
1122
|
},
|
|
1254
|
-
"display": {
|
|
1255
|
-
|
|
1256
|
-
"columns": [
|
|
1257
|
-
{ "key": "data.name", "label": "Name" },
|
|
1258
|
-
{ "key": "data.email", "label": "Email" }
|
|
1259
|
-
],
|
|
1260
|
-
"pageSize": 25
|
|
1261
|
-
},
|
|
1262
|
-
"access": {
|
|
1263
|
-
"roles": ["admin", "manager"],
|
|
1264
|
-
"public": false
|
|
1265
|
-
}
|
|
1123
|
+
"display": { "mode": "table", "columns": [ { "key": "data.name", "label": "Name" } ], "pageSize": 25 },
|
|
1124
|
+
"access": { "roles": ["admin", "manager"], "public": false }
|
|
1266
1125
|
}</code></pre>
|
|
1267
1126
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1327
|
-
<p>List all action configs.</p>
|
|
1328
|
-
|
|
1329
|
-
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/actions</span></h3>
|
|
1330
|
-
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1331
|
-
<p>Create a new action config. Returns <code>201</code> on success.</p>
|
|
1332
|
-
<pre class="code-block"><code>{
|
|
1127
|
+
<h3><span class="method-badge method-get">GET</span><span
|
|
1128
|
+
class="endpoint-path">/api/views/:slug</span></h3>
|
|
1129
|
+
<p class="auth-note">Requires: <code>views</code> permission</p>
|
|
1130
|
+
<p>Return a single view config by slug.</p>
|
|
1131
|
+
|
|
1132
|
+
<h3><span class="method-badge method-put">PUT</span><span
|
|
1133
|
+
class="endpoint-path">/api/views/:slug</span></h3>
|
|
1134
|
+
<p class="auth-note">Requires: <code>views</code> permission</p>
|
|
1135
|
+
<p>Update a view config. Accepts the same body shape as POST; all fields are optional.</p>
|
|
1136
|
+
|
|
1137
|
+
<h3><span class="method-badge method-delete">DELETE</span><span
|
|
1138
|
+
class="endpoint-path">/api/views/:slug</span></h3>
|
|
1139
|
+
<p class="auth-note">Requires: <code>views</code> permission</p>
|
|
1140
|
+
<p>Delete a view config.</p>
|
|
1141
|
+
|
|
1142
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/views/:slug/execute</span>
|
|
1143
|
+
</h3>
|
|
1144
|
+
<p class="auth-note">Requires: <code>views</code> permission</p>
|
|
1145
|
+
<p>Execute the view's aggregation pipeline and return paginated results. Query params:
|
|
1146
|
+
<code>page</code> (default 1), <code>limit</code> (default 25).</p>
|
|
1147
|
+
<pre class="code-block"><code>// Response
|
|
1148
|
+
{ "results": [ ... ], "total": 142, "page": 1, "limit": 25 }</code></pre>
|
|
1149
|
+
|
|
1150
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/views/collection/:slug</span>
|
|
1151
|
+
</h3>
|
|
1152
|
+
<p class="auth-note">Requires: <code>views</code> permission</p>
|
|
1153
|
+
<p>List all view configs whose <code>pipeline.source</code> matches the given collection slug.</p>
|
|
1154
|
+
|
|
1155
|
+
<h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
1156
|
+
Public Endpoint</h3>
|
|
1157
|
+
|
|
1158
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/views/:slug/public</span>
|
|
1159
|
+
</h3>
|
|
1160
|
+
<p class="auth-note">Access level: per view <code>access</code> config</p>
|
|
1161
|
+
<p>Execute the view publicly. If <code>access.public</code> is <code>false</code>, a valid JWT and a
|
|
1162
|
+
role listed in <code>access.roles</code> is required.</p>
|
|
1163
|
+
|
|
1164
|
+
</div>
|
|
1165
|
+
|
|
1166
|
+
<!-- Actions API -->
|
|
1167
|
+
<div class="tab-panel docs-body">
|
|
1168
|
+
|
|
1169
|
+
<p>Actions require a MongoDB connection. All admin endpoints require authentication and the
|
|
1170
|
+
<code>actions</code> permission. Action configs are stored in <code>cms__actions</code>.</p>
|
|
1171
|
+
|
|
1172
|
+
<h3 style="margin-top:16px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
1173
|
+
Admin Endpoints</h3>
|
|
1174
|
+
|
|
1175
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/actions</span>
|
|
1176
|
+
</h3>
|
|
1177
|
+
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1178
|
+
<p>List all action configs.</p>
|
|
1179
|
+
|
|
1180
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/actions</span>
|
|
1181
|
+
</h3>
|
|
1182
|
+
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1183
|
+
<p>Create a new action config. Returns <code>201</code> on success.</p>
|
|
1184
|
+
<pre class="code-block"><code>{
|
|
1333
1185
|
"title": "Approve Application",
|
|
1334
|
-
"slug": "approve-application",
|
|
1335
|
-
"description": "...",
|
|
1186
|
+
"slug": "approve-application",
|
|
1336
1187
|
"collection": "applications",
|
|
1337
|
-
"trigger": {
|
|
1338
|
-
"type": "manual",
|
|
1339
|
-
"label": "Approve",
|
|
1340
|
-
"icon": "check-circle",
|
|
1341
|
-
"confirmMessage": "Approve this application?" // null to skip confirmation
|
|
1342
|
-
},
|
|
1188
|
+
"trigger": { "type": "manual", "label": "Approve", "icon": "check-circle", "confirmMessage": "Approve this application?" },
|
|
1343
1189
|
"steps": [
|
|
1344
|
-
{ "type": "updateField",
|
|
1345
|
-
{ "type": "updateField",
|
|
1346
|
-
{ "type": "
|
|
1347
|
-
|
|
1348
|
-
{ "type": "email", "config": { "to": "{{entry.data.email}}",
|
|
1349
|
-
"subject": "Application approved",
|
|
1350
|
-
"template": "Hi {{entry.data.name}}, your application is approved." } }
|
|
1190
|
+
{ "type": "updateField", "config": { "field": "status", "value": "approved" } },
|
|
1191
|
+
{ "type": "updateField", "config": { "field": "approvedAt", "value": "{{now}}" } },
|
|
1192
|
+
{ "type": "email", "config": { "to": "{{entry.data.email}}", "subject": "Application approved",
|
|
1193
|
+
"template": "Hi {{entry.data.name}}, your application is approved." } }
|
|
1351
1194
|
],
|
|
1352
1195
|
"access": { "roles": ["admin", "manager"] }
|
|
1353
1196
|
}</code></pre>
|
|
1354
1197
|
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1198
|
+
<h3><span class="method-badge method-get">GET</span><span
|
|
1199
|
+
class="endpoint-path">/api/actions/:slug</span></h3>
|
|
1200
|
+
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1201
|
+
<p>Return a single action config by slug.</p>
|
|
1202
|
+
|
|
1203
|
+
<h3><span class="method-badge method-put">PUT</span><span
|
|
1204
|
+
class="endpoint-path">/api/actions/:slug</span></h3>
|
|
1205
|
+
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1206
|
+
<p>Update an action config.</p>
|
|
1207
|
+
|
|
1208
|
+
<h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/actions/:slug</span>
|
|
1209
|
+
</h3>
|
|
1210
|
+
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1211
|
+
<p>Delete an action config.</p>
|
|
1212
|
+
|
|
1213
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/actions/:slug/execute</span>
|
|
1214
|
+
</h3>
|
|
1215
|
+
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1216
|
+
<p>Execute an action against a specific entry.</p>
|
|
1217
|
+
<pre class="code-block"><code>// Request body
|
|
1371
1218
|
{ "entryId": "uuid-of-the-entry" }
|
|
1372
1219
|
|
|
1373
1220
|
// Response
|
|
1374
|
-
{
|
|
1375
|
-
"success": true,
|
|
1376
|
-
"stepsCompleted": 4,
|
|
1377
|
-
"results": [
|
|
1378
|
-
{ "type": "updateField", "success": true, "result": { "field": "status", "value": "approved" } },
|
|
1379
|
-
{ "type": "email", "success": true, "result": { "to": "user@example.com" } }
|
|
1380
|
-
]
|
|
1381
|
-
}
|
|
1221
|
+
{ "success": true, "stepsCompleted": 4, "results": [ { "type": "updateField", "success": true, ... } ] }
|
|
1382
1222
|
|
|
1383
|
-
// Partial failure
|
|
1384
|
-
{
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
}</code></pre>
|
|
1223
|
+
// Partial failure
|
|
1224
|
+
{ "success": false, "stepsCompleted": 2, "results": [ ..., { "type": "webhook", "success": false, "error": "Webhook returned HTTP 500" } ] }</code></pre>
|
|
1225
|
+
|
|
1226
|
+
<h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/actions/collection/:slug</span>
|
|
1227
|
+
</h3>
|
|
1228
|
+
<p class="auth-note">Requires: <code>actions</code> permission</p>
|
|
1229
|
+
<p>List all action configs targeting a given collection slug. Used by the entry list view to populate
|
|
1230
|
+
per-row trigger buttons.</p>
|
|
1392
1231
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
<p>List all action configs targeting a given collection slug. Used by the entry list view to
|
|
1396
|
-
populate per-row trigger buttons.</p>
|
|
1232
|
+
<h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
|
|
1233
|
+
Public Endpoint</h3>
|
|
1397
1234
|
|
|
1398
|
-
|
|
1399
|
-
|
|
1235
|
+
<h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/actions/:slug/public</span>
|
|
1236
|
+
</h3>
|
|
1237
|
+
<p class="auth-note">Requires: JWT + role in <code>access.roles</code></p>
|
|
1238
|
+
<p>Execute an action publicly. Always requires a valid JWT — the role is checked against <code>access.roles</code>.
|
|
1239
|
+
Request body and response shape are identical to the admin <code>/execute</code> endpoint.</p>
|
|
1400
1240
|
|
|
1401
|
-
|
|
1402
|
-
<p class="auth-note">Requires: JWT + role in <code>access.roles</code></p>
|
|
1403
|
-
<p>Execute an action publicly. Always requires a valid JWT — the role is checked against
|
|
1404
|
-
<code>access.roles</code>. Request body and response shape are identical to the admin
|
|
1405
|
-
<code>/execute</code> endpoint.</p>
|
|
1241
|
+
</div>
|
|
1406
1242
|
|
|
1407
1243
|
</div>
|
|
1408
1244
|
</div>
|