@reldens/cms 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/architecture-guide.md +450 -0
- package/.claude/security-guide.md +102 -0
- package/.claude/seo-guide.md +167 -0
- package/.claude/templating-system-guide.md +29 -0
- package/CLAUDE.md +93 -550
- package/bin/reldens-cms-generate-entities.js +0 -1
- package/install/index.html +4 -0
- package/lib/admin-manager/router-contents.js +1 -0
- package/lib/frontend/content-renderer.js +1 -0
- package/lib/frontend/template-cache.js +1 -1
- package/lib/frontend/template-resolver.js +7 -2
- package/lib/frontend.js +38 -6
- package/lib/manager.js +11 -1
- package/lib/mysql-installer.js +2 -1
- package/lib/sitemap-loader.js +101 -0
- package/lib/template-engine/collections-transformer.js +43 -6
- package/lib/template-engine.js +1 -5
- package/migrations/default-blocks.sql +1 -1
- package/migrations/default-entity-access.sql +1 -1
- package/migrations/default-forms.sql +0 -1
- package/migrations/default-homepage.sql +7 -7
- package/migrations/default-sitemaps-and-robots.sql +44 -0
- package/migrations/default-user.sql +1 -1
- package/migrations/users-authentication.sql +1 -1
- package/package.json +3 -4
- package/templates/layouts/raw.html +1 -0
- package/templates/raw.html +1 -0
- package/templates/robots.txt +3 -0
- package/templates/sitemap.xml +9 -0
- package/.claude/sitemap-generator-guide.md +0 -511
- package/bin/reldens-cms-generate-sitemap.js +0 -149
- package/lib/sitemap-generator.js +0 -181
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# Architecture Guide
|
|
2
|
+
|
|
3
|
+
## Core Orchestrators
|
|
4
|
+
|
|
5
|
+
### Manager
|
|
6
|
+
|
|
7
|
+
**File:** `lib/manager.js`
|
|
8
|
+
|
|
9
|
+
Main CMS orchestrator that:
|
|
10
|
+
|
|
11
|
+
- Initializes all services (data server, admin, frontend)
|
|
12
|
+
- Handles configuration and environment variables
|
|
13
|
+
- Manages multi-domain setup and security
|
|
14
|
+
- Coordinates service lifecycle
|
|
15
|
+
- Initializes password encryption handler
|
|
16
|
+
- Defines default templateExtensions: `['.html', '.mustache', '.template', '.txt', '.xml', '.json']`
|
|
17
|
+
- Passes templateExtensions to all frontend components ensuring consistency
|
|
18
|
+
|
|
19
|
+
### Frontend
|
|
20
|
+
|
|
21
|
+
**File:** `lib/frontend.js`
|
|
22
|
+
|
|
23
|
+
Frontend orchestrator that:
|
|
24
|
+
|
|
25
|
+
- Coordinates all frontend operations
|
|
26
|
+
- Manages template engine, cache, and rendering
|
|
27
|
+
- Handles search and dynamic forms
|
|
28
|
+
- Routes requests to appropriate handlers
|
|
29
|
+
- Receives templateExtensions from Manager and passes to TemplateResolver and TemplateCache
|
|
30
|
+
- Handles Content-Type detection based on request path extensions
|
|
31
|
+
|
|
32
|
+
### Admin Manager
|
|
33
|
+
|
|
34
|
+
**File:** `lib/admin-manager.js`
|
|
35
|
+
|
|
36
|
+
Admin panel orchestrator that:
|
|
37
|
+
|
|
38
|
+
- Manages admin panel routes and authentication
|
|
39
|
+
- Handles entity CRUD operations
|
|
40
|
+
- Processes file uploads
|
|
41
|
+
- Builds admin UI from entity configurations
|
|
42
|
+
|
|
43
|
+
### Password Encryption Handler
|
|
44
|
+
|
|
45
|
+
**File:** `lib/password-encryption-handler.js`
|
|
46
|
+
|
|
47
|
+
Password encryption handler that:
|
|
48
|
+
|
|
49
|
+
- Automatic password encryption for users entity
|
|
50
|
+
- Event-driven architecture
|
|
51
|
+
- PBKDF2 encryption with 100k iterations
|
|
52
|
+
- Detects and skips already-encrypted passwords
|
|
53
|
+
- Configurable entity and field names
|
|
54
|
+
|
|
55
|
+
### Admin Router Contents
|
|
56
|
+
|
|
57
|
+
**File:** `lib/admin-manager/router-contents.js`
|
|
58
|
+
|
|
59
|
+
Admin routing and form handling that:
|
|
60
|
+
|
|
61
|
+
- Password field handling (type="password", empty on edit)
|
|
62
|
+
- Password updates optional (skip if empty when editing)
|
|
63
|
+
- Configurable password field names via passwordFieldNames
|
|
64
|
+
|
|
65
|
+
## Installation & Setup
|
|
66
|
+
|
|
67
|
+
### Installer
|
|
68
|
+
|
|
69
|
+
**File:** `lib/installer.js`
|
|
70
|
+
|
|
71
|
+
Installation orchestrator that:
|
|
72
|
+
|
|
73
|
+
- Web-based installer with subprocess management
|
|
74
|
+
- Dependency checking and installation
|
|
75
|
+
- Database schema creation
|
|
76
|
+
- Environment file generation
|
|
77
|
+
- Post-installation callbacks
|
|
78
|
+
|
|
79
|
+
### MySQL Installer
|
|
80
|
+
|
|
81
|
+
**File:** `lib/mysql-installer.js`
|
|
82
|
+
|
|
83
|
+
Database-specific installation that:
|
|
84
|
+
|
|
85
|
+
- MySQL schema creation
|
|
86
|
+
- Schema migration support
|
|
87
|
+
- Database validation
|
|
88
|
+
|
|
89
|
+
### Prisma Subprocess Worker
|
|
90
|
+
|
|
91
|
+
**File:** `lib/prisma-subprocess-worker.js`
|
|
92
|
+
|
|
93
|
+
Subprocess worker that:
|
|
94
|
+
|
|
95
|
+
- Handles Prisma client generation
|
|
96
|
+
- Progress tracking for long operations
|
|
97
|
+
|
|
98
|
+
## Frontend Architecture
|
|
99
|
+
|
|
100
|
+
### Template Resolver
|
|
101
|
+
|
|
102
|
+
**File:** `lib/frontend/template-resolver.js`
|
|
103
|
+
|
|
104
|
+
Template discovery that:
|
|
105
|
+
|
|
106
|
+
- Domain-aware template resolution with fallback system (domain → default domain → base)
|
|
107
|
+
- Automatic extension resolution (tries `.html`, `.mustache`, `.template`, `.txt`, `.xml`, `.json`)
|
|
108
|
+
- Layout and partial template lookup
|
|
109
|
+
- Path-to-template mapping
|
|
110
|
+
- Logs warnings when templates are not found in any location
|
|
111
|
+
|
|
112
|
+
### Template Cache
|
|
113
|
+
|
|
114
|
+
**File:** `lib/frontend/template-cache.js`
|
|
115
|
+
|
|
116
|
+
Template caching that:
|
|
117
|
+
|
|
118
|
+
- Loads and caches partials
|
|
119
|
+
- Domain-specific template management
|
|
120
|
+
- Partial inheritance and overrides
|
|
121
|
+
- Uses templateExtensions to discover partial files in directories
|
|
122
|
+
- Supports all configured extensions for partial templates
|
|
123
|
+
|
|
124
|
+
### Request Processor
|
|
125
|
+
|
|
126
|
+
**File:** `lib/frontend/request-processor.js`
|
|
127
|
+
|
|
128
|
+
Request routing that:
|
|
129
|
+
|
|
130
|
+
- Route database lookup
|
|
131
|
+
- Domain extraction from requests
|
|
132
|
+
- Path normalization
|
|
133
|
+
- Cache key generation
|
|
134
|
+
|
|
135
|
+
### Entity Access Manager
|
|
136
|
+
|
|
137
|
+
**File:** `lib/frontend/entity-access-manager.js`
|
|
138
|
+
|
|
139
|
+
Entity access control that:
|
|
140
|
+
|
|
141
|
+
- Loads entity access rules
|
|
142
|
+
- Public/private entity validation
|
|
143
|
+
- Entity lookup by path
|
|
144
|
+
|
|
145
|
+
### Content Renderer
|
|
146
|
+
|
|
147
|
+
**File:** `lib/frontend/content-renderer.js`
|
|
148
|
+
|
|
149
|
+
Content generation that:
|
|
150
|
+
|
|
151
|
+
- Main content rendering logic
|
|
152
|
+
- Route-based content generation
|
|
153
|
+
- Template processing
|
|
154
|
+
- Meta field handling
|
|
155
|
+
|
|
156
|
+
### Response Manager
|
|
157
|
+
|
|
158
|
+
**File:** `lib/frontend/response-manager.js`
|
|
159
|
+
|
|
160
|
+
Response handling that:
|
|
161
|
+
|
|
162
|
+
- HTTP response management
|
|
163
|
+
- Cache integration
|
|
164
|
+
- Error handling (404, 500)
|
|
165
|
+
|
|
166
|
+
## Template Engine
|
|
167
|
+
|
|
168
|
+
### Template Engine Core
|
|
169
|
+
|
|
170
|
+
**File:** `lib/template-engine.js`
|
|
171
|
+
|
|
172
|
+
Core template processor that:
|
|
173
|
+
|
|
174
|
+
- Orchestrates all template transformers
|
|
175
|
+
- System variables injection
|
|
176
|
+
- Event-driven rendering pipeline
|
|
177
|
+
- Mustache integration
|
|
178
|
+
|
|
179
|
+
### Template Transformers
|
|
180
|
+
|
|
181
|
+
**Entities Transformer**
|
|
182
|
+
- File: `lib/template-engine/entities-transformer.js`
|
|
183
|
+
- Single entity rendering `<entity name="cmsBlocks" field="name" value="header"/>`
|
|
184
|
+
|
|
185
|
+
**Collections Transformer**
|
|
186
|
+
- File: `lib/template-engine/collections-transformer.js`
|
|
187
|
+
- Collection loops with pagination
|
|
188
|
+
|
|
189
|
+
**Collections Single Transformer**
|
|
190
|
+
- File: `lib/template-engine/collections-single-transformer.js`
|
|
191
|
+
- Single field collections
|
|
192
|
+
|
|
193
|
+
**Partials Transformer**
|
|
194
|
+
- File: `lib/template-engine/partials-transformer.js`
|
|
195
|
+
- Partial template processing
|
|
196
|
+
|
|
197
|
+
**Forms Transformer**
|
|
198
|
+
- File: `lib/template-engine/forms-transformer.js`
|
|
199
|
+
- Dynamic forms rendering `<cmsForm key="contact"/>`
|
|
200
|
+
|
|
201
|
+
**URL Transformer**
|
|
202
|
+
- File: `lib/template-engine/url-transformer.js`
|
|
203
|
+
- URL generation `[url(/path)]`
|
|
204
|
+
|
|
205
|
+
**Asset Transformer**
|
|
206
|
+
- File: `lib/template-engine/asset-transformer.js`
|
|
207
|
+
- Asset URLs `[asset(/img/logo.png)]`
|
|
208
|
+
|
|
209
|
+
**CDN Transformer**
|
|
210
|
+
- File: `lib/template-engine/cdn-transformer.js`
|
|
211
|
+
- CDN URL transformation
|
|
212
|
+
|
|
213
|
+
**Date Transformer**
|
|
214
|
+
- File: `lib/template-engine/date-transformer.js`
|
|
215
|
+
- Date formatting `[date(now, Y-m-d)]`
|
|
216
|
+
|
|
217
|
+
**Translate Transformer**
|
|
218
|
+
- File: `lib/template-engine/translate-transformer.js`
|
|
219
|
+
- Internationalization `[translate(key)]`
|
|
220
|
+
|
|
221
|
+
### System Variables Provider
|
|
222
|
+
|
|
223
|
+
**File:** `lib/template-engine/system-variables-provider.js`
|
|
224
|
+
|
|
225
|
+
System variables that:
|
|
226
|
+
|
|
227
|
+
- Current request context (host, path, protocol)
|
|
228
|
+
- Current route data
|
|
229
|
+
- Current domain information
|
|
230
|
+
- System information (environment, timestamp)
|
|
231
|
+
|
|
232
|
+
### Translation Service
|
|
233
|
+
|
|
234
|
+
**File:** `lib/template-engine/translation-service.js`
|
|
235
|
+
|
|
236
|
+
Translation loading that:
|
|
237
|
+
|
|
238
|
+
- JSON translation file management
|
|
239
|
+
- Locale detection
|
|
240
|
+
- Fallback handling
|
|
241
|
+
|
|
242
|
+
## Dynamic Forms System
|
|
243
|
+
|
|
244
|
+
### Dynamic Form
|
|
245
|
+
|
|
246
|
+
**File:** `lib/dynamic-form.js`
|
|
247
|
+
|
|
248
|
+
Form validation and processing that:
|
|
249
|
+
|
|
250
|
+
- Schema-based validation
|
|
251
|
+
- Honeypot protection
|
|
252
|
+
- Rate limiting integration
|
|
253
|
+
- Data sanitization
|
|
254
|
+
- Database storage
|
|
255
|
+
|
|
256
|
+
### Dynamic Form Renderer
|
|
257
|
+
|
|
258
|
+
**File:** `lib/dynamic-form-renderer.js`
|
|
259
|
+
|
|
260
|
+
Form template rendering that:
|
|
261
|
+
|
|
262
|
+
- Domain-aware form templates
|
|
263
|
+
- Field type templates
|
|
264
|
+
- Error display
|
|
265
|
+
- Form attribute handling
|
|
266
|
+
|
|
267
|
+
### Dynamic Form Request Handler
|
|
268
|
+
|
|
269
|
+
**File:** `lib/dynamic-form-request-handler.js`
|
|
270
|
+
|
|
271
|
+
Form request handling that:
|
|
272
|
+
|
|
273
|
+
- POST request processing
|
|
274
|
+
- Validation orchestration
|
|
275
|
+
- Success/error redirects
|
|
276
|
+
- JSON response support
|
|
277
|
+
|
|
278
|
+
## Search System
|
|
279
|
+
|
|
280
|
+
### Search
|
|
281
|
+
|
|
282
|
+
**File:** `lib/search.js`
|
|
283
|
+
|
|
284
|
+
Search functionality that:
|
|
285
|
+
|
|
286
|
+
- Multi-entity search
|
|
287
|
+
- Custom search sets
|
|
288
|
+
- Query parameter parsing
|
|
289
|
+
- Pagination support
|
|
290
|
+
|
|
291
|
+
### Search Renderer
|
|
292
|
+
|
|
293
|
+
**File:** `lib/search-renderer.js`
|
|
294
|
+
|
|
295
|
+
Search result rendering that:
|
|
296
|
+
|
|
297
|
+
- Template-based result display
|
|
298
|
+
- Custom column classes
|
|
299
|
+
- Domain-aware templates
|
|
300
|
+
|
|
301
|
+
### Search Request Handler
|
|
302
|
+
|
|
303
|
+
**File:** `lib/search-request-handler.js`
|
|
304
|
+
|
|
305
|
+
Search request handling that:
|
|
306
|
+
|
|
307
|
+
- Query processing
|
|
308
|
+
- Template data support
|
|
309
|
+
- Error handling
|
|
310
|
+
|
|
311
|
+
## Cache System
|
|
312
|
+
|
|
313
|
+
### Cache Manager
|
|
314
|
+
|
|
315
|
+
**File:** `lib/cache/cache-manager.js`
|
|
316
|
+
|
|
317
|
+
Cache orchestrator that:
|
|
318
|
+
|
|
319
|
+
- Domain and path-based caching
|
|
320
|
+
- Cache invalidation
|
|
321
|
+
- Enable/disable functionality
|
|
322
|
+
|
|
323
|
+
### Cache Routes Handler
|
|
324
|
+
|
|
325
|
+
**File:** `lib/cache/cache-routes-handler.js`
|
|
326
|
+
|
|
327
|
+
Cache admin routes that:
|
|
328
|
+
|
|
329
|
+
- Cache clearing endpoints
|
|
330
|
+
- Cache management UI integration
|
|
331
|
+
|
|
332
|
+
### Add Cache Button Subscriber
|
|
333
|
+
|
|
334
|
+
**File:** `lib/cache/add-cache-button-subscriber.js`
|
|
335
|
+
|
|
336
|
+
Cache UI integration that:
|
|
337
|
+
|
|
338
|
+
- Adds cache buttons to admin panel
|
|
339
|
+
- Event-driven cache controls
|
|
340
|
+
|
|
341
|
+
## Admin System
|
|
342
|
+
|
|
343
|
+
### Router
|
|
344
|
+
|
|
345
|
+
**File:** `lib/admin-manager/router.js`
|
|
346
|
+
|
|
347
|
+
Admin routing that:
|
|
348
|
+
|
|
349
|
+
- Authentication middleware
|
|
350
|
+
- Session management
|
|
351
|
+
- CRUD route setup
|
|
352
|
+
- File upload handling
|
|
353
|
+
|
|
354
|
+
### Router Contents
|
|
355
|
+
|
|
356
|
+
**File:** `lib/admin-manager/router-contents.js`
|
|
357
|
+
|
|
358
|
+
Admin content generation that:
|
|
359
|
+
|
|
360
|
+
- List view generation
|
|
361
|
+
- Edit form generation
|
|
362
|
+
- Relation handling
|
|
363
|
+
- Save/delete processing
|
|
364
|
+
|
|
365
|
+
### Contents Builder
|
|
366
|
+
|
|
367
|
+
**File:** `lib/admin-manager/contents-builder.js`
|
|
368
|
+
|
|
369
|
+
Admin UI builder that:
|
|
370
|
+
|
|
371
|
+
- Sidebar navigation
|
|
372
|
+
- Entity list/edit views
|
|
373
|
+
- Form field generation
|
|
374
|
+
- Branding and styling
|
|
375
|
+
|
|
376
|
+
### Admin Filters Manager
|
|
377
|
+
|
|
378
|
+
**File:** `lib/admin-manager/admin-filters-manager.js`
|
|
379
|
+
|
|
380
|
+
Entity filtering that:
|
|
381
|
+
|
|
382
|
+
- Filter UI generation
|
|
383
|
+
- Query building
|
|
384
|
+
|
|
385
|
+
### Default Translations
|
|
386
|
+
|
|
387
|
+
**File:** `lib/admin-manager/default-translations.js`
|
|
388
|
+
|
|
389
|
+
Admin translations that:
|
|
390
|
+
|
|
391
|
+
- Default English labels
|
|
392
|
+
- Extensible translation system
|
|
393
|
+
|
|
394
|
+
## Utility Classes
|
|
395
|
+
|
|
396
|
+
**Entities Loader**
|
|
397
|
+
- File: `lib/entities-loader.js`
|
|
398
|
+
- Entity loading from files
|
|
399
|
+
|
|
400
|
+
**Loaded Entities Processor**
|
|
401
|
+
- File: `lib/loaded-entities-processor.js`
|
|
402
|
+
- Entity configuration processing
|
|
403
|
+
|
|
404
|
+
**Admin Entities Generator**
|
|
405
|
+
- File: `lib/admin-entities-generator.js`
|
|
406
|
+
- Admin entity configuration
|
|
407
|
+
|
|
408
|
+
**Admin Templates Loader**
|
|
409
|
+
- File: `lib/admin-templates-loader.js`
|
|
410
|
+
- Admin template loading
|
|
411
|
+
|
|
412
|
+
**Templates To Path Mapper**
|
|
413
|
+
- File: `lib/templates-to-path-mapper.js`
|
|
414
|
+
- Template path mapping
|
|
415
|
+
|
|
416
|
+
**Templates List**
|
|
417
|
+
- File: `lib/templates-list.js`
|
|
418
|
+
- Template file list
|
|
419
|
+
|
|
420
|
+
**JSON Fields Parser**
|
|
421
|
+
- File: `lib/json-fields-parser.js`
|
|
422
|
+
- JSON field parsing
|
|
423
|
+
|
|
424
|
+
**Pagination Handler**
|
|
425
|
+
- File: `lib/pagination-handler.js`
|
|
426
|
+
- Pagination logic
|
|
427
|
+
|
|
428
|
+
**Template Reloader**
|
|
429
|
+
- File: `lib/template-reloader.js`
|
|
430
|
+
- Development template reloading
|
|
431
|
+
|
|
432
|
+
**CMS Pages Route Manager**
|
|
433
|
+
- File: `lib/cms-pages-route-manager.js`
|
|
434
|
+
- CMS page routing
|
|
435
|
+
|
|
436
|
+
**Admin Manager Validator**
|
|
437
|
+
- File: `lib/admin-manager-validator.js`
|
|
438
|
+
- Admin config validation
|
|
439
|
+
|
|
440
|
+
**Admin Dist Helper**
|
|
441
|
+
- File: `lib/admin-dist-helper.js`
|
|
442
|
+
- Admin asset distribution
|
|
443
|
+
|
|
444
|
+
**MIME Types**
|
|
445
|
+
- File: `lib/mime-types.js`
|
|
446
|
+
- File type definitions
|
|
447
|
+
|
|
448
|
+
**Allowed Extensions**
|
|
449
|
+
- File: `lib/allowed-extensions.js`
|
|
450
|
+
- Upload extension whitelist
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Security Guide
|
|
2
|
+
|
|
3
|
+
## Authentication
|
|
4
|
+
|
|
5
|
+
**Role-based admin access:**
|
|
6
|
+
- Admin panel protected by authentication middleware
|
|
7
|
+
- Session-based authentication
|
|
8
|
+
- Configurable admin role ID
|
|
9
|
+
- Custom authentication callbacks supported
|
|
10
|
+
|
|
11
|
+
## Password Encryption
|
|
12
|
+
|
|
13
|
+
**Algorithm:** PBKDF2 (Password-Based Key Derivation Function 2)
|
|
14
|
+
- Iterations: 100,000
|
|
15
|
+
- Key Length: 64 bytes
|
|
16
|
+
- Digest: SHA-512
|
|
17
|
+
- Salt Length: 32 bytes (randomly generated)
|
|
18
|
+
- Storage Format: `salt:hash` (192 characters total)
|
|
19
|
+
|
|
20
|
+
**Automatic Password Encryption:**
|
|
21
|
+
- Event-driven encryption on save
|
|
22
|
+
- Enabled by default via `PasswordEncryptionHandler`
|
|
23
|
+
- Can be disabled with `enablePasswordEncryption: false` in Manager config
|
|
24
|
+
|
|
25
|
+
See `.claude/password-management-guide.md` for comprehensive password management documentation.
|
|
26
|
+
|
|
27
|
+
## CSRF Protection
|
|
28
|
+
|
|
29
|
+
**Session-based CSRF tokens:**
|
|
30
|
+
- CSRF tokens generated per session
|
|
31
|
+
- Validated on form submissions
|
|
32
|
+
- Integrated with Express session middleware
|
|
33
|
+
|
|
34
|
+
## File Upload Validation
|
|
35
|
+
|
|
36
|
+
**MIME type checking:**
|
|
37
|
+
- Validates file MIME types against allowed types
|
|
38
|
+
- Extension whitelist validation
|
|
39
|
+
- Configurable allowed extensions per field
|
|
40
|
+
|
|
41
|
+
**Upload field configuration:**
|
|
42
|
+
- `allowedTypes`: Must be a STRING ('image', 'audio', 'text'), NOT an array
|
|
43
|
+
- `bucket`: Relative path from projectRoot
|
|
44
|
+
- `bucketPath`: URL path for display
|
|
45
|
+
|
|
46
|
+
## Entity Access Control
|
|
47
|
+
|
|
48
|
+
**Public/private entity rules:**
|
|
49
|
+
- Configured via `entities_access` table
|
|
50
|
+
- Per-entity operation rules (read, write, update, delete)
|
|
51
|
+
- Public entities accessible without authentication
|
|
52
|
+
- Private entities require authentication
|
|
53
|
+
|
|
54
|
+
## Honeypot Protection
|
|
55
|
+
|
|
56
|
+
**Bot detection in forms:**
|
|
57
|
+
- Hidden honeypot fields in dynamic forms
|
|
58
|
+
- Submission rejected if honeypot field is filled
|
|
59
|
+
- Transparent to legitimate users
|
|
60
|
+
|
|
61
|
+
## Rate Limiting
|
|
62
|
+
|
|
63
|
+
**Via @reldens/server-utils:**
|
|
64
|
+
- Configurable rate limits per endpoint
|
|
65
|
+
- IP-based rate limiting
|
|
66
|
+
- Prevents brute force attacks
|
|
67
|
+
|
|
68
|
+
## XSS Protection
|
|
69
|
+
|
|
70
|
+
**Input sanitization:**
|
|
71
|
+
- Via @reldens/server-utils
|
|
72
|
+
- HTML entity encoding
|
|
73
|
+
- Script tag removal
|
|
74
|
+
- Event handler attribute removal
|
|
75
|
+
|
|
76
|
+
## SQL Injection Prevention
|
|
77
|
+
|
|
78
|
+
**Via Prisma ORM:**
|
|
79
|
+
- Parameterized queries
|
|
80
|
+
- No raw SQL execution
|
|
81
|
+
- Type-safe query building
|
|
82
|
+
|
|
83
|
+
## Path Validation
|
|
84
|
+
|
|
85
|
+
**File path security:**
|
|
86
|
+
- Path traversal prevention
|
|
87
|
+
- Restricted file access
|
|
88
|
+
- Validated upload paths
|
|
89
|
+
|
|
90
|
+
## CSP Headers
|
|
91
|
+
|
|
92
|
+
**Content Security Policy via Helmet:**
|
|
93
|
+
- Configurable CSP directives
|
|
94
|
+
- Script source restrictions
|
|
95
|
+
- Style source restrictions
|
|
96
|
+
|
|
97
|
+
## HTTPS Support
|
|
98
|
+
|
|
99
|
+
**SSL/TLS configuration:**
|
|
100
|
+
- HTTPS server support
|
|
101
|
+
- Configurable SSL certificates
|
|
102
|
+
- Automatic HTTP to HTTPS redirect
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# SEO Guide: Sitemaps and Robots.txt
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The CMS provides built-in support for dynamic robots.txt and sitemap.xml generation using CMS pages and templates.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
During CMS installation, check the **"Install SEO files (robots.txt and sitemap.xml)"** option to automatically create:
|
|
10
|
+
|
|
11
|
+
- `/robots.txt` route and page (available to all domains)
|
|
12
|
+
- `/sitemap.xml` route and page (available to all domains)
|
|
13
|
+
|
|
14
|
+
## Robots.txt
|
|
15
|
+
|
|
16
|
+
### How It Works
|
|
17
|
+
|
|
18
|
+
**Route:** `/robots.txt`
|
|
19
|
+
|
|
20
|
+
**Database Configuration:**
|
|
21
|
+
- Template field: `'robots'` (extension omitted)
|
|
22
|
+
- Resolved template file: `templates/robots.txt`
|
|
23
|
+
- Layout: `'raw'` (passthrough only, no HTML wrapping)
|
|
24
|
+
- Content-Type: Automatically detected as `text/plain`
|
|
25
|
+
|
|
26
|
+
**Characteristics:**
|
|
27
|
+
- Simple static template pointing to `/sitemap.xml`
|
|
28
|
+
- Each domain serves its own robots.txt with a link to its own sitemap
|
|
29
|
+
- No database queries - pure static content
|
|
30
|
+
|
|
31
|
+
### Template Example
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
User-agent: *
|
|
35
|
+
Allow: /
|
|
36
|
+
Sitemap: {{currentRequest.publicUrl}}/sitemap.xml
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Sitemap.xml
|
|
40
|
+
|
|
41
|
+
### How It Works
|
|
42
|
+
|
|
43
|
+
**Route:** `/sitemap.xml`
|
|
44
|
+
|
|
45
|
+
**Database Configuration:**
|
|
46
|
+
- Template field: `'sitemap'` (extension omitted)
|
|
47
|
+
- Resolved template file: `templates/sitemap.xml`
|
|
48
|
+
- Layout: `'raw'` (passthrough only, no HTML wrapping)
|
|
49
|
+
- Content-Type: Automatically detected as `application/xml`
|
|
50
|
+
|
|
51
|
+
**Data Loading:**
|
|
52
|
+
- Uses `SitemapLoader` class to load data via `reldens.afterVariablesCreated` event
|
|
53
|
+
- Queries `routes` table with `cms_pages` relation using OR condition
|
|
54
|
+
- Includes routes where `domain IS NULL` OR `domain = mappedDomain`
|
|
55
|
+
- Excludes redirect routes (`redirect_url` and `redirect_type` must be null)
|
|
56
|
+
- Excludes pages with `meta_robots = 'noindex,nofollow'` (utility files like ads.txt)
|
|
57
|
+
- Lists only enabled routes with associated cms_pages
|
|
58
|
+
- Includes `path` and `updated_at` fields from routes table
|
|
59
|
+
- No arbitrary limits - fetches all matching routes
|
|
60
|
+
- Caches results on request object to avoid duplicate queries during multi-pass rendering
|
|
61
|
+
- Automatically leverages the CMS cache system (1 hour TTL)
|
|
62
|
+
|
|
63
|
+
### Template Example
|
|
64
|
+
|
|
65
|
+
```xml
|
|
66
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
67
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
68
|
+
{{#sitemapPages}}
|
|
69
|
+
<url>
|
|
70
|
+
<loc>{{¤tRequest.publicUrl}}{{&path}}</loc>
|
|
71
|
+
<lastmod>{{&updated_at}}</lastmod>
|
|
72
|
+
</url>
|
|
73
|
+
{{/sitemapPages}}
|
|
74
|
+
</urlset>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The `sitemapPages` variable is automatically populated by `SitemapLoader` class which:
|
|
78
|
+
|
|
79
|
+
1. Listens to `reldens.afterVariablesCreated` event
|
|
80
|
+
2. Loads routes with `cms_pages` relation from database
|
|
81
|
+
3. Filters by domain and excludes noindex pages
|
|
82
|
+
4. Caches results on `req.sitemapPages` for subsequent renders
|
|
83
|
+
|
|
84
|
+
## Multi-Domain Setup
|
|
85
|
+
|
|
86
|
+
For multi-domain sites, each domain automatically gets its own filtered sitemap:
|
|
87
|
+
|
|
88
|
+
### Installation Creates Shared Route
|
|
89
|
+
|
|
90
|
+
Installation creates one shared route with `domain: NULL`
|
|
91
|
+
- This makes `/sitemap.xml` available to all domains
|
|
92
|
+
- Each domain serves the same URL but gets filtered results
|
|
93
|
+
|
|
94
|
+
### Automatic Domain Filtering
|
|
95
|
+
|
|
96
|
+
SitemapLoader automatically handles domain filtering:
|
|
97
|
+
- Uses `domainMapping` to resolve dev domains to production domains (e.g., `reldens.new` → `reldens.com`)
|
|
98
|
+
- Queries routes where `domain IS NULL` (shared) OR `domain = mappedDomain` (domain-specific)
|
|
99
|
+
- Excludes routes without cms_pages or with `meta_robots = 'noindex,nofollow'`
|
|
100
|
+
|
|
101
|
+
### No Additional Configuration Needed
|
|
102
|
+
|
|
103
|
+
Each domain accessing `/sitemap.xml` gets its own filtered results automatically.
|
|
104
|
+
|
|
105
|
+
## Implementation Details
|
|
106
|
+
|
|
107
|
+
### SitemapLoader Filter Logic
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
{
|
|
111
|
+
enabled: 1,
|
|
112
|
+
redirect_url: null,
|
|
113
|
+
redirect_type: null,
|
|
114
|
+
OR: [
|
|
115
|
+
{domain: null},
|
|
116
|
+
{domain: mappedDomain}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Database Query
|
|
122
|
+
|
|
123
|
+
- Queries `routes` table with `loadWithRelations(filters, 'cms_pages')`
|
|
124
|
+
- Translates to: `WHERE enabled=1 AND redirect_url IS NULL AND redirect_type IS NULL AND (domain IS NULL OR domain = mappedDomain)`
|
|
125
|
+
- Loads associated `cms_pages` in single query using Prisma/ObjectionJS/MikroORM relations
|
|
126
|
+
|
|
127
|
+
### JavaScript Post-Filter
|
|
128
|
+
|
|
129
|
+
- Excludes routes without `cms_pages` relation
|
|
130
|
+
- Excludes routes where `cms_pages[0].meta_robots === 'noindex,nofollow'`
|
|
131
|
+
- This avoids polluting sitemap with utility files (robots.txt, ads.txt, sitemap.xml itself)
|
|
132
|
+
|
|
133
|
+
## Benefits
|
|
134
|
+
|
|
135
|
+
**Dynamic:**
|
|
136
|
+
- Sitemaps update automatically when routes change
|
|
137
|
+
|
|
138
|
+
**Cached:**
|
|
139
|
+
- Route-level cache (1 hour TTL)
|
|
140
|
+
- Request-level cache to avoid duplicate queries
|
|
141
|
+
|
|
142
|
+
**SEO-friendly:**
|
|
143
|
+
- Standard XML sitemap format
|
|
144
|
+
- Proper lastmod dates
|
|
145
|
+
|
|
146
|
+
**Multi-domain:**
|
|
147
|
+
- Each domain gets its own sitemap
|
|
148
|
+
- Domain-specific + shared routes included
|
|
149
|
+
|
|
150
|
+
**Domain Mapping:**
|
|
151
|
+
- Automatically resolves dev domains to production domains for queries
|
|
152
|
+
|
|
153
|
+
**Smart Filtering:**
|
|
154
|
+
- Excludes utility files (robots.txt, ads.txt) via meta_robots field
|
|
155
|
+
|
|
156
|
+
**Event-driven:**
|
|
157
|
+
- Uses `reldens.afterVariablesCreated` event for extensibility
|
|
158
|
+
|
|
159
|
+
**No limits:**
|
|
160
|
+
- Fetches all matching routes (no arbitrary pagination)
|
|
161
|
+
|
|
162
|
+
**Efficient:**
|
|
163
|
+
- Single database query with relation loading
|
|
164
|
+
- JavaScript post-filter for meta_robots
|
|
165
|
+
|
|
166
|
+
**Cross-driver:**
|
|
167
|
+
- Works with Prisma, ObjectionJS, and MikroORM storage drivers
|