@reldens/cms 0.47.0 → 0.49.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/advanced-usage-guide.md +98 -0
- package/.claude/api-reference.md +146 -0
- package/.claude/configuration-guide.md +126 -0
- package/.claude/database-schema.md +32 -0
- package/.claude/forms-system-guide.md +193 -0
- package/.claude/installation-guide.md +223 -0
- package/.claude/multi-domain-i18n-guide.md +178 -0
- package/.claude/password-management-guide.md +426 -0
- package/.claude/search-guide.md +66 -0
- package/.claude/templating-system-guide.md +349 -0
- package/CLAUDE.md +92 -3
- package/README.md +71 -1447
- package/bin/reldens-cms-update-password.js +246 -0
- package/lib/admin-manager/router-contents.js +14 -2
- package/lib/admin-manager/router.js +1 -0
- package/lib/manager.js +70 -8
- package/lib/password-encryption-handler.js +94 -0
- package/lib/template-engine.js +8 -2
- package/package.json +5 -4
- package/templates/.env.dist +1 -1
- package/templates/page.html +15 -11
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Advanced Installation Guide
|
|
2
|
+
|
|
3
|
+
## Subprocess Installation Handling
|
|
4
|
+
|
|
5
|
+
The installer supports complex operations through subprocess management:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
const { Installer } = require('@reldens/cms');
|
|
9
|
+
|
|
10
|
+
const installer = new Installer({
|
|
11
|
+
projectRoot: process.cwd(),
|
|
12
|
+
subprocessMaxAttempts: 1800,
|
|
13
|
+
postInstallCallback: async (props) => {
|
|
14
|
+
console.log('Entities loaded:', Object.keys(props.loadedEntities.rawRegisteredEntities));
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**The installer automatically handles:**
|
|
21
|
+
|
|
22
|
+
- Package dependency checking and installation
|
|
23
|
+
- Database schema creation via subprocess
|
|
24
|
+
- Prisma client generation with progress tracking
|
|
25
|
+
- Entity generation with validation
|
|
26
|
+
- Environment file creation
|
|
27
|
+
- Directory structure setup
|
|
28
|
+
|
|
29
|
+
## Enhanced Manager Initialization
|
|
30
|
+
|
|
31
|
+
The Manager class provides comprehensive service initialization:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
const cms = new Manager({
|
|
35
|
+
app: customExpressApp,
|
|
36
|
+
appServer: customAppServer,
|
|
37
|
+
dataServer: customDataServer,
|
|
38
|
+
adminManager: customAdmin,
|
|
39
|
+
frontend: customFrontend,
|
|
40
|
+
adminRoleId: 99,
|
|
41
|
+
authenticationMethod: 'db-users',
|
|
42
|
+
authenticationCallback: async (email, password, roleId) => {
|
|
43
|
+
return await yourAuthService.validate(email, password, roleId);
|
|
44
|
+
},
|
|
45
|
+
cache: true,
|
|
46
|
+
reloadTime: -1,
|
|
47
|
+
defaultDomain: 'example.com',
|
|
48
|
+
domainMapping: {'dev.example.com': 'development'},
|
|
49
|
+
siteKeyMapping: {'example.com': 'main'}
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Manager automatically:**
|
|
54
|
+
|
|
55
|
+
- Validates all provided instances
|
|
56
|
+
- Initializes missing services
|
|
57
|
+
- Sets up entity access control
|
|
58
|
+
- Generates admin entities
|
|
59
|
+
- Configures template reloading
|
|
60
|
+
|
|
61
|
+
## Development Mode Detection
|
|
62
|
+
|
|
63
|
+
The CMS automatically detects development environments based on domain patterns.
|
|
64
|
+
|
|
65
|
+
**Default Development Patterns:**
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
const patterns = [
|
|
69
|
+
'localhost',
|
|
70
|
+
'127.0.0.1',
|
|
71
|
+
'.local',
|
|
72
|
+
'.test',
|
|
73
|
+
'.dev',
|
|
74
|
+
'.acc',
|
|
75
|
+
'.staging',
|
|
76
|
+
'local.',
|
|
77
|
+
'test.',
|
|
78
|
+
'dev.',
|
|
79
|
+
'acc.',
|
|
80
|
+
'staging.'
|
|
81
|
+
];
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Override Development Patterns:**
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
const cms = new Manager({
|
|
88
|
+
developmentPatterns: [
|
|
89
|
+
'localhost',
|
|
90
|
+
'127.0.0.1',
|
|
91
|
+
'.local'
|
|
92
|
+
],
|
|
93
|
+
domainMapping: {
|
|
94
|
+
'www.example.com': 'example.com',
|
|
95
|
+
'new.example.com': 'example.com'
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Important Notes:**
|
|
101
|
+
|
|
102
|
+
- Domain patterns only match at the start or end of domains, not arbitrary positions
|
|
103
|
+
- Override `developmentPatterns` in production to prevent staging/acc domains from enabling development mode
|
|
104
|
+
|
|
105
|
+
## Security Configuration
|
|
106
|
+
|
|
107
|
+
### External Domains for CSP
|
|
108
|
+
|
|
109
|
+
Configure external domains for CSP directives (kebab-case or camelCase):
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const cms = new Manager({
|
|
113
|
+
appServerConfig: {
|
|
114
|
+
developmentExternalDomains: {
|
|
115
|
+
'scriptSrc': ['https://cdn.example.com'],
|
|
116
|
+
'script-src': ['https://analytics.example.com'],
|
|
117
|
+
'styleSrc': ['https://fonts.googleapis.com'],
|
|
118
|
+
'font-src': ['https://fonts.gstatic.com']
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**The system automatically:**
|
|
125
|
+
|
|
126
|
+
- Converts kebab-case keys to camelCase
|
|
127
|
+
- Adds domains to both the base directive and the -elem variant
|
|
128
|
+
|
|
129
|
+
### CSP Directive Merging vs Override
|
|
130
|
+
|
|
131
|
+
**Default (merge with base directives):**
|
|
132
|
+
|
|
133
|
+
```javascript
|
|
134
|
+
const cms = new Manager({
|
|
135
|
+
appServerConfig: {
|
|
136
|
+
helmetConfig: {
|
|
137
|
+
contentSecurityPolicy: {
|
|
138
|
+
directives: {
|
|
139
|
+
scriptSrc: ['https://cdn.example.com']
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Default Base Directives:**
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
{
|
|
151
|
+
defaultSrc: ["'self'"],
|
|
152
|
+
scriptSrc: ["'self'"],
|
|
153
|
+
scriptSrcElem: ["'self'"],
|
|
154
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
155
|
+
styleSrcElem: ["'self'", "'unsafe-inline'"],
|
|
156
|
+
imgSrc: ["'self'", "data:", "https:"],
|
|
157
|
+
fontSrc: ["'self'"],
|
|
158
|
+
connectSrc: ["'self'"],
|
|
159
|
+
frameAncestors: ["'none'"],
|
|
160
|
+
baseUri: ["'self'"],
|
|
161
|
+
formAction: ["'self'"]
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Complete Replacement:**
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
const cms = new Manager({
|
|
169
|
+
appServerConfig: {
|
|
170
|
+
helmetConfig: {
|
|
171
|
+
contentSecurityPolicy: {
|
|
172
|
+
overrideDirectives: true,
|
|
173
|
+
directives: {
|
|
174
|
+
defaultSrc: ["'self'"],
|
|
175
|
+
scriptSrc: ["'self'", "https://trusted-cdn.com"],
|
|
176
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
177
|
+
imgSrc: ["'self'", "data:", "https:"],
|
|
178
|
+
fontSrc: ["'self'"],
|
|
179
|
+
connectSrc: ["'self'"],
|
|
180
|
+
frameAncestors: ["'none'"],
|
|
181
|
+
baseUri: ["'self'"],
|
|
182
|
+
formAction: ["'self'"]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Additional Helmet Security Headers
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const cms = new Manager({
|
|
194
|
+
appServerConfig: {
|
|
195
|
+
helmetConfig: {
|
|
196
|
+
hsts: {
|
|
197
|
+
maxAge: 31536000,
|
|
198
|
+
includeSubDomains: true,
|
|
199
|
+
preload: true
|
|
200
|
+
},
|
|
201
|
+
crossOriginOpenerPolicy: {
|
|
202
|
+
policy: "same-origin"
|
|
203
|
+
},
|
|
204
|
+
crossOriginResourcePolicy: {
|
|
205
|
+
policy: "same-origin"
|
|
206
|
+
},
|
|
207
|
+
crossOriginEmbedderPolicy: {
|
|
208
|
+
policy: "require-corp"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Note:** In development mode, CSP and HSTS are automatically disabled. Security headers are only enforced in production.
|
|
216
|
+
|
|
217
|
+
**Trusted Types:** To enable Trusted Types for enhanced XSS protection:
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
requireTrustedTypesFor: ["'script'"]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
However, this requires updating all JavaScript code to use the Trusted Types API.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Multi-Domain and Internationalization Guide
|
|
2
|
+
|
|
3
|
+
## Internationalization
|
|
4
|
+
|
|
5
|
+
### Translation Files
|
|
6
|
+
|
|
7
|
+
Create translation files in the `translations` directory:
|
|
8
|
+
|
|
9
|
+
**translations/en.json:**
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"navigation": {
|
|
14
|
+
"home": "Home",
|
|
15
|
+
"about": "About Us",
|
|
16
|
+
"contact": "Contact"
|
|
17
|
+
},
|
|
18
|
+
"messages": {
|
|
19
|
+
"welcome": "Welcome to our site!",
|
|
20
|
+
"greeting": "Hello {name}!"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**translations/es.json:**
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"navigation": {
|
|
30
|
+
"home": "Inicio",
|
|
31
|
+
"about": "Acerca de",
|
|
32
|
+
"contact": "Contacto"
|
|
33
|
+
},
|
|
34
|
+
"messages": {
|
|
35
|
+
"welcome": "¡Bienvenido a nuestro sitio!",
|
|
36
|
+
"greeting": "¡Hola {name}!"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Using Translations in Templates
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
[translate(navigation.home)]
|
|
45
|
+
[t(navigation.home, Home)]
|
|
46
|
+
[t(messages.greeting, Hello!, {name: John})]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Locale detection from request headers or ?locale=es parameter.
|
|
50
|
+
|
|
51
|
+
## Multi-Domain Setup
|
|
52
|
+
|
|
53
|
+
### Directory Structure
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
templates/
|
|
57
|
+
├── layouts/
|
|
58
|
+
│ ├── default.html
|
|
59
|
+
│ ├── full-width.html
|
|
60
|
+
│ └── minimal.html
|
|
61
|
+
├── domains/
|
|
62
|
+
│ ├── example.com/
|
|
63
|
+
│ │ ├── layouts/
|
|
64
|
+
│ │ ├── partials/
|
|
65
|
+
│ │ │ ├── header.html
|
|
66
|
+
│ │ │ └── footer.html
|
|
67
|
+
│ │ ├── cms_forms/
|
|
68
|
+
│ │ │ ├── form.html
|
|
69
|
+
│ │ │ └── field_text.html
|
|
70
|
+
│ │ ├── page.html
|
|
71
|
+
│ │ └── index.html
|
|
72
|
+
│ └── dev.example.com/
|
|
73
|
+
│ └── page.html
|
|
74
|
+
├── partials/
|
|
75
|
+
│ ├── header.html (default)
|
|
76
|
+
│ └── footer.html (default)
|
|
77
|
+
├── cms_forms/
|
|
78
|
+
│ ├── form.html
|
|
79
|
+
│ ├── field_text.html
|
|
80
|
+
│ └── field_email.html
|
|
81
|
+
├── translations/
|
|
82
|
+
│ ├── en.json
|
|
83
|
+
│ ├── es.json
|
|
84
|
+
│ └── fr.json
|
|
85
|
+
├── page.html (base HTML wrapper)
|
|
86
|
+
└── 404.html
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Template Resolution Order
|
|
90
|
+
|
|
91
|
+
1. Domain-specific: `templates/domains/{domain}/template.html`
|
|
92
|
+
2. Default: `templates/template.html`
|
|
93
|
+
3. Base: Package default templates
|
|
94
|
+
|
|
95
|
+
### Configuration
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
const cms = new Manager({
|
|
99
|
+
defaultDomain: 'example.com',
|
|
100
|
+
domainMapping: {'dev.example.com': 'development'},
|
|
101
|
+
siteKeyMapping: {'example.com': 'main'}
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Layout System
|
|
106
|
+
|
|
107
|
+
The CMS uses a two-tier layout system:
|
|
108
|
+
|
|
109
|
+
**page.html - Full HTML wrapper:**
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<!DOCTYPE html>
|
|
113
|
+
<html lang="{{locale}}">
|
|
114
|
+
<head>
|
|
115
|
+
<title>{{title}}</title>
|
|
116
|
+
<meta name="description" content="{{description}}"/>
|
|
117
|
+
<link href="[url(/css/styles.css)]" rel="stylesheet"/>
|
|
118
|
+
</head>
|
|
119
|
+
<body class="{{siteHandle}}">
|
|
120
|
+
{{&content}}
|
|
121
|
+
<script src="[url(/js/scripts.js)]"></script>
|
|
122
|
+
</body>
|
|
123
|
+
</html>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**layouts/default.html - Body content only:**
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<entity name="cmsBlocks" field="name" value="header-main"/>
|
|
130
|
+
|
|
131
|
+
<main id="main" class="main-container">
|
|
132
|
+
<div class="container">
|
|
133
|
+
<div class="row">
|
|
134
|
+
<div class="col-md-3">
|
|
135
|
+
<entity name="cmsBlocks" field="name" value="sidebar-left"/>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="col-md-9">
|
|
138
|
+
{{&content}}
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</main>
|
|
143
|
+
|
|
144
|
+
<entity name="cmsBlocks" field="name" value="footer-main"/>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Available Layouts:**
|
|
148
|
+
|
|
149
|
+
Pages can use different layouts by setting the `layout` field in `cms_pages`:
|
|
150
|
+
|
|
151
|
+
- `default` - Header, sidebar, main content, footer
|
|
152
|
+
- `full-width` - Full width without sidebars
|
|
153
|
+
- `minimal` - Basic layout with minimal styling
|
|
154
|
+
|
|
155
|
+
## Content Blocks
|
|
156
|
+
|
|
157
|
+
Create reusable content blocks in the `cms_blocks` table via admin panel:
|
|
158
|
+
|
|
159
|
+
```sql
|
|
160
|
+
INSERT INTO cms_blocks (name, title, content) VALUES
|
|
161
|
+
('contact-info', 'Contact Information', '<p>Email: info@example.com</p>'),
|
|
162
|
+
('article-sidebar', 'Article Categories',
|
|
163
|
+
'<div class="categories"><h3>Categories</h3><ul><li><a href="[url(/articles/technology)]">Technology</a></li></ul></div>');
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Entity Access Control
|
|
167
|
+
|
|
168
|
+
Control which entities are publicly accessible:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const cms = new Manager({
|
|
172
|
+
entityAccess: {
|
|
173
|
+
articles: { public: true, operations: ['read'] },
|
|
174
|
+
cmsPages: { public: true, operations: ['read'] },
|
|
175
|
+
users: { public: false }
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
```
|