eva4j 1.0.9 → 1.0.11
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/AGENTS.md +87 -6
- package/DOMAIN_YAML_GUIDE.md +393 -0
- package/FUTURE_FEATURES.md +968 -556
- package/README.md +3 -3
- package/bin/eva4j.js +1 -0
- package/examples/domain-field-visibility.yaml +235 -0
- package/examples/domain-multiple-relations.yaml +4 -4
- package/examples/domain-one-to-many.yaml +1 -1
- package/examples/domain-one-to-one.yaml +6 -3
- package/examples/domain-secondary-onetomany.yaml +106 -0
- package/examples/domain-secondary-onetoone.yaml +98 -0
- package/examples/domain-transitions.yaml +60 -0
- package/package.json +4 -3
- package/prettier.config.js +9 -0
- package/src/commands/detach.js +57 -0
- package/src/commands/generate-entities.js +258 -57
- package/src/commands/generate-kafka-event.js +7 -4
- package/src/commands/generate-resource.js +22 -25
- package/src/commands/generate-usecase.js +17 -41
- package/src/generators/base-generator.js +2 -1
- package/src/generators/shared-generator.js +20 -2
- package/src/utils/checksum-manager.js +130 -0
- package/src/utils/template-engine.js +63 -5
- package/src/utils/yaml-to-entity.js +284 -17
- package/templates/aggregate/AggregateMapper.java.ejs +52 -10
- package/templates/aggregate/AggregateRoot.java.ejs +75 -5
- package/templates/aggregate/DomainEntity.java.ejs +101 -4
- package/templates/aggregate/Enum.java.ejs +49 -1
- package/templates/aggregate/JpaEntity.java.ejs +10 -2
- package/templates/base/application/Application.java.ejs +1 -1
- package/templates/base/root/gitignore.ejs +3 -0
- package/templates/crud/ApplicationMapper.java.ejs +156 -9
- package/templates/crud/CreateCommand.java.ejs +7 -0
- package/templates/crud/CreateCommandHandler.java.ejs +55 -3
- package/templates/crud/CreateItemDto.java.ejs +10 -2
- package/templates/crud/CreateValueObjectDto.java.ejs +18 -0
- package/templates/crud/SecondaryEntityDto.java.ejs +7 -2
- package/templates/kafka-event/KafkaMessageBroker.java.ejs +3 -3
- package/templates/postman/Collection.json.ejs +95 -34
- package/templates/shared/customExceptions/BusinessException.java.ejs +11 -0
- package/templates/shared/customExceptions/InvalidStateTransitionException.java.ejs +11 -0
- package/templates/shared/handlerException/HandlerExceptions.java.ejs +16 -0
package/AGENTS.md
CHANGED
|
@@ -543,6 +543,79 @@ public record UserResponseDto(
|
|
|
543
543
|
| Instant | Instant | Timestamp UTC |
|
|
544
544
|
| UUID | UUID | Identificador único |
|
|
545
545
|
|
|
546
|
+
### Propiedades de Campo
|
|
547
|
+
|
|
548
|
+
Los campos en domain.yaml soportan las siguientes propiedades:
|
|
549
|
+
|
|
550
|
+
| Propiedad | Tipo | Default | Descripción |
|
|
551
|
+
|-----------|------|---------|-------------|
|
|
552
|
+
| `name` | String | - | Nombre del campo (obligatorio) |
|
|
553
|
+
| `type` | String | - | Tipo de dato Java (obligatorio) |
|
|
554
|
+
| `annotations` | Array | `[]` | Anotaciones JPA personalizadas |
|
|
555
|
+
| `isValueObject` | Boolean | `false` | Marca explícita de Value Object |
|
|
556
|
+
| `isEmbedded` | Boolean | `false` | Marca explícita de @Embedded |
|
|
557
|
+
| `enumValues` | Array | `[]` | Valores inline de enum |
|
|
558
|
+
| **`readOnly`** | Boolean | `false` | **Excluye del constructor de negocio y CreateDto** |
|
|
559
|
+
| **`hidden`** | Boolean | `false` | **Excluye del ResponseDto** |
|
|
560
|
+
| **`validations`** | Array | `[]` | **Anotaciones JSR-303 en el Command y CreateDto** |
|
|
561
|
+
|
|
562
|
+
#### Flags de Visibilidad: `readOnly` y `hidden`
|
|
563
|
+
|
|
564
|
+
**`readOnly: true`** - Campos calculados/derivados
|
|
565
|
+
- ❌ Excluido de: Constructor de negocio, CreateDto
|
|
566
|
+
- ✅ Incluido en: Constructor completo, ResponseDto
|
|
567
|
+
- **Uso:** Totales calculados, contadores, campos derivados
|
|
568
|
+
|
|
569
|
+
```yaml
|
|
570
|
+
fields:
|
|
571
|
+
- name: totalAmount
|
|
572
|
+
type: BigDecimal
|
|
573
|
+
readOnly: true # Calculado de la suma de items
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**`hidden: true`** - Campos sensibles/internos
|
|
577
|
+
- ❌ Excluido de: ResponseDto
|
|
578
|
+
- ✅ Incluido en: Constructor de negocio, CreateDto
|
|
579
|
+
- **Uso:** Passwords, tokens, secrets, información sensible
|
|
580
|
+
|
|
581
|
+
```yaml
|
|
582
|
+
fields:
|
|
583
|
+
- name: passwordHash
|
|
584
|
+
type: String
|
|
585
|
+
hidden: true # No exponer en API
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
**Matriz de comportamiento:**
|
|
589
|
+
|
|
590
|
+
| Campo | Constructor Negocio | CreateDto | ResponseDto |
|
|
591
|
+
|-------|---------------------|-----------|-------------|
|
|
592
|
+
| Normal | ✅ | ✅ | ✅ |
|
|
593
|
+
| `readOnly: true` | ❌ | ❌ | ✅ |
|
|
594
|
+
| `hidden: true` | ✅ | ✅ | ❌ |
|
|
595
|
+
| Ambos flags | ❌ | ❌ | ❌ |
|
|
596
|
+
|
|
597
|
+
**Ejemplo práctico:**
|
|
598
|
+
```yaml
|
|
599
|
+
entities:
|
|
600
|
+
- name: order
|
|
601
|
+
fields:
|
|
602
|
+
- name: orderNumber
|
|
603
|
+
type: String # ✅ Normal - en todos lados
|
|
604
|
+
|
|
605
|
+
- name: totalAmount
|
|
606
|
+
type: BigDecimal
|
|
607
|
+
readOnly: true # ⚙️ Calculado - no en constructor
|
|
608
|
+
|
|
609
|
+
- name: processingToken
|
|
610
|
+
type: String
|
|
611
|
+
hidden: true # 🔒 Sensible - no en respuesta
|
|
612
|
+
|
|
613
|
+
- name: internalFlag
|
|
614
|
+
type: Boolean
|
|
615
|
+
readOnly: true # 🔐 Calculado Y sensible
|
|
616
|
+
hidden: true
|
|
617
|
+
```
|
|
618
|
+
|
|
546
619
|
### Tipos de Relaciones
|
|
547
620
|
|
|
548
621
|
- `OneToOne` - Relación uno a uno
|
|
@@ -572,15 +645,18 @@ public record UserResponseDto(
|
|
|
572
645
|
### Al Generar Mappers
|
|
573
646
|
|
|
574
647
|
1. **NUNCA** mapear campos de auditoría (createdAt, updatedAt, createdBy, updatedBy)
|
|
575
|
-
2. **
|
|
576
|
-
3. **
|
|
648
|
+
2. **NUNCA** mapear campos readOnly en métodos de creación (fromCommand, fromDto)
|
|
649
|
+
3. **NUNCA** mapear campos hidden en métodos de respuesta (toDto, toResponseDto)
|
|
650
|
+
4. **SIEMPRE** filtrar campos antes de usar `.builder()`
|
|
651
|
+
5. **SIEMPRE** mapear bidireccionalidad en relaciones
|
|
577
652
|
|
|
578
653
|
### Al Generar DTOs
|
|
579
654
|
|
|
580
655
|
1. **NUNCA** exponer `createdBy` y `updatedBy` en respuestas
|
|
581
|
-
2. **
|
|
582
|
-
3. **
|
|
583
|
-
4. **SIEMPRE**
|
|
656
|
+
2. **NUNCA** incluir campos `readOnly` en CreateDto
|
|
657
|
+
3. **NUNCA** incluir campos `hidden` en ResponseDto
|
|
658
|
+
4. **SIEMPRE** usar Java Records para DTOs
|
|
659
|
+
5. **SIEMPRE** filtrar campos según flags de visibilidad
|
|
584
660
|
|
|
585
661
|
---
|
|
586
662
|
|
|
@@ -677,13 +753,18 @@ Al generar o modificar código, verificar:
|
|
|
677
753
|
- [ ] Métodos de negocio con **validaciones explícitas**
|
|
678
754
|
- [ ] Entidades JPA con **Lombok y herencia correcta**
|
|
679
755
|
- [ ] Mappers **excluyen campos de auditoría**
|
|
756
|
+
- [ ] Mappers **excluyen campos readOnly en creación**
|
|
757
|
+
- [ ] Mappers **excluyen campos hidden en respuestas**
|
|
680
758
|
- [ ] DTOs de respuesta **sin createdBy/updatedBy**
|
|
759
|
+
- [ ] DTOs de respuesta **sin campos hidden**
|
|
760
|
+
- [ ] DTOs de creación **sin campos readOnly**
|
|
681
761
|
- [ ] Relaciones bidireccionales con métodos `assign*()`
|
|
682
762
|
- [ ] Value Objects **inmutables**
|
|
683
763
|
- [ ] Configuración de auditoría cuando `trackUser: true`
|
|
764
|
+
- [ ] Validaciones JSR-303 **solo en Command y CreateDto, nunca en dominio**
|
|
684
765
|
|
|
685
766
|
---
|
|
686
767
|
|
|
687
|
-
**Última actualización:** 2026-02-
|
|
768
|
+
**Última actualización:** 2026-02-21
|
|
688
769
|
**Versión de eva4j:** 1.x
|
|
689
770
|
**Estado:** Documento de referencia para agentes IA
|
package/DOMAIN_YAML_GUIDE.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- [Entidades](#entidades)
|
|
11
11
|
- [Value Objects](#value-objects)
|
|
12
12
|
- [Enums](#enums)
|
|
13
|
+
- [Validaciones JSR-303](#validaciones-jsr-303)
|
|
13
14
|
- [Relaciones](#relaciones)
|
|
14
15
|
- [Tipos de Datos](#tipos-de-datos)
|
|
15
16
|
- [Ejemplos Completos](#ejemplos-completos)
|
|
@@ -396,6 +397,398 @@ fields:
|
|
|
396
397
|
|
|
397
398
|
---
|
|
398
399
|
|
|
400
|
+
### Control de Visibilidad de Campos
|
|
401
|
+
|
|
402
|
+
Eva4j permite controlar qué campos participan en constructores, DTOs de creación y DTOs de respuesta mediante dos flags opcionales: **`readOnly`** y **`hidden`**.
|
|
403
|
+
|
|
404
|
+
#### 📋 Matriz de Comportamiento
|
|
405
|
+
|
|
406
|
+
| Campo | Constructor Negocio | Constructor Completo | CreateDto | ResponseDto |
|
|
407
|
+
|-------|---------------------|----------------------|-----------|-------------|
|
|
408
|
+
| **Normal** | ✅ Incluido | ✅ Incluido | ✅ Incluido | ✅ Incluido |
|
|
409
|
+
| **`readOnly: true`** | ❌ Excluido | ✅ Incluido | ❌ Excluido | ✅ Incluido |
|
|
410
|
+
| **`hidden: true`** | ✅ Incluido | ✅ Incluido | ✅ Incluido | ❌ Excluido |
|
|
411
|
+
| **Ambos flags** | ❌ Excluido | ✅ Incluido | ❌ Excluido | ❌ Excluido |
|
|
412
|
+
|
|
413
|
+
#### 🔒 `readOnly: true` - Campos Calculados/Derivados
|
|
414
|
+
|
|
415
|
+
Marca campos que **se calculan internamente** y no deben pasarse como parámetros en constructores o DTOs de creación.
|
|
416
|
+
|
|
417
|
+
**Casos de uso típicos:**
|
|
418
|
+
- Totales calculados (suma de items)
|
|
419
|
+
- Contadores automáticos
|
|
420
|
+
- Campos derivados de otros datos
|
|
421
|
+
- Timestamps calculados
|
|
422
|
+
|
|
423
|
+
**Sintaxis:**
|
|
424
|
+
```yaml
|
|
425
|
+
fields:
|
|
426
|
+
- name: totalAmount
|
|
427
|
+
type: BigDecimal
|
|
428
|
+
readOnly: true # ✅ No en constructor ni CreateDto
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Ejemplo completo:**
|
|
432
|
+
```yaml
|
|
433
|
+
entities:
|
|
434
|
+
- name: order
|
|
435
|
+
isRoot: true
|
|
436
|
+
tableName: orders
|
|
437
|
+
audit:
|
|
438
|
+
enabled: true
|
|
439
|
+
fields:
|
|
440
|
+
- name: id
|
|
441
|
+
type: String
|
|
442
|
+
- name: orderNumber
|
|
443
|
+
type: String
|
|
444
|
+
- name: customerId
|
|
445
|
+
type: String
|
|
446
|
+
# Campo readOnly - calculado de los items
|
|
447
|
+
- name: totalAmount
|
|
448
|
+
type: BigDecimal
|
|
449
|
+
readOnly: true
|
|
450
|
+
# Campo readOnly - contador de items
|
|
451
|
+
- name: itemCount
|
|
452
|
+
type: Integer
|
|
453
|
+
readOnly: true
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Código generado:**
|
|
457
|
+
```java
|
|
458
|
+
// Constructor de negocio - SIN fields readOnly
|
|
459
|
+
public Order(String orderNumber, String customerId) {
|
|
460
|
+
this.orderNumber = orderNumber;
|
|
461
|
+
this.customerId = customerId;
|
|
462
|
+
// totalAmount e itemCount NO están aquí
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Constructor completo - CON fields readOnly (reconstrucción desde DB)
|
|
466
|
+
public Order(String id, String orderNumber, String customerId,
|
|
467
|
+
BigDecimal totalAmount, Integer itemCount,
|
|
468
|
+
LocalDateTime createdAt, LocalDateTime updatedAt) {
|
|
469
|
+
// Todos los campos incluidos
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// CreateDto - SIN fields readOnly
|
|
473
|
+
public record CreateOrderDto(
|
|
474
|
+
String orderNumber,
|
|
475
|
+
String customerId
|
|
476
|
+
// totalAmount e itemCount NO están aquí
|
|
477
|
+
) {}
|
|
478
|
+
|
|
479
|
+
// ResponseDto - CON fields readOnly (mostrar valores calculados)
|
|
480
|
+
public record OrderResponseDto(
|
|
481
|
+
String id,
|
|
482
|
+
String orderNumber,
|
|
483
|
+
String customerId,
|
|
484
|
+
BigDecimal totalAmount, // ✅ Incluido
|
|
485
|
+
Integer itemCount, // ✅ Incluido
|
|
486
|
+
LocalDateTime createdAt,
|
|
487
|
+
LocalDateTime updatedAt
|
|
488
|
+
) {}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
#### 🙈 `hidden: true` - Campos Sensibles/Internos
|
|
492
|
+
|
|
493
|
+
Marca campos que **NO deben exponerse** en respuestas de API pero sí pueden recibirse en creación.
|
|
494
|
+
|
|
495
|
+
**Casos de uso típicos:**
|
|
496
|
+
- Passwords/hashes de seguridad
|
|
497
|
+
- Tokens internos
|
|
498
|
+
- Secrets y claves de API
|
|
499
|
+
- Información sensible (SSN, datos privados)
|
|
500
|
+
- Flags de control interno
|
|
501
|
+
|
|
502
|
+
**Sintaxis:**
|
|
503
|
+
```yaml
|
|
504
|
+
fields:
|
|
505
|
+
- name: passwordHash
|
|
506
|
+
type: String
|
|
507
|
+
hidden: true # ✅ No en ResponseDto
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Ejemplo completo:**
|
|
511
|
+
```yaml
|
|
512
|
+
entities:
|
|
513
|
+
- name: user
|
|
514
|
+
isRoot: true
|
|
515
|
+
tableName: users
|
|
516
|
+
audit:
|
|
517
|
+
enabled: true
|
|
518
|
+
trackUser: true
|
|
519
|
+
fields:
|
|
520
|
+
- name: id
|
|
521
|
+
type: String
|
|
522
|
+
- name: username
|
|
523
|
+
type: String
|
|
524
|
+
- name: email
|
|
525
|
+
type: String
|
|
526
|
+
# Campo hidden - NO en ResponseDto
|
|
527
|
+
- name: passwordHash
|
|
528
|
+
type: String
|
|
529
|
+
hidden: true
|
|
530
|
+
# Campo hidden - token interno
|
|
531
|
+
- name: resetPasswordToken
|
|
532
|
+
type: String
|
|
533
|
+
hidden: true
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
**Código generado:**
|
|
537
|
+
```java
|
|
538
|
+
// Constructor de negocio - CON fields hidden
|
|
539
|
+
public User(String username, String email,
|
|
540
|
+
String passwordHash, String resetPasswordToken) {
|
|
541
|
+
this.username = username;
|
|
542
|
+
this.email = email;
|
|
543
|
+
this.passwordHash = passwordHash;
|
|
544
|
+
this.resetPasswordToken = resetPasswordToken;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// CreateDto - CON fields hidden (para recibirlos en creación)
|
|
548
|
+
public record CreateUserDto(
|
|
549
|
+
String username,
|
|
550
|
+
String email,
|
|
551
|
+
String passwordHash, // ✅ Se puede recibir
|
|
552
|
+
String resetPasswordToken // ✅ Se puede recibir
|
|
553
|
+
) {}
|
|
554
|
+
|
|
555
|
+
// ResponseDto - SIN fields hidden (proteger datos sensibles)
|
|
556
|
+
public record UserResponseDto(
|
|
557
|
+
String id,
|
|
558
|
+
String username,
|
|
559
|
+
String email,
|
|
560
|
+
LocalDateTime createdAt,
|
|
561
|
+
LocalDateTime updatedAt
|
|
562
|
+
// passwordHash y resetPasswordToken NO están aquí
|
|
563
|
+
) {}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
#### 🔐 Combinando Ambos Flags
|
|
567
|
+
|
|
568
|
+
Puedes combinar `readOnly` y `hidden` para campos que son **calculados internamente Y sensibles**.
|
|
569
|
+
|
|
570
|
+
**Ejemplo:**
|
|
571
|
+
```yaml
|
|
572
|
+
fields:
|
|
573
|
+
- name: isLocked
|
|
574
|
+
type: Boolean
|
|
575
|
+
readOnly: true # Calculado internamente
|
|
576
|
+
hidden: true # NO exponer en API
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
**Resultado:**
|
|
580
|
+
- ❌ NO en constructor de negocio (es readOnly)
|
|
581
|
+
- ❌ NO en CreateDto (es readOnly)
|
|
582
|
+
- ❌ NO en ResponseDto (es hidden)
|
|
583
|
+
- ✅ SÍ en constructor completo (para reconstrucción desde DB)
|
|
584
|
+
|
|
585
|
+
#### 📘 Ejemplo Completo: Sistema de Órdenes
|
|
586
|
+
|
|
587
|
+
```yaml
|
|
588
|
+
aggregates:
|
|
589
|
+
- name: Order
|
|
590
|
+
entities:
|
|
591
|
+
- name: order
|
|
592
|
+
isRoot: true
|
|
593
|
+
tableName: orders
|
|
594
|
+
audit:
|
|
595
|
+
enabled: true
|
|
596
|
+
trackUser: true
|
|
597
|
+
fields:
|
|
598
|
+
- name: id
|
|
599
|
+
type: String
|
|
600
|
+
|
|
601
|
+
# Campos normales
|
|
602
|
+
- name: orderNumber
|
|
603
|
+
type: String
|
|
604
|
+
- name: customerId
|
|
605
|
+
type: String
|
|
606
|
+
- name: status
|
|
607
|
+
type: String
|
|
608
|
+
|
|
609
|
+
# Campos readOnly (calculados)
|
|
610
|
+
- name: totalAmount
|
|
611
|
+
type: BigDecimal
|
|
612
|
+
readOnly: true # Suma de items
|
|
613
|
+
- name: itemCount
|
|
614
|
+
type: Integer
|
|
615
|
+
readOnly: true # Cuenta de items
|
|
616
|
+
|
|
617
|
+
# Campo hidden (interno)
|
|
618
|
+
- name: processingToken
|
|
619
|
+
type: String
|
|
620
|
+
hidden: true # Token de procesamiento interno
|
|
621
|
+
|
|
622
|
+
# Campo readOnly + hidden (calculado e interno)
|
|
623
|
+
- name: riskScore
|
|
624
|
+
type: Integer
|
|
625
|
+
readOnly: true
|
|
626
|
+
hidden: true # Puntaje de riesgo interno
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
**Constructor de negocio generado:**
|
|
630
|
+
```java
|
|
631
|
+
public Order(String orderNumber, String customerId,
|
|
632
|
+
String status, String processingToken) {
|
|
633
|
+
// totalAmount, itemCount, riskScore NO están (readOnly)
|
|
634
|
+
// processingToken SÍ está (solo hidden, no readOnly)
|
|
635
|
+
}
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**CreateOrderDto generado:**
|
|
639
|
+
```java
|
|
640
|
+
public record CreateOrderDto(
|
|
641
|
+
String orderNumber,
|
|
642
|
+
String customerId,
|
|
643
|
+
String status,
|
|
644
|
+
String processingToken // ✅ hidden pero SÍ en create
|
|
645
|
+
// totalAmount, itemCount, riskScore NO están (readOnly)
|
|
646
|
+
) {}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
**OrderResponseDto generado:**
|
|
650
|
+
```java
|
|
651
|
+
public record OrderResponseDto(
|
|
652
|
+
String id,
|
|
653
|
+
String orderNumber,
|
|
654
|
+
String customerId,
|
|
655
|
+
String status,
|
|
656
|
+
BigDecimal totalAmount, // ✅ readOnly pero SÍ en response
|
|
657
|
+
Integer itemCount, // ✅ readOnly pero SÍ en response
|
|
658
|
+
LocalDateTime createdAt,
|
|
659
|
+
LocalDateTime updatedAt
|
|
660
|
+
// processingToken NO está (hidden)
|
|
661
|
+
// riskScore NO está (hidden)
|
|
662
|
+
) {}
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
#### ⚡ Comportamiento por Defecto
|
|
666
|
+
|
|
667
|
+
Si no especificas `readOnly` ni `hidden`:
|
|
668
|
+
- ✅ El comportamiento actual se mantiene sin cambios
|
|
669
|
+
- ✅ Campos normales aparecen en todos lados
|
|
670
|
+
- ✅ Solo los campos de auditoría (`createdBy`, `updatedBy`) se excluyen automáticamente de ResponseDto
|
|
671
|
+
|
|
672
|
+
```yaml
|
|
673
|
+
# Sin flags - comportamiento estándar
|
|
674
|
+
fields:
|
|
675
|
+
- name: productName
|
|
676
|
+
type: String # ✅ En constructor, CreateDto Y ResponseDto
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
#### 📚 Ver También
|
|
680
|
+
|
|
681
|
+
- **Ejemplo completo:** [examples/domain-field-visibility.yaml](../examples/domain-field-visibility.yaml)
|
|
682
|
+
- **Campos de auditoría:** Los campos `createdAt`, `updatedAt`, `createdBy`, `updatedBy` siguen su propio comportamiento especial definido en la sección de Auditoría
|
|
683
|
+
|
|
684
|
+
---
|
|
685
|
+
|
|
686
|
+
### Validaciones JSR-303
|
|
687
|
+
|
|
688
|
+
Eva4j soporta anotaciones Bean Validation (JSR-303/Jakarta Validation) en campos del `domain.yaml`. Las validaciones se generan **únicamente en la capa de aplicación**: en el `Create<Aggregate>Command` y en los `Create<Entity>Dto` de entidades secundarias. **No se aplican a entidades de dominio** ni a campos con `readOnly: true`.
|
|
689
|
+
|
|
690
|
+
El import `jakarta.validation.constraints.*` se agrega automáticamente cuando se detecta al menos una validación en los campos del comando.
|
|
691
|
+
|
|
692
|
+
#### Sintaxis
|
|
693
|
+
|
|
694
|
+
```yaml
|
|
695
|
+
fields:
|
|
696
|
+
- name: email
|
|
697
|
+
type: String
|
|
698
|
+
validations:
|
|
699
|
+
- type: NotBlank
|
|
700
|
+
message: "Email es requerido"
|
|
701
|
+
- type: Email
|
|
702
|
+
message: "Email inválido"
|
|
703
|
+
|
|
704
|
+
- name: age
|
|
705
|
+
type: Integer
|
|
706
|
+
validations:
|
|
707
|
+
- type: Min
|
|
708
|
+
value: 18
|
|
709
|
+
message: "Edad mínima 18 años"
|
|
710
|
+
- type: Max
|
|
711
|
+
value: 120
|
|
712
|
+
|
|
713
|
+
- name: username
|
|
714
|
+
type: String
|
|
715
|
+
validations:
|
|
716
|
+
- type: Size
|
|
717
|
+
min: 3
|
|
718
|
+
max: 50
|
|
719
|
+
message: "Username entre 3 y 50 caracteres"
|
|
720
|
+
|
|
721
|
+
- name: code
|
|
722
|
+
type: String
|
|
723
|
+
validations:
|
|
724
|
+
- type: Pattern
|
|
725
|
+
regexp: "^[A-Z]{3}-[0-9]{4}$"
|
|
726
|
+
message: "Formato inválido"
|
|
727
|
+
|
|
728
|
+
- name: price
|
|
729
|
+
type: BigDecimal
|
|
730
|
+
validations:
|
|
731
|
+
- type: Digits
|
|
732
|
+
integer: 10
|
|
733
|
+
fraction: 2
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
#### Propiedades por Tipo
|
|
737
|
+
|
|
738
|
+
| Propiedad | Tipos que la usan | Descripción |
|
|
739
|
+
|-----------|-------------------|-------------|
|
|
740
|
+
| `type` | Todos | Nombre de la anotación (`NotNull`, `NotBlank`, `Email`, `Min`, `Max`, `Size`, `Pattern`, `Digits`, `Positive`, `Negative`, `Past`, `Future`, etc.) |
|
|
741
|
+
| `message` | Todos (opcional) | Mensaje de error personalizado |
|
|
742
|
+
| `value` | `Min`, `Max` | Valor límite numérico |
|
|
743
|
+
| `min` | `Size` | Tamaño mínimo |
|
|
744
|
+
| `max` | `Size` | Tamaño máximo |
|
|
745
|
+
| `regexp` | `Pattern` | Expresión regular |
|
|
746
|
+
| `integer` | `Digits` | Máximo de dígitos enteros |
|
|
747
|
+
| `fraction` | `Digits` | Máximo de dígitos decimales |
|
|
748
|
+
| `inclusive` | `DecimalMin`, `DecimalMax` | Si el límite es inclusivo |
|
|
749
|
+
|
|
750
|
+
#### Anotaciones sin parámetros (solo `type` requerido)
|
|
751
|
+
|
|
752
|
+
`NotNull`, `NotBlank`, `NotEmpty`, `Email`, `Positive`, `PositiveOrZero`, `Negative`, `NegativeOrZero`, `Past`, `PastOrPresent`, `Future`, `FutureOrPresent`, `AssertTrue`, `AssertFalse`
|
|
753
|
+
|
|
754
|
+
#### Código generado
|
|
755
|
+
|
|
756
|
+
Para un campo con validaciones:
|
|
757
|
+
|
|
758
|
+
```yaml
|
|
759
|
+
- name: email
|
|
760
|
+
type: String
|
|
761
|
+
validations:
|
|
762
|
+
- type: Email
|
|
763
|
+
message: "Email inválido"
|
|
764
|
+
- type: NotBlank
|
|
765
|
+
message: "Email es requerido"
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
Se genera en `CreateUserCommand.java`:
|
|
769
|
+
|
|
770
|
+
```java
|
|
771
|
+
import jakarta.validation.constraints.*;
|
|
772
|
+
|
|
773
|
+
public record CreateUserCommand(
|
|
774
|
+
@Email(message = "Email inválido")
|
|
775
|
+
@NotBlank(message = "Email es requerido")
|
|
776
|
+
String email,
|
|
777
|
+
...
|
|
778
|
+
) implements Command {
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
#### Reglas de aplicación
|
|
783
|
+
|
|
784
|
+
- ✅ **Sí** se aplican en `Create<Aggregate>Command`
|
|
785
|
+
- ✅ **Sí** se aplican en `Create<Entity>Dto` (entidades secundarias)
|
|
786
|
+
- ❌ **No** se aplican a entidades de dominio (`Order.java`, etc.)
|
|
787
|
+
- ❌ **No** se aplican a campos con `readOnly: true` (ya están excluidos del command)
|
|
788
|
+
- ❌ **No** se aplican a campos con `hidden: true` si también son `readOnly: true`
|
|
789
|
+
|
|
790
|
+
---
|
|
791
|
+
|
|
399
792
|
### Auditoría Automática
|
|
400
793
|
|
|
401
794
|
eva4j soporta dos niveles de auditoría automática de entidades:
|