domma-cms 0.25.14 → 0.25.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/admin/js/app.js +2 -2
  2. package/admin/js/templates/api-reference.html +68 -1233
  3. package/admin/js/templates/docs/api-actions.html +146 -0
  4. package/admin/js/templates/docs/api-authentication.html +202 -0
  5. package/admin/js/templates/docs/api-collections.html +347 -0
  6. package/admin/js/templates/docs/api-layouts.html +123 -0
  7. package/admin/js/templates/docs/api-media.html +158 -0
  8. package/admin/js/templates/docs/api-navigation.html +99 -0
  9. package/admin/js/templates/docs/api-pages.html +214 -0
  10. package/admin/js/templates/docs/api-plugins.html +136 -0
  11. package/admin/js/templates/docs/api-settings.html +148 -0
  12. package/admin/js/templates/docs/api-users.html +189 -0
  13. package/admin/js/templates/docs/api-views.html +142 -0
  14. package/admin/js/templates/docs/components-howto.html +175 -0
  15. package/admin/js/templates/docs/components-reference.html +259 -0
  16. package/admin/js/templates/docs/components-rules.html +167 -0
  17. package/admin/js/templates/docs/components-walkthrough.html +167 -0
  18. package/admin/js/templates/docs/tutorial-crud.html +344 -0
  19. package/admin/js/templates/docs/tutorial-forms.html +93 -0
  20. package/admin/js/templates/docs/tutorial-plugin.html +234 -0
  21. package/admin/js/templates/docs/usage-actions.html +122 -0
  22. package/admin/js/templates/docs/usage-cta-shortcode.html +124 -0
  23. package/admin/js/templates/docs/usage-dconfig.html +148 -0
  24. package/admin/js/templates/docs/usage-media.html +25 -0
  25. package/admin/js/templates/docs/usage-navigation.html +31 -0
  26. package/admin/js/templates/docs/usage-pages.html +68 -0
  27. package/admin/js/templates/docs/usage-plugins.html +36 -0
  28. package/admin/js/templates/docs/usage-shortcodes.html +810 -0
  29. package/admin/js/templates/docs/usage-site-settings.html +52 -0
  30. package/admin/js/templates/docs/usage-users-roles.html +84 -0
  31. package/admin/js/templates/docs/usage-views.html +105 -0
  32. package/admin/js/templates/documentation.html +60 -1522
  33. package/admin/js/templates/tutorials.html +46 -659
  34. package/admin/js/views/api-reference.js +1 -1
  35. package/admin/js/views/doc-pages.js +1 -0
  36. package/admin/js/views/documentation.js +1 -1
  37. package/admin/js/views/index.js +1 -1
  38. package/admin/js/views/tutorials.js +1 -1
  39. package/config/menus/admin-sidebar.json +76 -6
  40. package/package.json +1 -1
  41. package/public/js/site.js +1 -1
  42. package/server/server.js +3 -1
  43. package/server/services/menus.js +18 -0
  44. package/server/services/renderer.js +2 -0
  45. package/server/services/sidebar-migration.js +145 -3
@@ -0,0 +1,347 @@
1
+ <div class="view-header">
2
+ <h1><span data-icon="code"></span> API · Collections</h1>
3
+ <a href="#/api-reference" class="btn btn-ghost btn-sm"><span data-icon="arrow-left"></span> API overview</a>
4
+ </div>
5
+ <style>
6
+ .method-badge {
7
+ display: inline-block;
8
+ font-size: 11px;
9
+ font-weight: 700;
10
+ letter-spacing: 0.5px;
11
+ padding: 2px 7px;
12
+ border-radius: 4px;
13
+ font-family: var(--dm-font-mono, monospace);
14
+ margin-right: 6px;
15
+ vertical-align: middle;
16
+ }
17
+
18
+ .method-get {
19
+ background: #d1fae5;
20
+ color: #065f46;
21
+ }
22
+
23
+ .method-post {
24
+ background: #dbeafe;
25
+ color: #1e40af;
26
+ }
27
+
28
+ .method-put {
29
+ background: #fef3c7;
30
+ color: #92400e;
31
+ }
32
+
33
+ .method-patch {
34
+ background: #ccfbf1;
35
+ color: #134e4a;
36
+ }
37
+
38
+ .method-delete {
39
+ background: #fee2e2;
40
+ color: #991b1b;
41
+ }
42
+
43
+ .endpoint-path {
44
+ font-family: var(--dm-font-mono, monospace);
45
+ font-size: 14px;
46
+ }
47
+
48
+ .auth-note {
49
+ font-size: 12px;
50
+ color: var(--dm-color-text-muted, #6b7280);
51
+ margin: 4px 0 12px;
52
+ }
53
+
54
+ .auth-note code {
55
+ font-size: 11px;
56
+ }
57
+
58
+ .docs-body h3 {
59
+ margin-top: 24px;
60
+ margin-bottom: 8px;
61
+ }
62
+
63
+ .docs-body h3:first-child {
64
+ margin-top: 0;
65
+ }
66
+ </style>
67
+
68
+ <div class="row">
69
+ <div class="col-12">
70
+ <div class="docs-body">
71
+
72
+ <p>Collections have two access planes: <strong>admin endpoints</strong> (authenticated, role-gated)
73
+ and <strong>public
74
+ endpoints</strong> (access level configured per collection).</p>
75
+
76
+ <h3 style="margin-top:16px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
77
+ Schema Management</h3>
78
+
79
+ <h3><span class="method-badge method-get">GET</span><span
80
+ class="endpoint-path">/api/collections</span></h3>
81
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
82
+ <p>List all collection schemas (metadata only, no entries).</p>
83
+ <pre class="code-block"><code>// Response 200
84
+ [ { "slug": "blog", "title": "Blog Posts", "description": "...", "fields": [...] } ]</code></pre>
85
+
86
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/pro-status</span>
87
+ </h3>
88
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
89
+ <p>Check whether the Pro (MongoDB) storage adapter is available.</p>
90
+ <pre class="code-block"><code>// Response 200 (free)
91
+ { "pro": false, "connections": [] }
92
+
93
+ // Response 200 (pro)
94
+ { "pro": true, "connections": ["default", "analytics"] }</code></pre>
95
+
96
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/connections</span>
97
+ </h3>
98
+ <p class="auth-note">Requires Bearer token + admin role.</p>
99
+ <p>Return configured MongoDB connections from <code>config/connections.json</code>.</p>
100
+ <pre class="code-block"><code>// Response 200
101
+ { "default": { "type": "mongodb", "uri": "mongodb://localhost:27017", "database": "my_cms" } }</code></pre>
102
+
103
+ <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/connections</span>
104
+ </h3>
105
+ <p class="auth-note">Requires Bearer token + admin role.</p>
106
+ <p>Save MongoDB connection definitions. Each connection requires <code>type</code>, <code>uri</code>,
107
+ and <code>database</code>.</p>
108
+ <pre class="code-block"><code>// Response 200
109
+ { "success": true }
110
+
111
+ // Error 400
112
+ { "error": "Connection \"default\" requires type, uri, and database" }</code></pre>
113
+
114
+ <h3><span class="method-badge method-post">POST</span><span
115
+ class="endpoint-path">/api/collections</span></h3>
116
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
117
+ <p>Create a new collection. A <code>slug</code> is auto-generated from the title if not provided.</p>
118
+ <table class="table table-sm">
119
+ <thead>
120
+ <tr>
121
+ <th>Field</th>
122
+ <th>Type</th>
123
+ <th>Description</th>
124
+ </tr>
125
+ </thead>
126
+ <tbody>
127
+ <tr>
128
+ <td><code>title</code></td>
129
+ <td>string</td>
130
+ <td>Required. Human-readable collection name</td>
131
+ </tr>
132
+ <tr>
133
+ <td><code>slug</code></td>
134
+ <td>string</td>
135
+ <td>Optional. URL-safe identifier. Auto-generated if omitted.</td>
136
+ </tr>
137
+ <tr>
138
+ <td><code>description</code></td>
139
+ <td>string</td>
140
+ <td>Optional description</td>
141
+ </tr>
142
+ <tr>
143
+ <td><code>fields</code></td>
144
+ <td>array</td>
145
+ <td>Field definitions</td>
146
+ </tr>
147
+ <tr>
148
+ <td><code>api</code></td>
149
+ <td>object</td>
150
+ <td>Public API access config per operation</td>
151
+ </tr>
152
+ <tr>
153
+ <td><code>storage</code></td>
154
+ <td>object</td>
155
+ <td>Optional Pro: <code>{ "adapter": "mongodb", "connection": "default" }</code></td>
156
+ </tr>
157
+ </tbody>
158
+ </table>
159
+ <pre class="code-block"><code>// Response 201 — returns the created schema object
160
+
161
+ // Error 409
162
+ { "error": "A collection with that slug already exists" }</code></pre>
163
+
164
+ <h3><span class="method-badge method-get">GET</span><span
165
+ class="endpoint-path">/api/collections/:slug</span></h3>
166
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
167
+ <p>Return the schema for a single collection by slug.</p>
168
+
169
+ <h3><span class="method-badge method-put">PUT</span><span
170
+ class="endpoint-path">/api/collections/:slug</span></h3>
171
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
172
+ <p>Update a collection schema.</p>
173
+
174
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug</span>
175
+ </h3>
176
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
177
+ <p>Delete a collection and all its entries. Preset collections cannot be deleted.</p>
178
+ <pre class="code-block"><code>// Response 200
179
+ { "success": true }
180
+
181
+ // Error 403
182
+ { "error": "Cannot delete a preset collection" }</code></pre>
183
+
184
+ <h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
185
+ Admin Entry CRUD</h3>
186
+
187
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/entries</span>
188
+ </h3>
189
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
190
+ <p>List entries with pagination, sorting, and full-text search.</p>
191
+ <table class="table table-sm">
192
+ <thead>
193
+ <tr>
194
+ <th>Query param</th>
195
+ <th>Default</th>
196
+ <th>Description</th>
197
+ </tr>
198
+ </thead>
199
+ <tbody>
200
+ <tr>
201
+ <td><code>page</code></td>
202
+ <td>1</td>
203
+ <td>Page number</td>
204
+ </tr>
205
+ <tr>
206
+ <td><code>limit</code></td>
207
+ <td>50</td>
208
+ <td>Entries per page</td>
209
+ </tr>
210
+ <tr>
211
+ <td><code>sort</code></td>
212
+ <td>createdAt</td>
213
+ <td>Field to sort by</td>
214
+ </tr>
215
+ <tr>
216
+ <td><code>order</code></td>
217
+ <td>desc</td>
218
+ <td><code>asc</code> or <code>desc</code></td>
219
+ </tr>
220
+ <tr>
221
+ <td><code>search</code></td>
222
+ <td>—</td>
223
+ <td>Full-text search query</td>
224
+ </tr>
225
+ </tbody>
226
+ </table>
227
+ <pre class="code-block"><code>// Response 200
228
+ { "entries": [ { "id": "uuid", "data": { ... }, "createdAt": "...", "updatedAt": "..." } ], "total": 42, "page": 1, "limit": 50 }</code></pre>
229
+
230
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
231
+ </h3>
232
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
233
+ <p>Return a single entry by ID.</p>
234
+
235
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/entries</span>
236
+ </h3>
237
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
238
+ <p>Create a new entry. Data is validated against the collection schema.</p>
239
+ <pre class="code-block"><code>// Response 201 — returns the created entry</code></pre>
240
+
241
+ <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
242
+ </h3>
243
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
244
+ <p>Update an entry. Data is validated against the schema.</p>
245
+
246
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
247
+ </h3>
248
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
249
+ <p>Delete a single entry.</p>
250
+ <pre class="code-block"><code>// Response 200
251
+ { "success": true }</code></pre>
252
+
253
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/entries</span>
254
+ </h3>
255
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
256
+ <p>Clear all entries from a collection. Irreversible.</p>
257
+ <pre class="code-block"><code>// Response 200
258
+ { "success": true }</code></pre>
259
+
260
+ <h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
261
+ Export &amp; Import</h3>
262
+
263
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/export</span>
264
+ </h3>
265
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
266
+ <p>Download all entries as a file attachment.</p>
267
+ <table class="table table-sm">
268
+ <thead>
269
+ <tr>
270
+ <th>Query param</th>
271
+ <th>Values</th>
272
+ <th>Description</th>
273
+ </tr>
274
+ </thead>
275
+ <tbody>
276
+ <tr>
277
+ <td><code>format</code></td>
278
+ <td><code>json</code> (default), <code>csv</code></td>
279
+ <td>Export format</td>
280
+ </tr>
281
+ </tbody>
282
+ </table>
283
+ <pre class="code-block"><code>// Response 200 — file download
284
+ // Content-Disposition: attachment; filename="blog-entries.json"</code></pre>
285
+
286
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/import</span>
287
+ </h3>
288
+ <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
289
+ <p>Bulk-import entries from a JSON array. Existing entries are not removed.</p>
290
+ <table class="table table-sm">
291
+ <thead>
292
+ <tr>
293
+ <th>Field</th>
294
+ <th>Type</th>
295
+ <th>Description</th>
296
+ </tr>
297
+ </thead>
298
+ <tbody>
299
+ <tr>
300
+ <td><code>entries</code></td>
301
+ <td>array</td>
302
+ <td>Array of entry objects with a <code>data</code> field each</td>
303
+ </tr>
304
+ </tbody>
305
+ </table>
306
+ <pre class="code-block"><code>// Request body
307
+ { "entries": [ { "data": { "title": "Post 1" } }, { "data": { "title": "Post 2" } } ] }
308
+
309
+ // Response 201
310
+ { "imported": 2, "skipped": 0 }</code></pre>
311
+
312
+ <h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
313
+ Public Access</h3>
314
+
315
+ <p>Public endpoints respect the per-collection <code>api</code> config. Each operation can be <strong>disabled</strong>,
316
+ <strong>public</strong> (no auth), or restricted to a minimum role level.</p>
317
+
318
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/public</span>
319
+ </h3>
320
+ <p class="auth-note">Access level: per collection <code>api.read</code> config.</p>
321
+ <p>List entries publicly. Supports the same pagination and search query params as the admin
322
+ endpoint.</p>
323
+
324
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/public/:id</span>
325
+ </h3>
326
+ <p class="auth-note">Access level: per collection <code>api.read</code> config.</p>
327
+ <p>Return a single entry publicly by ID.</p>
328
+
329
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/public</span>
330
+ </h3>
331
+ <p class="auth-note">Access level: per collection <code>api.create</code> config.</p>
332
+ <p>Create an entry publicly (e.g. form submissions). Entry is tagged with <code>source: "api"</code>.
333
+ </p>
334
+
335
+ <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/public/:id</span>
336
+ </h3>
337
+ <p class="auth-note">Access level: per collection <code>api.update</code> config.</p>
338
+ <p>Update an entry publicly.</p>
339
+
340
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/public/:id</span>
341
+ </h3>
342
+ <p class="auth-note">Access level: per collection <code>api.delete</code> config.</p>
343
+ <p>Delete an entry publicly.</p>
344
+
345
+ </div>
346
+ </div>
347
+ </div>
@@ -0,0 +1,123 @@
1
+ <div class="view-header">
2
+ <h1><span data-icon="code"></span> API · Layouts</h1>
3
+ <a href="#/api-reference" class="btn btn-ghost btn-sm"><span data-icon="arrow-left"></span> API overview</a>
4
+ </div>
5
+ <style>
6
+ .method-badge {
7
+ display: inline-block;
8
+ font-size: 11px;
9
+ font-weight: 700;
10
+ letter-spacing: 0.5px;
11
+ padding: 2px 7px;
12
+ border-radius: 4px;
13
+ font-family: var(--dm-font-mono, monospace);
14
+ margin-right: 6px;
15
+ vertical-align: middle;
16
+ }
17
+
18
+ .method-get {
19
+ background: #d1fae5;
20
+ color: #065f46;
21
+ }
22
+
23
+ .method-post {
24
+ background: #dbeafe;
25
+ color: #1e40af;
26
+ }
27
+
28
+ .method-put {
29
+ background: #fef3c7;
30
+ color: #92400e;
31
+ }
32
+
33
+ .method-patch {
34
+ background: #ccfbf1;
35
+ color: #134e4a;
36
+ }
37
+
38
+ .method-delete {
39
+ background: #fee2e2;
40
+ color: #991b1b;
41
+ }
42
+
43
+ .endpoint-path {
44
+ font-family: var(--dm-font-mono, monospace);
45
+ font-size: 14px;
46
+ }
47
+
48
+ .auth-note {
49
+ font-size: 12px;
50
+ color: var(--dm-color-text-muted, #6b7280);
51
+ margin: 4px 0 12px;
52
+ }
53
+
54
+ .auth-note code {
55
+ font-size: 11px;
56
+ }
57
+
58
+ .docs-body h3 {
59
+ margin-top: 24px;
60
+ margin-bottom: 8px;
61
+ }
62
+
63
+ .docs-body h3:first-child {
64
+ margin-top: 0;
65
+ }
66
+ </style>
67
+
68
+ <div class="row">
69
+ <div class="col-12">
70
+ <div class="docs-body">
71
+
72
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/layouts</span>
73
+ </h3>
74
+ <p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
75
+ <p>Return all layout presets from <code>config/presets.json</code>.</p>
76
+ <pre class="code-block"><code>// Response 200
77
+ {
78
+ "default": { "label": "Default", "sections": [...] },
79
+ "full-width": { "label": "Full Width", "sections": [...] }
80
+ }</code></pre>
81
+
82
+ <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/layouts</span>
83
+ </h3>
84
+ <p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
85
+ <p>Replace the entire layout presets object.</p>
86
+ <pre class="code-block"><code>// Response 200
87
+ { "success": true }</code></pre>
88
+
89
+ <h3><span class="method-badge method-get">GET</span><span
90
+ class="endpoint-path">/api/layouts/options</span></h3>
91
+ <p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
92
+ <p>Return layout display options stored in <code>config/site.json</code> under
93
+ <code>layoutOptions</code>.</p>
94
+ <pre class="code-block"><code>// Response 200
95
+ { "spacerSize": 8 }</code></pre>
96
+
97
+ <h3><span class="method-badge method-put">PUT</span><span
98
+ class="endpoint-path">/api/layouts/options</span></h3>
99
+ <p class="auth-note">Requires Bearer token + <code>layouts</code> permission.</p>
100
+ <p>Merge layout option updates into the existing options. Existing keys not included are
101
+ preserved.</p>
102
+ <table class="table table-sm">
103
+ <thead>
104
+ <tr>
105
+ <th>Field</th>
106
+ <th>Type</th>
107
+ <th>Description</th>
108
+ </tr>
109
+ </thead>
110
+ <tbody>
111
+ <tr>
112
+ <td><code>spacerSize</code></td>
113
+ <td>number</td>
114
+ <td>Default spacer block size in pixels</td>
115
+ </tr>
116
+ </tbody>
117
+ </table>
118
+ <pre class="code-block"><code>// Response 200
119
+ { "success": true }</code></pre>
120
+
121
+ </div>
122
+ </div>
123
+ </div>
@@ -0,0 +1,158 @@
1
+ <div class="view-header">
2
+ <h1><span data-icon="code"></span> API · Media</h1>
3
+ <a href="#/api-reference" class="btn btn-ghost btn-sm"><span data-icon="arrow-left"></span> API overview</a>
4
+ </div>
5
+ <style>
6
+ .method-badge {
7
+ display: inline-block;
8
+ font-size: 11px;
9
+ font-weight: 700;
10
+ letter-spacing: 0.5px;
11
+ padding: 2px 7px;
12
+ border-radius: 4px;
13
+ font-family: var(--dm-font-mono, monospace);
14
+ margin-right: 6px;
15
+ vertical-align: middle;
16
+ }
17
+
18
+ .method-get {
19
+ background: #d1fae5;
20
+ color: #065f46;
21
+ }
22
+
23
+ .method-post {
24
+ background: #dbeafe;
25
+ color: #1e40af;
26
+ }
27
+
28
+ .method-put {
29
+ background: #fef3c7;
30
+ color: #92400e;
31
+ }
32
+
33
+ .method-patch {
34
+ background: #ccfbf1;
35
+ color: #134e4a;
36
+ }
37
+
38
+ .method-delete {
39
+ background: #fee2e2;
40
+ color: #991b1b;
41
+ }
42
+
43
+ .endpoint-path {
44
+ font-family: var(--dm-font-mono, monospace);
45
+ font-size: 14px;
46
+ }
47
+
48
+ .auth-note {
49
+ font-size: 12px;
50
+ color: var(--dm-color-text-muted, #6b7280);
51
+ margin: 4px 0 12px;
52
+ }
53
+
54
+ .auth-note code {
55
+ font-size: 11px;
56
+ }
57
+
58
+ .docs-body h3 {
59
+ margin-top: 24px;
60
+ margin-bottom: 8px;
61
+ }
62
+
63
+ .docs-body h3:first-child {
64
+ margin-top: 0;
65
+ }
66
+ </style>
67
+
68
+ <div class="row">
69
+ <div class="col-12">
70
+ <div class="docs-body">
71
+
72
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/media</span></h3>
73
+ <p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
74
+ <p>List all media files in the uploads directory.</p>
75
+ <pre class="code-block"><code>// Response 200
76
+ [ { "name": "hero.jpg", "url": "/media/hero.jpg", "size": 204800, "mime": "image/jpeg" } ]</code></pre>
77
+
78
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/media</span>
79
+ </h3>
80
+ <p class="auth-note">Requires Bearer token + <code>media</code> permission. Content-Type: <code>multipart/form-data</code>.
81
+ </p>
82
+ <p>Upload one or more files. Returns a single object for one file, or an array for multiple.</p>
83
+ <pre class="code-block"><code>// Response 201 (single)
84
+ { "name": "photo.jpg", "url": "/media/photo.jpg", "size": 98304, "mime": "image/jpeg" }</code></pre>
85
+
86
+ <h3><span class="method-badge method-patch">PATCH</span><span
87
+ class="endpoint-path">/api/media/:name</span></h3>
88
+ <p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
89
+ <p>Rename a media file. Fails with 409 if the new name already exists.</p>
90
+ <table class="table table-sm">
91
+ <thead>
92
+ <tr>
93
+ <th>Field</th>
94
+ <th>Type</th>
95
+ <th>Description</th>
96
+ </tr>
97
+ </thead>
98
+ <tbody>
99
+ <tr>
100
+ <td><code>newName</code></td>
101
+ <td>string</td>
102
+ <td>New filename (will be sanitised)</td>
103
+ </tr>
104
+ </tbody>
105
+ </table>
106
+ <pre class="code-block"><code>// Response 200
107
+ { "name": "new-photo.jpg", "url": "/media/new-photo.jpg", ... }</code></pre>
108
+
109
+ <h3><span class="method-badge method-delete">DELETE</span><span
110
+ class="endpoint-path">/api/media/:name</span></h3>
111
+ <p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
112
+ <p>Delete a media file from the uploads directory.</p>
113
+ <pre class="code-block"><code>// Response 200
114
+ { "success": true }</code></pre>
115
+
116
+ <h3><span class="method-badge method-get">GET</span><span
117
+ class="endpoint-path">/api/media/:name/info</span></h3>
118
+ <p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
119
+ <p>Return image metadata (dimensions, format, file size) for editable image formats (JPEG, PNG, WebP,
120
+ GIF, TIFF).</p>
121
+ <pre class="code-block"><code>// Response 200
122
+ { "width": 1920, "height": 1080, "format": "jpeg", "size": 204800 }</code></pre>
123
+
124
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/media/:name/transform</span>
125
+ </h3>
126
+ <p class="auth-note">Requires Bearer token + <code>media</code> permission.</p>
127
+ <p>Apply image transformations (resize, crop, rotate, watermark, etc.) and optionally save to a new
128
+ filename.</p>
129
+ <table class="table table-sm">
130
+ <thead>
131
+ <tr>
132
+ <th>Field</th>
133
+ <th>Type</th>
134
+ <th>Description</th>
135
+ </tr>
136
+ </thead>
137
+ <tbody>
138
+ <tr>
139
+ <td><code>operations</code></td>
140
+ <td>object</td>
141
+ <td>Transformation operations to apply</td>
142
+ </tr>
143
+ <tr>
144
+ <td><code>saveAs</code></td>
145
+ <td>string</td>
146
+ <td>Optional. Output filename. Defaults to overwriting the source.</td>
147
+ </tr>
148
+ </tbody>
149
+ </table>
150
+ <pre class="code-block"><code>// Request body
151
+ { "operations": { "resize": { "width": 800, "height": 600 }, "format": "webp" }, "saveAs": "hero-800.webp" }
152
+
153
+ // Response 200
154
+ { "name": "hero-800.webp", "url": "/media/hero-800.webp", ... }</code></pre>
155
+
156
+ </div>
157
+ </div>
158
+ </div>