@currentjs/gen 0.3.2 → 0.5.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/CHANGELOG.md +10 -611
- package/README.md +623 -427
- package/dist/cli.js +2 -1
- package/dist/commands/commit.js +25 -42
- package/dist/commands/createApp.js +1 -0
- package/dist/commands/createModule.js +151 -45
- package/dist/commands/diff.js +27 -40
- package/dist/commands/generateAll.js +141 -291
- package/dist/commands/migrateCommit.js +6 -18
- package/dist/commands/migratePush.d.ts +1 -0
- package/dist/commands/migratePush.js +135 -0
- package/dist/commands/migrateUpdate.d.ts +1 -0
- package/dist/commands/migrateUpdate.js +147 -0
- package/dist/commands/newGenerateAll.d.ts +4 -0
- package/dist/commands/newGenerateAll.js +336 -0
- package/dist/generators/controllerGenerator.d.ts +43 -19
- package/dist/generators/controllerGenerator.js +547 -329
- package/dist/generators/domainLayerGenerator.d.ts +21 -0
- package/dist/generators/domainLayerGenerator.js +276 -0
- package/dist/generators/dtoGenerator.d.ts +21 -0
- package/dist/generators/dtoGenerator.js +518 -0
- package/dist/generators/newControllerGenerator.d.ts +55 -0
- package/dist/generators/newControllerGenerator.js +644 -0
- package/dist/generators/newServiceGenerator.d.ts +19 -0
- package/dist/generators/newServiceGenerator.js +266 -0
- package/dist/generators/newStoreGenerator.d.ts +39 -0
- package/dist/generators/newStoreGenerator.js +408 -0
- package/dist/generators/newTemplateGenerator.d.ts +29 -0
- package/dist/generators/newTemplateGenerator.js +510 -0
- package/dist/generators/serviceGenerator.d.ts +16 -51
- package/dist/generators/serviceGenerator.js +167 -586
- package/dist/generators/storeGenerator.d.ts +35 -32
- package/dist/generators/storeGenerator.js +291 -238
- package/dist/generators/storeGeneratorV2.d.ts +31 -0
- package/dist/generators/storeGeneratorV2.js +190 -0
- package/dist/generators/templateGenerator.d.ts +21 -21
- package/dist/generators/templateGenerator.js +393 -268
- package/dist/generators/templates/appTemplates.d.ts +3 -1
- package/dist/generators/templates/appTemplates.js +15 -10
- package/dist/generators/templates/data/appYamlTemplate +5 -2
- package/dist/generators/templates/data/cursorRulesTemplate +315 -221
- package/dist/generators/templates/data/frontendScriptTemplate +45 -11
- package/dist/generators/templates/data/mainViewTemplate +1 -1
- package/dist/generators/templates/data/systemTsTemplate +5 -0
- package/dist/generators/templates/index.d.ts +0 -3
- package/dist/generators/templates/index.js +0 -3
- package/dist/generators/templates/newStoreTemplates.d.ts +5 -0
- package/dist/generators/templates/newStoreTemplates.js +141 -0
- package/dist/generators/templates/storeTemplates.d.ts +1 -5
- package/dist/generators/templates/storeTemplates.js +102 -219
- package/dist/generators/templates/viewTemplates.js +1 -1
- package/dist/generators/useCaseGenerator.d.ts +13 -0
- package/dist/generators/useCaseGenerator.js +188 -0
- package/dist/types/configTypes.d.ts +148 -0
- package/dist/types/configTypes.js +10 -0
- package/dist/utils/childEntityUtils.d.ts +18 -0
- package/dist/utils/childEntityUtils.js +78 -0
- package/dist/utils/commandUtils.d.ts +43 -0
- package/dist/utils/commandUtils.js +124 -0
- package/dist/utils/commitUtils.d.ts +4 -1
- package/dist/utils/constants.d.ts +10 -0
- package/dist/utils/constants.js +13 -1
- package/dist/utils/diResolver.d.ts +32 -0
- package/dist/utils/diResolver.js +204 -0
- package/dist/utils/new_parts_of_migrationUtils.d.ts +0 -0
- package/dist/utils/new_parts_of_migrationUtils.js +164 -0
- package/dist/utils/typeUtils.d.ts +19 -0
- package/dist/utils/typeUtils.js +70 -0
- package/package.json +7 -3
|
@@ -3,11 +3,14 @@
|
|
|
3
3
|
## Architecture Overview
|
|
4
4
|
This is a CurrentJS framework application using clean architecture principles with the following layers:
|
|
5
5
|
- **Controllers**: Handle HTTP requests/responses and route handling
|
|
6
|
+
- **UseCases**: Orchestrate handler calls in sequence
|
|
6
7
|
- **Services**: Contain business logic and orchestrate operations
|
|
7
8
|
- **Stores**: Provide data access layer and database operations
|
|
8
9
|
- **Domain Entities**: Core business models
|
|
9
10
|
- **Views**: HTML templates for server-side rendering
|
|
10
11
|
|
|
12
|
+
All layers (except Domain and Views) are auto-wired via **dependency injection** — the generator scans `@Injectable` and `@Controller` decorators, resolves constructor dependencies, and generates wiring code in `src/app.ts`.
|
|
13
|
+
|
|
11
14
|
## Commands
|
|
12
15
|
|
|
13
16
|
```bash
|
|
@@ -26,9 +29,10 @@ current diff [module] # Show differences between generated and current code
|
|
|
26
29
|
1. Create an empty app (`current create app`) – this step is already done.
|
|
27
30
|
2. Create a new module: `current create module Name`
|
|
28
31
|
3. In the module's yaml file, define module's:
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
+
- domain (aggregates and value objects)
|
|
33
|
+
- useCases (with input/output and handlers)
|
|
34
|
+
- api endpoints (with auth)
|
|
35
|
+
- web pages (with auth and onSuccess/onError)
|
|
32
36
|
4. Generate TypeScript files: `current generate Name`
|
|
33
37
|
5. If required, make changes in the:
|
|
34
38
|
- model (i.e. some specific business rules or validations)
|
|
@@ -38,7 +42,7 @@ current diff [module] # Show differences between generated and current code
|
|
|
38
42
|
--- If needed more than CRUD: ---
|
|
39
43
|
|
|
40
44
|
7. Define action in the service by creating a method
|
|
41
|
-
8. Describe this action in the module's yaml.
|
|
45
|
+
8. Describe this action in the module's yaml under useCases. Additionally, you may define api/web endpoints.
|
|
42
46
|
9. `current generate Modulename`
|
|
43
47
|
10. commit changes: `current commit`
|
|
44
48
|
|
|
@@ -54,189 +58,223 @@ current diff [module] # Show differences between generated and current code
|
|
|
54
58
|
|
|
55
59
|
**Complete Module Example:**
|
|
56
60
|
```yaml
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
required: true
|
|
63
|
-
|
|
64
|
-
type:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
61
|
+
domain:
|
|
62
|
+
aggregates:
|
|
63
|
+
Post:
|
|
64
|
+
root: true # Marks as aggregate root
|
|
65
|
+
fields:
|
|
66
|
+
title: { type: string, required: true }
|
|
67
|
+
content: { type: string, required: true }
|
|
68
|
+
authorId: { type: id, required: true }
|
|
69
|
+
publishedAt: { type: datetime }
|
|
70
|
+
status: { type: string, required: true }
|
|
71
|
+
|
|
72
|
+
useCases:
|
|
73
|
+
Post:
|
|
74
|
+
list:
|
|
75
|
+
input:
|
|
76
|
+
pagination: { type: offset, defaults: { limit: 20, maxLimit: 100 } }
|
|
77
|
+
output: { from: Post, pagination: true }
|
|
78
|
+
handlers: [default:list] # Built-in list handler
|
|
79
|
+
get:
|
|
80
|
+
input: { identifier: id }
|
|
81
|
+
output: { from: Post }
|
|
82
|
+
handlers: [default:get] # Built-in get handler
|
|
83
|
+
create:
|
|
84
|
+
input: { from: Post }
|
|
85
|
+
output: { from: Post }
|
|
86
|
+
handlers: [default:create] # Built-in create
|
|
87
|
+
update:
|
|
88
|
+
input: { identifier: id, from: Post, partial: true }
|
|
89
|
+
output: { from: Post }
|
|
90
|
+
handlers: [default:update]
|
|
91
|
+
delete:
|
|
92
|
+
input: { identifier: id }
|
|
93
|
+
output: void
|
|
94
|
+
handlers: [ # Chain multiple handlers
|
|
95
|
+
checkCanDelete, # Custom → PostService.checkCanDelete(result, input)
|
|
96
|
+
default:delete # Built-in delete
|
|
97
|
+
]
|
|
98
|
+
publish: # Custom action
|
|
99
|
+
input: { identifier: id }
|
|
100
|
+
output: { from: Post }
|
|
101
|
+
handlers: [
|
|
102
|
+
default:get, # Fetch entity
|
|
103
|
+
validateForPublish, # Custom → PostService.validateForPublish(result, input)
|
|
104
|
+
updatePublishStatus # Custom → PostService.updatePublishStatus(result, input)
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
api: # REST API configuration
|
|
108
|
+
Post: # Keyed by model name
|
|
109
|
+
prefix: /api/posts # Base URL for API endpoints
|
|
110
|
+
endpoints:
|
|
111
|
+
- method: GET # HTTP method
|
|
112
|
+
path: / # Relative path (becomes /api/posts/)
|
|
113
|
+
useCase: Post:list # References useCases.Post.list
|
|
114
|
+
auth: all # Public access
|
|
115
|
+
- method: GET
|
|
116
|
+
path: /:id # Path parameter
|
|
117
|
+
useCase: Post:get
|
|
118
|
+
auth: all
|
|
119
|
+
- method: POST
|
|
120
|
+
path: /
|
|
121
|
+
useCase: Post:create
|
|
122
|
+
auth: authenticated # Must be logged in
|
|
123
|
+
- method: PUT
|
|
124
|
+
path: /:id
|
|
125
|
+
useCase: Post:update
|
|
126
|
+
auth: [owner, admin] # Owner OR admin (OR logic)
|
|
127
|
+
- method: DELETE
|
|
128
|
+
path: /:id
|
|
129
|
+
useCase: Post:delete
|
|
130
|
+
auth: [owner, admin]
|
|
131
|
+
- method: POST # Custom endpoint
|
|
132
|
+
path: /:id/publish
|
|
133
|
+
useCase: Post:publish
|
|
134
|
+
auth: [owner, editor, admin]
|
|
135
|
+
|
|
136
|
+
web: # Web interface configuration
|
|
137
|
+
Post: # Keyed by model name
|
|
138
|
+
prefix: /posts # Base URL for web pages
|
|
139
|
+
layout: main_view # Layout template name
|
|
140
|
+
pages:
|
|
141
|
+
- path: / # List page
|
|
142
|
+
useCase: Post:list
|
|
143
|
+
view: postList # Template name
|
|
144
|
+
auth: all
|
|
145
|
+
- path: /:id # Detail page
|
|
146
|
+
useCase: Post:get
|
|
147
|
+
view: postDetail
|
|
148
|
+
auth: all
|
|
149
|
+
- path: /create # Create form (GET = show form)
|
|
150
|
+
method: GET
|
|
151
|
+
view: postCreate
|
|
152
|
+
auth: authenticated
|
|
153
|
+
- path: /create # Create form (POST = submit)
|
|
154
|
+
method: POST
|
|
155
|
+
useCase: Post:create
|
|
156
|
+
auth: authenticated
|
|
157
|
+
onSuccess: # What happens after successful submission
|
|
158
|
+
redirect: /posts/:id
|
|
159
|
+
toast: "Post created successfully"
|
|
160
|
+
onError:
|
|
161
|
+
stay: true
|
|
162
|
+
toast: error
|
|
163
|
+
- path: /:id/edit # Edit form (GET = show form)
|
|
164
|
+
method: GET
|
|
165
|
+
useCase: Post:get # Load existing data
|
|
166
|
+
view: postUpdate
|
|
167
|
+
auth: [owner, admin]
|
|
168
|
+
- path: /:id/edit # Edit form (POST = submit)
|
|
169
|
+
method: POST
|
|
170
|
+
useCase: Post:update
|
|
171
|
+
auth: [owner, admin]
|
|
172
|
+
onSuccess:
|
|
173
|
+
back: true
|
|
174
|
+
toast: "Post updated successfully"
|
|
151
175
|
```
|
|
152
176
|
|
|
153
|
-
**Make sure no `
|
|
154
|
-
|
|
155
|
-
**Field Types:**
|
|
156
|
-
- `string` - Text data
|
|
157
|
-
- `number` - Numeric data (integer or float)
|
|
158
|
-
- `boolean` - True/false values
|
|
159
|
-
- `datetime` - Date and time values
|
|
160
|
-
- `ModelName` - Relationship to another model (e.g., `Owner`, `User`, `Post`)
|
|
161
|
-
|
|
162
|
-
**Multi-Model Endpoint Configuration:**
|
|
177
|
+
**Make sure no `id`/`owner_id`/`created_at`/`updated_at`/`deleted_at` fields are present in the domain definition, since they are added automatically**
|
|
163
178
|
|
|
164
|
-
|
|
179
|
+
**Use case option: withChild (aggregate root with child entities)**
|
|
165
180
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
181
|
+
Per use case you can set `withChild: true` (default `false`) to show child entities on the root's pages. Only applies when the entity has child entities (e.g. Invoice with InvoiceItem). Ignored if there are no child entities.
|
|
182
|
+
- **list** + `withChild: true`: adds a link column on the list page to the child entity list (no extra loading).
|
|
183
|
+
- **get** + `withChild: true`: on the detail page, renders a table of child entities below the main card, with View/Edit/Add links.
|
|
169
184
|
|
|
185
|
+
Example:
|
|
170
186
|
```yaml
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
endpoints:
|
|
179
|
-
- path: /create
|
|
180
|
-
view: catCreate
|
|
181
|
-
# Uses Cat model
|
|
182
|
-
|
|
183
|
-
- path: /createOwner
|
|
184
|
-
view: ownerCreate
|
|
185
|
-
model: Person # Override for this endpoint
|
|
187
|
+
useCases:
|
|
188
|
+
Invoice:
|
|
189
|
+
get:
|
|
190
|
+
withChild: true
|
|
191
|
+
input: { identifier: id }
|
|
192
|
+
output: { from: Invoice }
|
|
193
|
+
handlers: [default:get]
|
|
186
194
|
```
|
|
187
195
|
|
|
188
|
-
**
|
|
196
|
+
**Field Types:**
|
|
197
|
+
- `string` - Text data (VARCHAR in database)
|
|
198
|
+
- `number` - Numeric data (INT/DECIMAL in database)
|
|
199
|
+
- `integer` - Integer data (INT in database)
|
|
200
|
+
- `decimal` - Decimal data (DECIMAL in database)
|
|
201
|
+
- `boolean` - True/false values (BOOLEAN in database)
|
|
202
|
+
- `datetime` - Date and time values (DATETIME in database)
|
|
203
|
+
- `date` - Date values (DATE in database)
|
|
204
|
+
- `id` - Foreign key reference (INT in database)
|
|
205
|
+
- `json` - JSON data
|
|
206
|
+
- `enum` - Enumerated values (use with `values: [...]`)
|
|
207
|
+
- `ModelName` - Relationship to another model (e.g., `Owner`, `User`, `Post`)
|
|
208
|
+
|
|
209
|
+
**Multi-Model Configuration:**
|
|
189
210
|
|
|
190
|
-
|
|
211
|
+
When working with multiple models in a single module, each model is a separate key in `api` and `web`:
|
|
191
212
|
|
|
192
213
|
```yaml
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
214
|
+
domain:
|
|
215
|
+
aggregates:
|
|
216
|
+
Cat:
|
|
217
|
+
root: true
|
|
218
|
+
fields:
|
|
219
|
+
name: { type: string, required: true }
|
|
220
|
+
Person:
|
|
221
|
+
root: true
|
|
222
|
+
fields:
|
|
223
|
+
name: { type: string, required: true }
|
|
224
|
+
email: { type: string, required: true }
|
|
225
|
+
|
|
203
226
|
api:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
endpoints:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
227
|
+
Cat:
|
|
228
|
+
prefix: /api/cat
|
|
229
|
+
endpoints:
|
|
230
|
+
- method: GET
|
|
231
|
+
path: /
|
|
232
|
+
useCase: Cat:list
|
|
233
|
+
auth: all
|
|
234
|
+
Person:
|
|
235
|
+
prefix: /api/person
|
|
236
|
+
endpoints:
|
|
237
|
+
- method: GET
|
|
238
|
+
path: /
|
|
239
|
+
useCase: Person:list
|
|
240
|
+
auth: all
|
|
241
|
+
|
|
242
|
+
web:
|
|
243
|
+
Cat:
|
|
244
|
+
prefix: /cat
|
|
245
|
+
layout: main_view
|
|
246
|
+
pages:
|
|
247
|
+
- path: /
|
|
248
|
+
useCase: Cat:list
|
|
249
|
+
view: catList
|
|
250
|
+
auth: all
|
|
251
|
+
Person:
|
|
252
|
+
prefix: /person
|
|
253
|
+
layout: main_view
|
|
254
|
+
pages:
|
|
255
|
+
- path: /
|
|
256
|
+
useCase: Person:list
|
|
257
|
+
view: personList
|
|
258
|
+
auth: all
|
|
211
259
|
```
|
|
212
260
|
|
|
213
|
-
**Model Resolution Priority:**
|
|
214
|
-
1. `endpoint.model` (explicit override)
|
|
215
|
-
2. Inferred from action handler (e.g., `Person:default:create`)
|
|
216
|
-
3. `api.model` or `routes.model` (section default)
|
|
217
|
-
4. First model in `models[]` array (fallback)
|
|
218
|
-
|
|
219
261
|
**Model Relationships:**
|
|
220
262
|
|
|
221
|
-
Define relationships by using another model's name as the field type
|
|
263
|
+
Define relationships by using another model's name as the field type in `domain.aggregates`:
|
|
222
264
|
|
|
223
265
|
```yaml
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
required: true
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
type: string
|
|
235
|
-
required: true
|
|
236
|
-
- name: owner
|
|
237
|
-
type: Owner # Creates relationship with Owner model
|
|
238
|
-
required: true # Auto-generates foreign key: ownerId
|
|
239
|
-
displayFields: [name] # Optional: fields to show in dropdowns
|
|
266
|
+
domain:
|
|
267
|
+
aggregates:
|
|
268
|
+
Owner:
|
|
269
|
+
root: true
|
|
270
|
+
fields:
|
|
271
|
+
name: { type: string, required: true }
|
|
272
|
+
|
|
273
|
+
Cat:
|
|
274
|
+
root: true
|
|
275
|
+
fields:
|
|
276
|
+
name: { type: string, required: true }
|
|
277
|
+
owner: { type: Owner, required: true } # Creates relationship with Owner model
|
|
240
278
|
```
|
|
241
279
|
|
|
242
280
|
**Generated Behavior:**
|
|
@@ -255,90 +293,146 @@ Foreign keys are auto-generated following the pattern `fieldName + 'Id'`:
|
|
|
255
293
|
|
|
256
294
|
The foreign key always references the `id` field of the related model.
|
|
257
295
|
|
|
258
|
-
**🔄 Handler vs
|
|
296
|
+
**🔄 Handler vs Use Case Architecture:**
|
|
259
297
|
- **Handler**: Creates a separate service method (one handler = one service method)
|
|
260
|
-
- **
|
|
298
|
+
- **Use Case**: Defined under `useCases.ModelName.actionName`, calls handler methods step-by-step
|
|
299
|
+
- **UseCase reference**: Used in `api`/`web` endpoints as `ModelName:actionName` (e.g., `Post:list`)
|
|
300
|
+
|
|
301
|
+
**Built-in Handlers (used in `useCases.*.*.handlers`):**
|
|
302
|
+
- `default:list` - Creates service method with pagination parameters
|
|
303
|
+
- `default:get` - Creates service method named `get` with ID parameter
|
|
304
|
+
- `default:create` - Creates service method with DTO parameter
|
|
305
|
+
- `default:update` - Creates service method with ID and DTO parameters
|
|
306
|
+
- `default:delete` - Creates service method with ID parameter
|
|
261
307
|
|
|
262
|
-
|
|
263
|
-
- `ModelName:default:list` - Creates service method with pagination parameters
|
|
264
|
-
- `ModelName:default:get` - Creates service method named `get` with ID parameter
|
|
265
|
-
- `ModelName:default:create` - Creates service method with DTO parameter
|
|
266
|
-
- `ModelName:default:update` - Creates service method with ID and DTO parameters
|
|
267
|
-
- `ModelName:default:delete` - Creates service method with ID parameter
|
|
308
|
+
Note: Handlers within `useCases` do NOT need a model prefix because the model is already the key.
|
|
268
309
|
|
|
269
|
-
**Custom
|
|
270
|
-
- `
|
|
310
|
+
**Custom Handlers:**
|
|
311
|
+
- `customMethodName` - Creates service method that accepts `(result, input)` parameters
|
|
271
312
|
- `result`: Result from previous handler (or `null` if it's the first handler)
|
|
272
|
-
- `
|
|
313
|
+
- `input`: The parsed input DTO
|
|
273
314
|
- Each handler generates a separate method in the service
|
|
274
315
|
- User can customize the implementation after generation
|
|
275
316
|
|
|
276
|
-
**🔗 Multiple Handlers per
|
|
277
|
-
When
|
|
317
|
+
**🔗 Multiple Handlers per Use Case:**
|
|
318
|
+
When a use case has multiple handlers, each handler generates a separate service method, and the use case orchestrator calls them sequentially. The use case returns the result from the last handler.
|
|
278
319
|
|
|
279
320
|
**Parameter Passing Rules:**
|
|
280
|
-
- **Default handlers** (
|
|
281
|
-
- **Custom handlers**: Receive `(result,
|
|
321
|
+
- **Default handlers** (`default:*`): Receive standard parameters (id, pagination, DTO, etc.)
|
|
322
|
+
- **Custom handlers**: Receive `(result, input)` where:
|
|
282
323
|
- `result`: Result from previous handler, or `null` if it's the first handler
|
|
283
|
-
- `
|
|
284
|
-
|
|
285
|
-
**Handler Format Examples:**
|
|
286
|
-
- `
|
|
287
|
-
- `
|
|
288
|
-
- `
|
|
289
|
-
- `
|
|
290
|
-
|
|
291
|
-
**
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
324
|
+
- `input`: Parsed input DTO
|
|
325
|
+
|
|
326
|
+
**Handler Format Examples (inside `useCases`):**
|
|
327
|
+
- `default:list` - Creates service method `list(page, limit)`
|
|
328
|
+
- `default:get` - Creates service method `get(id)`
|
|
329
|
+
- `validateContent` - Creates service method `validateContent(result, input)`
|
|
330
|
+
- `notifySubscribers` - Creates service method `notifySubscribers(result, input)`
|
|
331
|
+
|
|
332
|
+
**Form Success/Error Handling (in `web` pages):**
|
|
333
|
+
|
|
334
|
+
Instead of a separate `strategy` field, use `onSuccess` and `onError` on web page endpoints:
|
|
335
|
+
```yaml
|
|
336
|
+
onSuccess:
|
|
337
|
+
redirect: /posts/:id # Redirect to URL
|
|
338
|
+
toast: "Saved!" # Show toast notification
|
|
339
|
+
back: true # Navigate back in browser history
|
|
340
|
+
stay: true # Stay on current page
|
|
341
|
+
onError:
|
|
342
|
+
stay: true # Stay on current page
|
|
343
|
+
toast: error # Show error toast
|
|
344
|
+
```
|
|
298
345
|
|
|
299
|
-
|
|
346
|
+
The template generator converts `onSuccess` options into `data-strategy` attributes on HTML forms.
|
|
347
|
+
|
|
348
|
+
**Auth Configuration (per endpoint in `api` and `web`):**
|
|
300
349
|
- `all` - Anyone (including anonymous users)
|
|
301
350
|
- `authenticated` - Any logged-in user
|
|
302
|
-
- `owner` - User who created the entity
|
|
351
|
+
- `owner` - User who created the entity (checks `ownerId` field)
|
|
303
352
|
- `admin`, `editor`, `user` - Custom roles from JWT token
|
|
304
|
-
-
|
|
353
|
+
- `[owner, admin]` - Array syntax: user must match ANY (OR logic). Privileged roles bypass ownership check.
|
|
305
354
|
|
|
306
355
|
**Generated Files from Configuration:**
|
|
307
356
|
- Domain entity class (one per model)
|
|
308
|
-
-
|
|
357
|
+
- Use case orchestrator (one per model)
|
|
358
|
+
- Service class with handler methods (one per model)
|
|
359
|
+
- Input/Output DTOs (one per use case)
|
|
309
360
|
- API controller with REST endpoints (one per model)
|
|
310
361
|
- Web controller with page rendering (one per model)
|
|
311
362
|
- Store class with database operations (one per model)
|
|
312
363
|
- HTML templates for all views
|
|
313
|
-
- TypeScript interfaces and DTOs
|
|
314
364
|
|
|
315
365
|
**Multi-Model Support:**
|
|
316
|
-
- Each model gets its own
|
|
317
|
-
-
|
|
318
|
-
-
|
|
319
|
-
-
|
|
366
|
+
- Each model gets its own Service, UseCase, Controller, and Store classes
|
|
367
|
+
- In `api`/`web`, each model is a separate key (e.g., `api.Cat`, `api.Person`)
|
|
368
|
+
- UseCase references use `ModelName:actionName` format (e.g., `Post:list`, `Person:create`)
|
|
369
|
+
- Handlers within `useCases` do not need model prefix (model is already the key)
|
|
320
370
|
- Controllers and services are generated per model, not per module
|
|
321
371
|
|
|
372
|
+
## Dependency Injection & Wiring
|
|
373
|
+
|
|
374
|
+
The application uses a decorator-driven DI system. All wiring is auto-generated in `src/app.ts` between `// currentjs:controllers:start` and `// currentjs:controllers:end` markers. **Never edit this block manually** — it is regenerated on each `current generate`.
|
|
375
|
+
|
|
376
|
+
### `@Injectable` Decorator
|
|
377
|
+
|
|
378
|
+
Lives in `src/system.ts`. Marks a class for automatic DI discovery:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { Injectable } from '../../../../system';
|
|
382
|
+
|
|
383
|
+
@Injectable()
|
|
384
|
+
export class MyService {
|
|
385
|
+
constructor(private myStore: MyStore) {}
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Generated Stores, Services, and UseCases already have `@Injectable()`. Controllers use `@Controller()` from `@currentjs/router` instead.
|
|
390
|
+
|
|
391
|
+
### Adding Custom Classes to DI
|
|
392
|
+
|
|
393
|
+
If you create a new class that should be auto-wired:
|
|
394
|
+
1. Add `@Injectable()` decorator (import from `src/system.ts`)
|
|
395
|
+
2. Declare dependencies as constructor parameters with their types
|
|
396
|
+
3. Run `current generate` — the class will be auto-imported and instantiated in `app.ts`
|
|
397
|
+
4. Run `current commit` to preserve your changes
|
|
398
|
+
|
|
399
|
+
### How Wiring Works
|
|
400
|
+
|
|
401
|
+
The generator:
|
|
402
|
+
1. Scans all module `.ts` files for `@Injectable` and `@Controller` decorators
|
|
403
|
+
2. Parses constructor parameters to build a dependency graph
|
|
404
|
+
3. Topologically sorts classes (stores → services → use cases → controllers)
|
|
405
|
+
4. Generates imports, instantiations, and the `controllers` array in `app.ts`
|
|
406
|
+
|
|
407
|
+
Database provider instances are injected into stores based on `app.yaml` configuration (global, with optional per-module overrides). Both npm packages and local file paths are supported as providers.
|
|
408
|
+
|
|
322
409
|
## Module Structure
|
|
323
410
|
```
|
|
324
411
|
src/modules/ModuleName/
|
|
325
|
-
├── application/
|
|
326
|
-
│ ├── services/ModuleService.ts # Business logic
|
|
327
|
-
│ └── validation/ModuleValidation.ts # DTOs and validation
|
|
328
412
|
├── domain/
|
|
329
|
-
│
|
|
413
|
+
│ ├── entities/
|
|
414
|
+
│ │ └── Entity.ts # Domain model (aggregate root)
|
|
415
|
+
│ └── valueObjects/
|
|
416
|
+
│ └── ValueObject.ts # Value objects (if any)
|
|
417
|
+
├── application/
|
|
418
|
+
│ ├── useCases/
|
|
419
|
+
│ │ └── EntityUseCase.ts # Use case orchestrator
|
|
420
|
+
│ ├── services/
|
|
421
|
+
│ │ └── EntityService.ts # Business logic handlers
|
|
422
|
+
│ └── dto/
|
|
423
|
+
│ └── EntityAction.ts # Input/Output DTOs per action
|
|
330
424
|
├── infrastructure/
|
|
331
425
|
│ ├── controllers/
|
|
332
|
-
│ │ ├──
|
|
333
|
-
│ │ └──
|
|
334
|
-
│
|
|
335
|
-
│
|
|
426
|
+
│ │ ├── EntityApiController.ts # REST API endpoints
|
|
427
|
+
│ │ └── EntityWebController.ts # Web page controllers
|
|
428
|
+
│ └── stores/
|
|
429
|
+
│ └── EntityStore.ts # Data access implementation
|
|
336
430
|
├── views/
|
|
337
|
-
│ ├──
|
|
338
|
-
│ ├──
|
|
339
|
-
│ ├──
|
|
340
|
-
│ └──
|
|
341
|
-
└──
|
|
431
|
+
│ ├── entityList.html # List view template
|
|
432
|
+
│ ├── entityDetail.html # Detail view template
|
|
433
|
+
│ ├── entityCreate.html # Create form template
|
|
434
|
+
│ └── entityEdit.html # Edit form template
|
|
435
|
+
└── modulename.yaml # Module configuration
|
|
342
436
|
```
|
|
343
437
|
|
|
344
438
|
## Best Practices
|