@atlashub/smartstack-mcp 1.2.2 → 1.3.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/README.md +88 -88
- package/config/default-config.json +62 -62
- package/dist/index.js +404 -17
- package/dist/index.js.map +1 -1
- package/package.json +65 -65
- package/templates/component.tsx.hbs +298 -298
- package/templates/controller.cs.hbs +166 -166
- package/templates/entity-extension.cs.hbs +231 -87
- package/templates/service-extension.cs.hbs +53 -53
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Collections.Generic;
|
|
3
|
-
using System.Threading;
|
|
4
|
-
using System.Threading.Tasks;
|
|
5
|
-
using Microsoft.AspNetCore.Authorization;
|
|
6
|
-
using Microsoft.AspNetCore.Mvc;
|
|
7
|
-
using Microsoft.Extensions.Logging;
|
|
8
|
-
|
|
9
|
-
namespace {{namespace}}.Controllers;
|
|
10
|
-
|
|
11
|
-
/// <summary>
|
|
12
|
-
/// API controller for {{name}} operations
|
|
13
|
-
/// </summary>
|
|
14
|
-
[ApiController]
|
|
15
|
-
[Route("api/[controller]")]
|
|
16
|
-
[Authorize]
|
|
17
|
-
[Produces("application/json")]
|
|
18
|
-
public class {{name}}Controller : ControllerBase
|
|
19
|
-
{
|
|
20
|
-
private readonly ILogger<{{name}}Controller> _logger;
|
|
21
|
-
// private readonly I{{name}}Service _{{nameCamel}}Service;
|
|
22
|
-
|
|
23
|
-
public {{name}}Controller(
|
|
24
|
-
ILogger<{{name}}Controller> logger
|
|
25
|
-
// I{{name}}Service {{nameCamel}}Service
|
|
26
|
-
)
|
|
27
|
-
{
|
|
28
|
-
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
29
|
-
// _{{nameCamel}}Service = {{nameCamel}}Service ?? throw new ArgumentNullException(nameof({{nameCamel}}Service));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/// <summary>
|
|
33
|
-
/// Get all {{namePlural}}
|
|
34
|
-
/// </summary>
|
|
35
|
-
/// <param name="cancellationToken">Cancellation token</param>
|
|
36
|
-
/// <returns>List of {{namePlural}}</returns>
|
|
37
|
-
[HttpGet]
|
|
38
|
-
[ProducesResponseType(typeof(IEnumerable<{{name}}Dto>), 200)]
|
|
39
|
-
public async Task<ActionResult<IEnumerable<{{name}}Dto>>> GetAll(CancellationToken cancellationToken = default)
|
|
40
|
-
{
|
|
41
|
-
_logger.LogInformation("Getting all {{namePlural}}");
|
|
42
|
-
|
|
43
|
-
// TODO: Implement using service
|
|
44
|
-
// var result = await _{{nameCamel}}Service.GetAllAsync(cancellationToken);
|
|
45
|
-
// return Ok(result);
|
|
46
|
-
|
|
47
|
-
return Ok(Array.Empty<{{name}}Dto>());
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/// <summary>
|
|
51
|
-
/// Get {{nameCamel}} by ID
|
|
52
|
-
/// </summary>
|
|
53
|
-
/// <param name="id">{{name}} ID</param>
|
|
54
|
-
/// <param name="cancellationToken">Cancellation token</param>
|
|
55
|
-
/// <returns>{{name}} details</returns>
|
|
56
|
-
[HttpGet("{id:guid}")]
|
|
57
|
-
[ProducesResponseType(typeof({{name}}Dto), 200)]
|
|
58
|
-
[ProducesResponseType(404)]
|
|
59
|
-
public async Task<ActionResult<{{name}}Dto>> GetById(
|
|
60
|
-
Guid id,
|
|
61
|
-
CancellationToken cancellationToken = default)
|
|
62
|
-
{
|
|
63
|
-
_logger.LogInformation("Getting {{nameCamel}} {Id}", id);
|
|
64
|
-
|
|
65
|
-
// TODO: Implement using service
|
|
66
|
-
// var result = await _{{nameCamel}}Service.GetByIdAsync(id, cancellationToken);
|
|
67
|
-
// if (result == null) return NotFound();
|
|
68
|
-
// return Ok(result);
|
|
69
|
-
|
|
70
|
-
return NotFound();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/// <summary>
|
|
74
|
-
/// Create new {{nameCamel}}
|
|
75
|
-
/// </summary>
|
|
76
|
-
/// <param name="request">Create request</param>
|
|
77
|
-
/// <param name="cancellationToken">Cancellation token</param>
|
|
78
|
-
/// <returns>Created {{nameCamel}}</returns>
|
|
79
|
-
[HttpPost]
|
|
80
|
-
[ProducesResponseType(typeof({{name}}Dto), 201)]
|
|
81
|
-
[ProducesResponseType(400)]
|
|
82
|
-
public async Task<ActionResult<{{name}}Dto>> Create(
|
|
83
|
-
[FromBody] Create{{name}}Request request,
|
|
84
|
-
CancellationToken cancellationToken = default)
|
|
85
|
-
{
|
|
86
|
-
_logger.LogInformation("Creating new {{nameCamel}}");
|
|
87
|
-
|
|
88
|
-
// TODO: Validate and create using service
|
|
89
|
-
// var result = await _{{nameCamel}}Service.CreateAsync(request, cancellationToken);
|
|
90
|
-
// return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
|
91
|
-
|
|
92
|
-
var id = Guid.NewGuid();
|
|
93
|
-
return CreatedAtAction(nameof(GetById), new { id }, null);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/// <summary>
|
|
97
|
-
/// Update {{nameCamel}}
|
|
98
|
-
/// </summary>
|
|
99
|
-
/// <param name="id">{{name}} ID</param>
|
|
100
|
-
/// <param name="request">Update request</param>
|
|
101
|
-
/// <param name="cancellationToken">Cancellation token</param>
|
|
102
|
-
[HttpPut("{id:guid}")]
|
|
103
|
-
[ProducesResponseType(204)]
|
|
104
|
-
[ProducesResponseType(404)]
|
|
105
|
-
[ProducesResponseType(400)]
|
|
106
|
-
public async Task<ActionResult> Update(
|
|
107
|
-
Guid id,
|
|
108
|
-
[FromBody] Update{{name}}Request request,
|
|
109
|
-
CancellationToken cancellationToken = default)
|
|
110
|
-
{
|
|
111
|
-
_logger.LogInformation("Updating {{nameCamel}} {Id}", id);
|
|
112
|
-
|
|
113
|
-
// TODO: Implement using service
|
|
114
|
-
// await _{{nameCamel}}Service.UpdateAsync(id, request, cancellationToken);
|
|
115
|
-
|
|
116
|
-
return NoContent();
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/// <summary>
|
|
120
|
-
/// Delete {{nameCamel}}
|
|
121
|
-
/// </summary>
|
|
122
|
-
/// <param name="id">{{name}} ID</param>
|
|
123
|
-
/// <param name="cancellationToken">Cancellation token</param>
|
|
124
|
-
[HttpDelete("{id:guid}")]
|
|
125
|
-
[ProducesResponseType(204)]
|
|
126
|
-
[ProducesResponseType(404)]
|
|
127
|
-
public async Task<ActionResult> Delete(
|
|
128
|
-
Guid id,
|
|
129
|
-
CancellationToken cancellationToken = default)
|
|
130
|
-
{
|
|
131
|
-
_logger.LogInformation("Deleting {{nameCamel}} {Id}", id);
|
|
132
|
-
|
|
133
|
-
// TODO: Implement using service
|
|
134
|
-
// await _{{nameCamel}}Service.DeleteAsync(id, cancellationToken);
|
|
135
|
-
|
|
136
|
-
return NoContent();
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// ============================================================================
|
|
141
|
-
// DTOs
|
|
142
|
-
// ============================================================================
|
|
143
|
-
|
|
144
|
-
/// <summary>
|
|
145
|
-
/// {{name}} data transfer object
|
|
146
|
-
/// </summary>
|
|
147
|
-
public record {{name}}Dto(
|
|
148
|
-
Guid Id,
|
|
149
|
-
DateTime CreatedAt,
|
|
150
|
-
DateTime? UpdatedAt
|
|
151
|
-
// TODO: Add additional properties
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
/// <summary>
|
|
155
|
-
/// Request to create a new {{nameCamel}}
|
|
156
|
-
/// </summary>
|
|
157
|
-
public record Create{{name}}Request(
|
|
158
|
-
// TODO: Add creation properties
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
/// <summary>
|
|
162
|
-
/// Request to update a {{nameCamel}}
|
|
163
|
-
/// </summary>
|
|
164
|
-
public record Update{{name}}Request(
|
|
165
|
-
// TODO: Add update properties
|
|
166
|
-
);
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Threading;
|
|
4
|
+
using System.Threading.Tasks;
|
|
5
|
+
using Microsoft.AspNetCore.Authorization;
|
|
6
|
+
using Microsoft.AspNetCore.Mvc;
|
|
7
|
+
using Microsoft.Extensions.Logging;
|
|
8
|
+
|
|
9
|
+
namespace {{namespace}}.Controllers;
|
|
10
|
+
|
|
11
|
+
/// <summary>
|
|
12
|
+
/// API controller for {{name}} operations
|
|
13
|
+
/// </summary>
|
|
14
|
+
[ApiController]
|
|
15
|
+
[Route("api/[controller]")]
|
|
16
|
+
[Authorize]
|
|
17
|
+
[Produces("application/json")]
|
|
18
|
+
public class {{name}}Controller : ControllerBase
|
|
19
|
+
{
|
|
20
|
+
private readonly ILogger<{{name}}Controller> _logger;
|
|
21
|
+
// private readonly I{{name}}Service _{{nameCamel}}Service;
|
|
22
|
+
|
|
23
|
+
public {{name}}Controller(
|
|
24
|
+
ILogger<{{name}}Controller> logger
|
|
25
|
+
// I{{name}}Service {{nameCamel}}Service
|
|
26
|
+
)
|
|
27
|
+
{
|
|
28
|
+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
29
|
+
// _{{nameCamel}}Service = {{nameCamel}}Service ?? throw new ArgumentNullException(nameof({{nameCamel}}Service));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// <summary>
|
|
33
|
+
/// Get all {{namePlural}}
|
|
34
|
+
/// </summary>
|
|
35
|
+
/// <param name="cancellationToken">Cancellation token</param>
|
|
36
|
+
/// <returns>List of {{namePlural}}</returns>
|
|
37
|
+
[HttpGet]
|
|
38
|
+
[ProducesResponseType(typeof(IEnumerable<{{name}}Dto>), 200)]
|
|
39
|
+
public async Task<ActionResult<IEnumerable<{{name}}Dto>>> GetAll(CancellationToken cancellationToken = default)
|
|
40
|
+
{
|
|
41
|
+
_logger.LogInformation("Getting all {{namePlural}}");
|
|
42
|
+
|
|
43
|
+
// TODO: Implement using service
|
|
44
|
+
// var result = await _{{nameCamel}}Service.GetAllAsync(cancellationToken);
|
|
45
|
+
// return Ok(result);
|
|
46
|
+
|
|
47
|
+
return Ok(Array.Empty<{{name}}Dto>());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// <summary>
|
|
51
|
+
/// Get {{nameCamel}} by ID
|
|
52
|
+
/// </summary>
|
|
53
|
+
/// <param name="id">{{name}} ID</param>
|
|
54
|
+
/// <param name="cancellationToken">Cancellation token</param>
|
|
55
|
+
/// <returns>{{name}} details</returns>
|
|
56
|
+
[HttpGet("{id:guid}")]
|
|
57
|
+
[ProducesResponseType(typeof({{name}}Dto), 200)]
|
|
58
|
+
[ProducesResponseType(404)]
|
|
59
|
+
public async Task<ActionResult<{{name}}Dto>> GetById(
|
|
60
|
+
Guid id,
|
|
61
|
+
CancellationToken cancellationToken = default)
|
|
62
|
+
{
|
|
63
|
+
_logger.LogInformation("Getting {{nameCamel}} {Id}", id);
|
|
64
|
+
|
|
65
|
+
// TODO: Implement using service
|
|
66
|
+
// var result = await _{{nameCamel}}Service.GetByIdAsync(id, cancellationToken);
|
|
67
|
+
// if (result == null) return NotFound();
|
|
68
|
+
// return Ok(result);
|
|
69
|
+
|
|
70
|
+
return NotFound();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// <summary>
|
|
74
|
+
/// Create new {{nameCamel}}
|
|
75
|
+
/// </summary>
|
|
76
|
+
/// <param name="request">Create request</param>
|
|
77
|
+
/// <param name="cancellationToken">Cancellation token</param>
|
|
78
|
+
/// <returns>Created {{nameCamel}}</returns>
|
|
79
|
+
[HttpPost]
|
|
80
|
+
[ProducesResponseType(typeof({{name}}Dto), 201)]
|
|
81
|
+
[ProducesResponseType(400)]
|
|
82
|
+
public async Task<ActionResult<{{name}}Dto>> Create(
|
|
83
|
+
[FromBody] Create{{name}}Request request,
|
|
84
|
+
CancellationToken cancellationToken = default)
|
|
85
|
+
{
|
|
86
|
+
_logger.LogInformation("Creating new {{nameCamel}}");
|
|
87
|
+
|
|
88
|
+
// TODO: Validate and create using service
|
|
89
|
+
// var result = await _{{nameCamel}}Service.CreateAsync(request, cancellationToken);
|
|
90
|
+
// return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
|
91
|
+
|
|
92
|
+
var id = Guid.NewGuid();
|
|
93
|
+
return CreatedAtAction(nameof(GetById), new { id }, null);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// <summary>
|
|
97
|
+
/// Update {{nameCamel}}
|
|
98
|
+
/// </summary>
|
|
99
|
+
/// <param name="id">{{name}} ID</param>
|
|
100
|
+
/// <param name="request">Update request</param>
|
|
101
|
+
/// <param name="cancellationToken">Cancellation token</param>
|
|
102
|
+
[HttpPut("{id:guid}")]
|
|
103
|
+
[ProducesResponseType(204)]
|
|
104
|
+
[ProducesResponseType(404)]
|
|
105
|
+
[ProducesResponseType(400)]
|
|
106
|
+
public async Task<ActionResult> Update(
|
|
107
|
+
Guid id,
|
|
108
|
+
[FromBody] Update{{name}}Request request,
|
|
109
|
+
CancellationToken cancellationToken = default)
|
|
110
|
+
{
|
|
111
|
+
_logger.LogInformation("Updating {{nameCamel}} {Id}", id);
|
|
112
|
+
|
|
113
|
+
// TODO: Implement using service
|
|
114
|
+
// await _{{nameCamel}}Service.UpdateAsync(id, request, cancellationToken);
|
|
115
|
+
|
|
116
|
+
return NoContent();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/// <summary>
|
|
120
|
+
/// Delete {{nameCamel}}
|
|
121
|
+
/// </summary>
|
|
122
|
+
/// <param name="id">{{name}} ID</param>
|
|
123
|
+
/// <param name="cancellationToken">Cancellation token</param>
|
|
124
|
+
[HttpDelete("{id:guid}")]
|
|
125
|
+
[ProducesResponseType(204)]
|
|
126
|
+
[ProducesResponseType(404)]
|
|
127
|
+
public async Task<ActionResult> Delete(
|
|
128
|
+
Guid id,
|
|
129
|
+
CancellationToken cancellationToken = default)
|
|
130
|
+
{
|
|
131
|
+
_logger.LogInformation("Deleting {{nameCamel}} {Id}", id);
|
|
132
|
+
|
|
133
|
+
// TODO: Implement using service
|
|
134
|
+
// await _{{nameCamel}}Service.DeleteAsync(id, cancellationToken);
|
|
135
|
+
|
|
136
|
+
return NoContent();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ============================================================================
|
|
141
|
+
// DTOs
|
|
142
|
+
// ============================================================================
|
|
143
|
+
|
|
144
|
+
/// <summary>
|
|
145
|
+
/// {{name}} data transfer object
|
|
146
|
+
/// </summary>
|
|
147
|
+
public record {{name}}Dto(
|
|
148
|
+
Guid Id,
|
|
149
|
+
DateTime CreatedAt,
|
|
150
|
+
DateTime? UpdatedAt
|
|
151
|
+
// TODO: Add additional properties
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
/// <summary>
|
|
155
|
+
/// Request to create a new {{nameCamel}}
|
|
156
|
+
/// </summary>
|
|
157
|
+
public record Create{{name}}Request(
|
|
158
|
+
// TODO: Add creation properties
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
/// <summary>
|
|
162
|
+
/// Request to update a {{nameCamel}}
|
|
163
|
+
/// </summary>
|
|
164
|
+
public record Update{{name}}Request(
|
|
165
|
+
// TODO: Add update properties
|
|
166
|
+
);
|
|
@@ -1,87 +1,231 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.ComponentModel.DataAnnotations;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
///
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{{#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/// <summary>
|
|
19
|
-
///
|
|
20
|
-
/// </summary>
|
|
21
|
-
public
|
|
22
|
-
|
|
23
|
-
/// <summary>
|
|
24
|
-
///
|
|
25
|
-
/// </summary>
|
|
26
|
-
public
|
|
27
|
-
|
|
28
|
-
{{/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
///
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
///
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
1
|
+
using System;
|
|
2
|
+
using System.ComponentModel.DataAnnotations;
|
|
3
|
+
using SmartStack.Domain.Common;
|
|
4
|
+
using SmartStack.Domain.Common.Interfaces;
|
|
5
|
+
|
|
6
|
+
namespace {{namespace}};
|
|
7
|
+
|
|
8
|
+
/// <summary>
|
|
9
|
+
/// {{name}} entity{{#if baseEntity}} extending {{baseEntity}}{{/if}}
|
|
10
|
+
/// </summary>
|
|
11
|
+
{{#if isSystemEntity}}
|
|
12
|
+
public class {{name}} : SystemEntity
|
|
13
|
+
{{else}}
|
|
14
|
+
public class {{name}} : BaseEntity
|
|
15
|
+
{{/if}}
|
|
16
|
+
{
|
|
17
|
+
{{#if baseEntity}}
|
|
18
|
+
/// <summary>
|
|
19
|
+
/// Foreign key to {{baseEntity}}
|
|
20
|
+
/// </summary>
|
|
21
|
+
public Guid {{baseEntity}}Id { get; private set; }
|
|
22
|
+
|
|
23
|
+
/// <summary>
|
|
24
|
+
/// Navigation property to {{baseEntity}}
|
|
25
|
+
/// </summary>
|
|
26
|
+
public virtual {{baseEntity}}? {{baseEntity}} { get; private set; }
|
|
27
|
+
|
|
28
|
+
{{/if}}
|
|
29
|
+
// === BUSINESS PROPERTIES ===
|
|
30
|
+
// TODO: Add {{name}} specific properties here
|
|
31
|
+
|
|
32
|
+
/// <summary>
|
|
33
|
+
/// Private constructor for EF Core
|
|
34
|
+
/// </summary>
|
|
35
|
+
private {{name}}() { }
|
|
36
|
+
|
|
37
|
+
/// <summary>
|
|
38
|
+
/// Factory method to create a new {{name}}
|
|
39
|
+
/// </summary>
|
|
40
|
+
{{#if isSystemEntity}}
|
|
41
|
+
public static {{name}} Create(
|
|
42
|
+
string code,
|
|
43
|
+
string? createdBy = null)
|
|
44
|
+
{
|
|
45
|
+
return new {{name}}
|
|
46
|
+
{
|
|
47
|
+
Id = Guid.NewGuid(),
|
|
48
|
+
Code = code.ToLowerInvariant(),
|
|
49
|
+
CreatedAt = DateTime.UtcNow,
|
|
50
|
+
CreatedBy = createdBy
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
{{else}}
|
|
54
|
+
public static {{name}} Create(
|
|
55
|
+
Guid tenantId,
|
|
56
|
+
string code,
|
|
57
|
+
string? createdBy = null)
|
|
58
|
+
{
|
|
59
|
+
return new {{name}}
|
|
60
|
+
{
|
|
61
|
+
Id = Guid.NewGuid(),
|
|
62
|
+
TenantId = tenantId,
|
|
63
|
+
Code = code.ToLowerInvariant(),
|
|
64
|
+
CreatedAt = DateTime.UtcNow,
|
|
65
|
+
CreatedBy = createdBy
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
{{/if}}
|
|
69
|
+
|
|
70
|
+
/// <summary>
|
|
71
|
+
/// Update the entity
|
|
72
|
+
/// </summary>
|
|
73
|
+
public void Update(string? updatedBy = null)
|
|
74
|
+
{
|
|
75
|
+
UpdatedAt = DateTime.UtcNow;
|
|
76
|
+
UpdatedBy = updatedBy;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// <summary>
|
|
80
|
+
/// Soft delete the entity
|
|
81
|
+
/// </summary>
|
|
82
|
+
public void SoftDelete(string? deletedBy = null)
|
|
83
|
+
{
|
|
84
|
+
IsDeleted = true;
|
|
85
|
+
DeletedAt = DateTime.UtcNow;
|
|
86
|
+
DeletedBy = deletedBy;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// <summary>
|
|
90
|
+
/// Restore a soft-deleted entity
|
|
91
|
+
/// </summary>
|
|
92
|
+
public void Restore(string? restoredBy = null)
|
|
93
|
+
{
|
|
94
|
+
IsDeleted = false;
|
|
95
|
+
DeletedAt = null;
|
|
96
|
+
DeletedBy = null;
|
|
97
|
+
UpdatedAt = DateTime.UtcNow;
|
|
98
|
+
UpdatedBy = restoredBy;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// Base Entity Classes (SmartStack.Domain.Common)
|
|
104
|
+
// ============================================================================
|
|
105
|
+
/*
|
|
106
|
+
/// <summary>
|
|
107
|
+
/// Base entity for tenant-scoped entities (default)
|
|
108
|
+
/// </summary>
|
|
109
|
+
public abstract class BaseEntity : ITenantEntity, IHasCode, ISoftDeletable, IVersioned
|
|
110
|
+
{
|
|
111
|
+
public Guid Id { get; set; } = Guid.NewGuid();
|
|
112
|
+
public Guid TenantId { get; set; }
|
|
113
|
+
|
|
114
|
+
private string _code = string.Empty;
|
|
115
|
+
public string Code
|
|
116
|
+
{
|
|
117
|
+
get => _code;
|
|
118
|
+
set => _code = value?.ToLowerInvariant() ?? string.Empty;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
122
|
+
public DateTime? UpdatedAt { get; set; }
|
|
123
|
+
public string? CreatedBy { get; set; }
|
|
124
|
+
public string? UpdatedBy { get; set; }
|
|
125
|
+
|
|
126
|
+
public bool IsDeleted { get; set; }
|
|
127
|
+
public DateTime? DeletedAt { get; set; }
|
|
128
|
+
public string? DeletedBy { get; set; }
|
|
129
|
+
|
|
130
|
+
public byte[] RowVersion { get; set; } = Array.Empty<byte>();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/// <summary>
|
|
134
|
+
/// Base entity for system-wide entities (no tenant isolation)
|
|
135
|
+
/// </summary>
|
|
136
|
+
public abstract class SystemEntity : ISystemEntity, IHasCode, ISoftDeletable, IVersioned
|
|
137
|
+
{
|
|
138
|
+
public Guid Id { get; set; } = Guid.NewGuid();
|
|
139
|
+
|
|
140
|
+
private string _code = string.Empty;
|
|
141
|
+
public string Code
|
|
142
|
+
{
|
|
143
|
+
get => _code;
|
|
144
|
+
set => _code = value?.ToLowerInvariant() ?? string.Empty;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
148
|
+
public DateTime? UpdatedAt { get; set; }
|
|
149
|
+
public string? CreatedBy { get; set; }
|
|
150
|
+
public string? UpdatedBy { get; set; }
|
|
151
|
+
|
|
152
|
+
public bool IsDeleted { get; set; }
|
|
153
|
+
public DateTime? DeletedAt { get; set; }
|
|
154
|
+
public string? DeletedBy { get; set; }
|
|
155
|
+
|
|
156
|
+
public byte[] RowVersion { get; set; } = Array.Empty<byte>();
|
|
157
|
+
}
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// EF Core Configuration
|
|
162
|
+
// ============================================================================
|
|
163
|
+
namespace {{infrastructureNamespace}}.Persistence.Configurations;
|
|
164
|
+
|
|
165
|
+
using Microsoft.EntityFrameworkCore;
|
|
166
|
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
167
|
+
using {{domainNamespace}};
|
|
168
|
+
|
|
169
|
+
public class {{name}}Configuration : IEntityTypeConfiguration<{{name}}>
|
|
170
|
+
{
|
|
171
|
+
public void Configure(EntityTypeBuilder<{{name}}> builder)
|
|
172
|
+
{
|
|
173
|
+
// Table name with schema and domain prefix
|
|
174
|
+
builder.ToTable("{{tablePrefix}}{{name}}s", "{{schema}}");
|
|
175
|
+
|
|
176
|
+
// Primary key
|
|
177
|
+
builder.HasKey(e => e.Id);
|
|
178
|
+
|
|
179
|
+
{{#unless isSystemEntity}}
|
|
180
|
+
// Multi-tenant
|
|
181
|
+
builder.Property(e => e.TenantId).IsRequired();
|
|
182
|
+
builder.HasIndex(e => e.TenantId);
|
|
183
|
+
|
|
184
|
+
// Code: lowercase, unique per tenant (filtered for soft delete)
|
|
185
|
+
builder.Property(e => e.Code).HasMaxLength(100).IsRequired();
|
|
186
|
+
builder.HasIndex(e => new { e.TenantId, e.Code })
|
|
187
|
+
.IsUnique()
|
|
188
|
+
.HasFilter("[IsDeleted] = 0")
|
|
189
|
+
.HasDatabaseName("IX_{{tablePrefix}}{{name}}s_Tenant_Code_Unique");
|
|
190
|
+
{{else}}
|
|
191
|
+
// Code: lowercase, unique (filtered for soft delete)
|
|
192
|
+
builder.Property(e => e.Code).HasMaxLength(100).IsRequired();
|
|
193
|
+
builder.HasIndex(e => e.Code)
|
|
194
|
+
.IsUnique()
|
|
195
|
+
.HasFilter("[IsDeleted] = 0")
|
|
196
|
+
.HasDatabaseName("IX_{{tablePrefix}}{{name}}s_Code_Unique");
|
|
197
|
+
{{/unless}}
|
|
198
|
+
|
|
199
|
+
// Concurrency token
|
|
200
|
+
builder.Property(e => e.RowVersion).IsRowVersion();
|
|
201
|
+
|
|
202
|
+
// Audit fields
|
|
203
|
+
builder.Property(e => e.CreatedBy).HasMaxLength(256);
|
|
204
|
+
builder.Property(e => e.UpdatedBy).HasMaxLength(256);
|
|
205
|
+
builder.Property(e => e.DeletedBy).HasMaxLength(256);
|
|
206
|
+
|
|
207
|
+
{{#if baseEntity}}
|
|
208
|
+
// Relationship to {{baseEntity}} (1:1)
|
|
209
|
+
builder.HasOne(e => e.{{baseEntity}})
|
|
210
|
+
.WithOne()
|
|
211
|
+
.HasForeignKey<{{name}}>(e => e.{{baseEntity}}Id)
|
|
212
|
+
.OnDelete(DeleteBehavior.Cascade);
|
|
213
|
+
|
|
214
|
+
// Index on foreign key
|
|
215
|
+
builder.HasIndex(e => e.{{baseEntity}}Id)
|
|
216
|
+
.IsUnique();
|
|
217
|
+
{{/if}}
|
|
218
|
+
|
|
219
|
+
// TODO: Add additional configuration
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ============================================================================
|
|
224
|
+
// DbContext Update (add to ApplicationDbContext.cs)
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// public DbSet<{{name}}> {{name}}s => Set<{{name}}>();
|
|
227
|
+
|
|
228
|
+
// ============================================================================
|
|
229
|
+
// Migration Command
|
|
230
|
+
// ============================================================================
|
|
231
|
+
// dotnet ef migrations add core_vX.X.X_XXX_Add{{name}} --context ApplicationDbContext
|