domma-cms 0.93.0 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/admin/css/admin.css +1 -1
  2. package/admin/js/app.js +2 -2
  3. package/admin/js/templates/docs/api-actions.html +86 -64
  4. package/admin/js/templates/docs/api-authentication.html +159 -123
  5. package/admin/js/templates/docs/api-builder.html +197 -0
  6. package/admin/js/templates/docs/api-collections.html +199 -259
  7. package/admin/js/templates/docs/api-external.html +225 -0
  8. package/admin/js/templates/docs/api-forms.html +268 -0
  9. package/admin/js/templates/docs/api-layouts.html +70 -45
  10. package/admin/js/templates/docs/api-media.html +57 -80
  11. package/admin/js/templates/docs/api-navigation.html +66 -22
  12. package/admin/js/templates/docs/api-pages.html +109 -129
  13. package/admin/js/templates/docs/api-plugins.html +123 -61
  14. package/admin/js/templates/docs/api-scaffold.html +185 -0
  15. package/admin/js/templates/docs/api-settings.html +72 -64
  16. package/admin/js/templates/docs/api-users.html +74 -107
  17. package/admin/js/templates/docs/api-views.html +68 -54
  18. package/admin/js/templates/docs/components-howto.html +20 -17
  19. package/admin/js/templates/docs/components-reference.html +13 -16
  20. package/admin/js/templates/docs/components-rules.html +7 -6
  21. package/admin/js/templates/docs/components-walkthrough.html +19 -19
  22. package/admin/js/templates/docs/tutorial-crud.html +68 -38
  23. package/admin/js/templates/docs/tutorial-forms.html +51 -35
  24. package/admin/js/templates/docs/tutorial-plugin.html +132 -56
  25. package/admin/js/templates/docs/usage-actions.html +55 -14
  26. package/admin/js/templates/docs/usage-collections.html +108 -0
  27. package/admin/js/templates/docs/usage-cta-shortcode.html +14 -3
  28. package/admin/js/templates/docs/usage-dconfig.html +0 -3
  29. package/admin/js/templates/docs/usage-editions.html +213 -0
  30. package/admin/js/templates/docs/usage-media.html +22 -6
  31. package/admin/js/templates/docs/usage-navigation.html +74 -18
  32. package/admin/js/templates/docs/usage-pages.html +60 -20
  33. package/admin/js/templates/docs/usage-plugins.html +89 -17
  34. package/admin/js/templates/docs/usage-shortcodes.html +123 -70
  35. package/admin/js/templates/docs/usage-site-settings.html +50 -18
  36. package/admin/js/templates/docs/usage-tools.html +73 -0
  37. package/admin/js/templates/docs/usage-users-roles.html +99 -20
  38. package/admin/js/templates/docs/usage-views.html +36 -19
  39. package/admin/js/templates/documentation.html +153 -32
  40. package/admin/js/templates/plugin-guide.html +15 -0
  41. package/admin/js/templates/plugin-guides.html +21 -0
  42. package/admin/js/templates/pro-docs.html +53 -234
  43. package/admin/js/templates/tutorials.html +5 -4
  44. package/admin/js/views/doc-pages.js +1 -1
  45. package/admin/js/views/index.js +1 -1
  46. package/admin/js/views/plugin-guides.js +5 -0
  47. package/bin/cli.js +6 -6
  48. package/package.json +1 -1
  49. package/plugins/blog/docs/guide.md +205 -0
  50. package/plugins/blog/plugin.json +1 -1
  51. package/plugins/feedback/docs/guide.md +95 -0
  52. package/plugins/feedback/plugin.json +1 -1
  53. package/plugins/free-tier.lock.json +16 -11
  54. package/plugins/mail-reader/docs/guide.md +147 -0
  55. package/plugins/mail-reader/plugin.json +1 -1
  56. package/plugins/security/docs/guide.md +170 -0
  57. package/plugins/security/plugin.json +1 -1
  58. package/plugins/shopping-cart/docs/guide.md +191 -0
  59. package/plugins/shopping-cart/plugin.json +1 -1
  60. package/server/routes/api/documentation.js +42 -0
  61. package/server/server.js +12 -0
  62. package/server/services/docs.js +13 -2
  63. package/server/services/pluginGuides.js +255 -0
  64. package/server/services/plugins.js +8 -0
@@ -69,278 +69,218 @@
69
69
  <div class="col-12">
70
70
  <div class="docs-body">
71
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
-
72
+ <p>Collections have two access planes: <strong>admin endpoints</strong> (<code>/api/collections/...</code>, signed-in,
73
+ gated by the <code>collections</code> permission for the action named - read, create, update, delete) and
74
+ <strong>public endpoints</strong>, gated per collection and per verb by the collection's API settings (the
75
+ collection editor's API &amp; Export tab). The same public endpoints are also served at <code>/api/v1/:slug</code>
76
+ for external programs - see <a href="#/docs/api/external">External API &amp; tokens</a>.</p>
77
+ <p>An entry looks like this on every storage adapter:</p>
78
+ <pre class="code-block"><code>{ "id": "uuid", "data": { "title": "..." },
79
+ "meta": { "createdAt": "...", "updatedAt": "...", "createdBy": "user-id", "source": "admin" } }</code></pre>
80
+
81
+ <h3 style="margin-top:16px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
82
+ Schema Management</h3>
83
+
84
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections</span></h3>
85
+ <p class="auth-note">Requires Bearer token + <code>collections</code> read permission.</p>
86
+ <p>Every collection schema you may see (no entries), each with its entry count.</p>
87
+ <pre class="code-block"><code>// Response 200
88
+ [ { "slug": "jobs", "title": "Jobs", "description": "...", "fields": [...], "entryCount": 12 } ]</code></pre>
89
+
90
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections</span></h3>
91
+ <p class="auth-note">Requires Bearer token + <code>collections</code> create permission.</p>
92
+ <p>Create a collection. The <code>slug</code> is made from the title if left out.</p>
93
+ <table class="table table-sm">
94
+ <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
95
+ <tbody>
96
+ <tr><td><code>title</code></td><td>string</td><td>Required. The collection's name</td></tr>
97
+ <tr><td><code>slug</code></td><td>string</td><td>Optional. URL-safe identifier</td></tr>
98
+ <tr><td><code>description</code></td><td>string</td><td>Optional</td></tr>
99
+ <tr><td><code>fields</code></td><td>array</td><td>Field definitions</td></tr>
100
+ <tr><td><code>api</code></td><td>object</td><td>Public access per verb - see Public Access below</td></tr>
101
+ <tr><td><code>export</code></td><td>object</td><td>Who may export from the public site's right-click menu</td></tr>
102
+ <tr><td><code>storage</code></td><td>object</td><td>Optional, needs MongoDB (Pro):
103
+ <code>{ "adapter": "mongodb", "connection": "default" }</code>. Files otherwise.</td></tr>
104
+ </tbody>
105
+ </table>
106
+ <pre class="code-block"><code>// Response 201 - the created schema
161
107
  // Error 409
162
108
  { "error": "A collection with that slug already exists" }</code></pre>
163
109
 
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 }
110
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug</span></h3>
111
+ <p class="auth-note">Requires Bearer token + <code>collections</code> read permission.</p>
112
+ <p>One collection's schema.</p>
180
113
 
114
+ <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug</span></h3>
115
+ <p class="auth-note">Requires Bearer token + <code>collections</code> update permission.</p>
116
+ <p>Update a schema. To move a collection between file and MongoDB storage, use
117
+ <code>migrate-storage</code> below rather than editing <code>storage</code>, so the entries move with it.</p>
118
+
119
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug</span></h3>
120
+ <p class="auth-note">Requires Bearer token + <code>collections</code> delete permission.</p>
121
+ <p>Delete a collection and all its entries. Built-in (preset) collections cannot be deleted.</p>
122
+ <pre class="code-block"><code>// Response 200
123
+ { "success": true }
181
124
  // Error 403
182
125
  { "error": "Cannot delete a preset collection" }</code></pre>
183
126
 
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
127
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/migrate-storage</span></h3>
128
+ <p class="auth-note">Requires Bearer token + <code>collections</code> update permission.</p>
129
+ <p>Move a collection's entries to file or MongoDB storage (the collection editor's Storage tab). Each entry is copied
130
+ as it is - the same id, data and <code>meta</code> (created and updated dates, who created it) - so references,
131
+ links and row ownership keep working. Nothing is moved, and nothing changes, if the target already holds an
132
+ entry with one of the ids or the source holds an id twice (409, with the ids in <code>collisions</code>).
133
+ The old copy is set aside, never deleted: <code>data.json</code> becomes <code>data.json.bak</code>, and a
134
+ MongoDB collection is renamed <code>cms_&lt;slug&gt;__moved_&lt;time&gt;</code>. System collections (roles, user
135
+ profiles, projects, notifications, API tokens and endpoints) always use files and cannot be moved (400).</p>
136
+ <pre class="code-block"><code>// Request body
137
+ { "storage": { "adapter": "mongodb", "connection": "default" } } // or { "adapter": "file" }
138
+ // Response 200
139
+ { "migrated": 42, "total": 42, "archived": "..." }
140
+ // Error 409
141
+ { "error": "The target storage already holds 3 of these entries ...", "collisions": ["id-1", "id-2", "id-3"] }
142
+ // Error 503 - the MongoDB connection is not available</code></pre>
143
+
144
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/pro-status</span></h3>
145
+ <p class="auth-note">Requires Bearer token + <code>collections</code> read permission.</p>
146
+ <p>Whether any database connection is set up (MongoDB storage is a Pro feature).</p>
147
+ <pre class="code-block"><code>// Response 200
148
+ { "pro": true, "connections": ["default"] }</code></pre>
149
+
150
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/connections</span></h3>
151
+ <p class="auth-note">Requires Bearer token + an admin role (level 0 or 1).</p>
152
+ <p>The MongoDB connections in <code>config/connections.json</code>. <code>PUT</code> saves them; each needs
153
+ <code>type</code>, <code>uri</code> and <code>database</code>.</p>
154
+ <pre class="code-block"><code>// Response 200
155
+ { "default": { "type": "mongodb", "uri": "mongodb://localhost:27017", "database": "my_cms" } }
156
+ // PUT - Error 400
157
+ { "error": "Connection \"default\" requires type, uri, and database" }</code></pre>
158
+
159
+ <h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
160
+ Admin Entry CRUD</h3>
161
+
162
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/entries</span></h3>
163
+ <p class="auth-note">Requires Bearer token + <code>collections</code> read permission.</p>
164
+ <p>List entries with paging, sorting, search and filters.</p>
165
+ <table class="table table-sm">
166
+ <thead><tr><th>Query param</th><th>Default</th><th>Description</th></tr></thead>
167
+ <tbody>
168
+ <tr><td><code>page</code></td><td>1</td><td>Page number</td></tr>
169
+ <tr><td><code>limit</code></td><td>50</td><td>Entries per page</td></tr>
170
+ <tr><td><code>sort</code></td><td>createdAt</td><td>Field to sort by</td></tr>
171
+ <tr><td><code>order</code></td><td>desc</td><td><code>asc</code> or <code>desc</code></td></tr>
172
+ <tr><td><code>search</code></td><td>-</td><td>Text found in any field</td></tr>
173
+ <tr><td><code>filter[&lt;field&gt;]</code>, <code>filter[&lt;field&gt;_&lt;op&gt;]</code></td><td>-</td><td>Structured
174
+ filters, ANDed. Operators: <code>eq</code>, <code>ne</code>, <code>gt</code>, <code>gte</code>,
175
+ <code>lt</code>, <code>lte</code>, <code>in</code>, <code>nin</code>, <code>contains</code>,
176
+ <code>starts</code>, <code>ends</code>, <code>exists</code>. <code>createdBy</code> and <code>id</code> work as
177
+ field names.</td></tr>
178
+ </tbody>
179
+ </table>
180
+ <pre class="code-block"><code>// GET /api/collections/jobs/entries?filter[location]=London&amp;filter[salary_gte]=50000
181
+ // Response 200
182
+ { "entries": [ { "id": "uuid", "data": { ... }, "meta": { ... } } ], "total": 42, "page": 1, "limit": 50 }</code></pre>
183
+
184
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span></h3>
185
+ <p class="auth-note">Requires Bearer token + <code>collections</code> read permission.</p>
186
+ <p>One entry.</p>
187
+
188
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/entries</span></h3>
189
+ <p class="auth-note">Requires Bearer token + <code>collections</code> create permission.</p>
190
+ <p>Create an entry. Its <code>data</code> is checked against the schema (required fields, and that every reference
191
+ points at an entry that exists).</p>
192
+ <pre class="code-block"><code>// Request body
193
+ { "data": { "title": "Senior Developer", "location": "London" } }
194
+ // Response 201 - the created entry</code></pre>
195
+
196
+ <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span></h3>
197
+ <p class="auth-note">Requires Bearer token + <code>collections</code> update permission.</p>
198
+ <p>Update an entry. <code>data</code> replaces the stored data as a whole, so send every field.
199
+ <code>POST /api/collections/:slug/entries/:id/spam</code> flags one entry as spam without touching the rest.</p>
200
+
201
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span></h3>
202
+ <p class="auth-note">Requires Bearer token + <code>collections</code> delete permission.</p>
203
+ <p>Delete one entry. Entries that referenced it are not changed; they show the reference as missing.</p>
204
+ <pre class="code-block"><code>// Response 200
251
205
  { "success": true }</code></pre>
252
206
 
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
207
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/entries</span></h3>
208
+ <p class="auth-note">Requires Bearer token + <code>collections</code> delete permission.</p>
209
+ <p>Delete every entry in a collection. Cannot be undone.</p>
210
+ <pre class="code-block"><code>// Response 200
258
211
  { "success": true }</code></pre>
259
212
 
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
213
+ <h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
214
+ Export &amp; Import</h3>
215
+
216
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/export</span></h3>
217
+ <p class="auth-note">Requires Bearer token + <code>collections</code> read permission.</p>
218
+ <p>Download every entry as <code>?format=json</code> (default) or <code>?format=csv</code>.</p>
219
+ <pre class="code-block"><code>// Response 200 - file download
220
+ // Content-Disposition: attachment; filename="jobs-entries.json"</code></pre>
221
+
222
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/import</span></h3>
223
+ <p class="auth-note">Requires Bearer token + <code>collections</code> create permission.</p>
224
+ <p>Add entries from a JSON array (JSON only). Existing entries are kept. Each entry is checked like any other save -
225
+ required fields, and references to entries that must exist - and one that fails is skipped and reported.
226
+ Fields the collection does not define are stored as given.</p>
227
+ <pre class="code-block"><code>// Request body
307
228
  { "entries": [ { "data": { "title": "Post 1" } }, { "data": { "title": "Post 2" } } ] }
308
-
309
229
  // 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>
230
+ { "imported": 2, "skipped": 0, "errors": [] }</code></pre>
231
+
232
+ <h3 style="margin-top:24px;font-size:15px;text-transform:uppercase;letter-spacing:.5px;opacity:.6">
233
+ Public Access</h3>
234
+
235
+ <p>Each verb (<code>read</code>, <code>create</code>, <code>update</code>, <code>delete</code>) has its own setting
236
+ in the schema's <code>api</code> block: switched off (403), <code>public</code> (no sign-in),
237
+ <code>token</code> (a project API token only - see <a href="#/docs/api/external">External API &amp; tokens</a>),
238
+ or a role name, which admits a signed-in user whose role is that senior or more. A role name the site does not
239
+ have admits only the level-0 role. <code>api.read.fields</code>, when set, limits which fields are returned. A
240
+ collection in a disabled project answers 404 on every public route.</p>
241
+ <pre class="code-block"><code>"api": {
242
+ "read": { "enabled": true, "access": "public", "fields": ["title", "location"] },
243
+ "create": { "enabled": true, "access": "user" },
244
+ "update": { "enabled": false, "access": "admin" },
245
+ "delete": { "enabled": false, "access": "admin" }
246
+ }</code></pre>
247
+
248
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/public</span></h3>
249
+ <p class="auth-note">Access level: the collection's <code>api.read</code> setting.</p>
250
+ <p>List entries. The same <code>page</code>, <code>limit</code>, <code>sort</code>, <code>order</code>,
251
+ <code>search</code> and <code>filter[...]</code> params as the admin endpoint, plus <code>resolveRefs=true</code>
252
+ to fill in referenced entries. <code>scope=mine</code> returns only the entries the signed-in user created (401
253
+ without a sign-in); it does not need <code>api.read</code> switched on.</p>
254
+
255
+ <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/collections/:slug/public/:id</span></h3>
256
+ <p class="auth-note">Access level: the collection's <code>api.read</code> setting.</p>
257
+ <p>One entry.</p>
258
+
259
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/public</span></h3>
260
+ <p class="auth-note">Access level: the collection's <code>api.create</code> setting.</p>
261
+ <p>Create an entry (<code>{"data": {...&#125;&#125;</code>). It is marked <code>source: "api"</code>, and
262
+ <code>createdBy</code> is the signed-in user or <code>token:&lt;id&gt;</code>.</p>
263
+
264
+ <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/public/:id</span></h3>
265
+ <p class="auth-note">Access level: the collection's <code>api.update</code> setting.</p>
266
+ <p>Update an entry (<code>{"data": {...&#125;&#125;</code>).</p>
267
+
268
+ <h3><span class="method-badge method-delete">DELETE</span><span class="endpoint-path">/api/collections/:slug/public/:id</span></h3>
269
+ <p class="auth-note">Access level: the collection's <code>api.delete</code> setting.</p>
270
+ <p>Delete an entry.</p>
271
+
272
+ <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/render-scope</span></h3>
273
+ <p class="auth-note">Requires a signed-in user (JWT).</p>
274
+ <p>Used by the public site to draw a <code>[collection scope="mine"]</code> block for the signed-in visitor: only
275
+ their own entries. An interactive block (<code>searchable</code>, <code>sortable</code>, <code>filterable</code>
276
+ or <code>paginate</code>) comes back as the Collection Browser, with transition buttons when the block asks for
277
+ <code>transitions</code>. <code>POST /api/collections/render-fragment</code> does the same for other block-display
278
+ pages of the Browser, gated by <code>api.read</code>. Both take the block's attributes as base64 JSON in
279
+ <code>attrs</code> and answer <code>{"html": "..."}</code>.</p>
280
+
281
+ <p><strong>See also:</strong> <a href="#/docs/api/external">External API &amp; tokens</a> for <code>/api/v1/:slug</code>
282
+ and project-scoped API tokens, and <a href="#/docs/api/builder">API Builder</a> for your own endpoints at
283
+ <code>/api/x/...</code>.</p>
344
284
 
345
285
  </div>
346
286
  </div>