maestro-bundle 1.0.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.
Files changed (60) hide show
  1. package/README.md +91 -0
  2. package/package.json +25 -0
  3. package/src/cli.mjs +212 -0
  4. package/templates/bundle-ai-agents/.spec/constitution.md +33 -0
  5. package/templates/bundle-ai-agents/AGENTS.md +140 -0
  6. package/templates/bundle-ai-agents/skills/agent-orchestration/SKILL.md +132 -0
  7. package/templates/bundle-ai-agents/skills/api-design/SKILL.md +100 -0
  8. package/templates/bundle-ai-agents/skills/clean-architecture/SKILL.md +99 -0
  9. package/templates/bundle-ai-agents/skills/context-engineering/SKILL.md +98 -0
  10. package/templates/bundle-ai-agents/skills/database-modeling/SKILL.md +59 -0
  11. package/templates/bundle-ai-agents/skills/docker-containerization/SKILL.md +114 -0
  12. package/templates/bundle-ai-agents/skills/eval-testing/SKILL.md +115 -0
  13. package/templates/bundle-ai-agents/skills/memory-management/SKILL.md +106 -0
  14. package/templates/bundle-ai-agents/skills/prompt-engineering/SKILL.md +66 -0
  15. package/templates/bundle-ai-agents/skills/rag-pipeline/SKILL.md +128 -0
  16. package/templates/bundle-ai-agents/skills/testing-strategy/SKILL.md +95 -0
  17. package/templates/bundle-base/AGENTS.md +118 -0
  18. package/templates/bundle-base/skills/branch-strategy/SKILL.md +42 -0
  19. package/templates/bundle-base/skills/code-review/SKILL.md +54 -0
  20. package/templates/bundle-base/skills/commit-pattern/SKILL.md +58 -0
  21. package/templates/bundle-data-pipeline/.spec/constitution.md +32 -0
  22. package/templates/bundle-data-pipeline/AGENTS.md +115 -0
  23. package/templates/bundle-data-pipeline/skills/data-preprocessing/SKILL.md +75 -0
  24. package/templates/bundle-data-pipeline/skills/docker-containerization/SKILL.md +114 -0
  25. package/templates/bundle-data-pipeline/skills/feature-engineering/SKILL.md +76 -0
  26. package/templates/bundle-data-pipeline/skills/mlops-pipeline/SKILL.md +77 -0
  27. package/templates/bundle-data-pipeline/skills/model-training/SKILL.md +68 -0
  28. package/templates/bundle-data-pipeline/skills/rag-pipeline/SKILL.md +128 -0
  29. package/templates/bundle-frontend-spa/.spec/constitution.md +32 -0
  30. package/templates/bundle-frontend-spa/AGENTS.md +107 -0
  31. package/templates/bundle-frontend-spa/skills/authentication/SKILL.md +90 -0
  32. package/templates/bundle-frontend-spa/skills/component-design/SKILL.md +115 -0
  33. package/templates/bundle-frontend-spa/skills/e2e-testing/SKILL.md +101 -0
  34. package/templates/bundle-frontend-spa/skills/integration-api/SKILL.md +95 -0
  35. package/templates/bundle-frontend-spa/skills/react-patterns/SKILL.md +130 -0
  36. package/templates/bundle-frontend-spa/skills/responsive-layout/SKILL.md +65 -0
  37. package/templates/bundle-frontend-spa/skills/state-management/SKILL.md +86 -0
  38. package/templates/bundle-jhipster-microservices/.spec/constitution.md +37 -0
  39. package/templates/bundle-jhipster-microservices/AGENTS.md +307 -0
  40. package/templates/bundle-jhipster-microservices/skills/ci-cd-pipeline/SKILL.md +112 -0
  41. package/templates/bundle-jhipster-microservices/skills/clean-architecture/SKILL.md +99 -0
  42. package/templates/bundle-jhipster-microservices/skills/ddd-tactical/SKILL.md +138 -0
  43. package/templates/bundle-jhipster-microservices/skills/jhipster-angular/SKILL.md +97 -0
  44. package/templates/bundle-jhipster-microservices/skills/jhipster-docker-k8s/SKILL.md +183 -0
  45. package/templates/bundle-jhipster-microservices/skills/jhipster-entities/SKILL.md +87 -0
  46. package/templates/bundle-jhipster-microservices/skills/jhipster-gateway/SKILL.md +96 -0
  47. package/templates/bundle-jhipster-microservices/skills/jhipster-kafka/SKILL.md +145 -0
  48. package/templates/bundle-jhipster-microservices/skills/jhipster-registry/SKILL.md +83 -0
  49. package/templates/bundle-jhipster-microservices/skills/jhipster-service/SKILL.md +131 -0
  50. package/templates/bundle-jhipster-microservices/skills/testing-strategy/SKILL.md +95 -0
  51. package/templates/bundle-jhipster-monorepo/.spec/constitution.md +32 -0
  52. package/templates/bundle-jhipster-monorepo/AGENTS.md +227 -0
  53. package/templates/bundle-jhipster-monorepo/skills/clean-architecture/SKILL.md +99 -0
  54. package/templates/bundle-jhipster-monorepo/skills/ddd-tactical/SKILL.md +138 -0
  55. package/templates/bundle-jhipster-monorepo/skills/jhipster-angular/SKILL.md +166 -0
  56. package/templates/bundle-jhipster-monorepo/skills/jhipster-entities/SKILL.md +141 -0
  57. package/templates/bundle-jhipster-monorepo/skills/jhipster-liquibase/SKILL.md +95 -0
  58. package/templates/bundle-jhipster-monorepo/skills/jhipster-security/SKILL.md +89 -0
  59. package/templates/bundle-jhipster-monorepo/skills/jhipster-spring/SKILL.md +155 -0
  60. package/templates/bundle-jhipster-monorepo/skills/testing-strategy/SKILL.md +95 -0
@@ -0,0 +1,227 @@
1
+ # Projeto: JHipster Monorepo
2
+
3
+ Você está construindo uma aplicação monolítica com JHipster. Backend em Java/Spring Boot, frontend em Angular, banco PostgreSQL, tudo em um único repositório.
4
+
5
+ ## Specification-Driven Development (SDD)
6
+
7
+ Este projeto usa **GitHub Spec Kit** para governança. Antes de implementar qualquer demanda:
8
+
9
+ 1. Rodar `/speckit.constitution` — se `.spec/constitution.md` não existir
10
+ 2. Rodar `/speckit.specify` — descrever O QUE e POR QUÊ (não como)
11
+ 3. Rodar `/speckit.plan` — arquitetura e decisões técnicas
12
+ 4. Rodar `/speckit.tasks` — quebrar em tasks atômicas
13
+ 5. Rodar `/speckit.implement` — executar as tasks
14
+
15
+ Nunca pular direto para código. Spec primeiro, código depois.
16
+
17
+ ## References
18
+
19
+ Documentos de referência que o agente deve consultar quando necessário:
20
+
21
+ - `references/jhipster-jdl-guide.md` — Guia completo de JDL
22
+ - `references/spring-boot-patterns.md` — Padrões Spring Boot
23
+ - `references/angular-patterns.md` — Padrões Angular no JHipster
24
+ - `references/liquibase-guide.md` — Guia de migrations Liquibase
25
+
26
+ ## Stack do projeto
27
+
28
+ - **Backend:** Java 21 + Spring Boot 3.x (gerado pelo JHipster)
29
+ - **Frontend:** Angular 17+ com TypeScript
30
+ - **Banco:** PostgreSQL
31
+ - **Cache:** Ehcache ou Redis
32
+ - **Migrations:** Liquibase (padrão JHipster)
33
+ - **Auth:** JWT (padrão JHipster) ou OAuth2/Keycloak
34
+ - **Testes:** JUnit 5 + Mockito (back), Jest + Cypress (front)
35
+ - **Build:** Maven ou Gradle
36
+ - **API docs:** Swagger/OpenAPI (auto-gerado)
37
+
38
+ ## Estrutura JHipster Monorepo
39
+
40
+ ```
41
+ project/
42
+ ├── src/
43
+ │ ├── main/
44
+ │ │ ├── java/com/empresa/projeto/
45
+ │ │ │ ├── domain/ # Entidades JPA (enriquecer com DDD)
46
+ │ │ │ │ ├── Demand.java
47
+ │ │ │ │ ├── Task.java
48
+ │ │ │ │ └── enumeration/
49
+ │ │ │ ├── repository/ # Spring Data JPA repositories
50
+ │ │ │ ├── service/ # Services (use cases)
51
+ │ │ │ │ ├── dto/ # DTOs
52
+ │ │ │ │ ├── mapper/ # MapStruct mappers
53
+ │ │ │ │ └── impl/
54
+ │ │ │ ├── web/rest/ # REST controllers
55
+ │ │ │ ├── config/ # Spring configs
56
+ │ │ │ └── security/ # Security configs
57
+ │ │ ├── resources/
58
+ │ │ │ ├── config/
59
+ │ │ │ │ ├── application.yml
60
+ │ │ │ │ ├── application-dev.yml
61
+ │ │ │ │ └── application-prod.yml
62
+ │ │ │ └── config/liquibase/ # Migrations
63
+ │ │ └── webapp/ # Angular app
64
+ │ │ ├── app/
65
+ │ │ │ ├── entities/ # Entity CRUD modules
66
+ │ │ │ ├── shared/ # Shared components
67
+ │ │ │ ├── core/ # Core services
68
+ │ │ │ └── layouts/ # Page layouts
69
+ │ │ └── content/ # Assets
70
+ │ └── test/
71
+ │ ├── java/ # JUnit tests
72
+ │ └── javascript/ # Jest tests
73
+ ├── .jhipster/ # JDL entity definitions
74
+ │ ├── Demand.json
75
+ │ └── Task.json
76
+ ├── jhipster-jdl.jdl # JDL model file
77
+ ├── pom.xml # Maven
78
+ └── package.json # Frontend deps
79
+ ```
80
+
81
+ ## Padrões de código
82
+
83
+ ### Java
84
+ - Máximo 500 linhas por classe
85
+ - Records para DTOs imutáveis (Java 21)
86
+ - Optional ao invés de null returns
87
+ - Streams API para coleções (não loops imperativos)
88
+ - Google Java Style Guide
89
+ - Lombok apenas para: `@Slf4j`, `@RequiredArgsConstructor`. Evitar `@Data`.
90
+ - Nunca `@Autowired` em campo — usar constructor injection
91
+
92
+ ### Angular
93
+ - Strict mode habilitado
94
+ - Standalone components (Angular 17+)
95
+ - Signals para estado reativo quando possível
96
+ - Lazy loading por rota/feature
97
+ - Reactive Forms com validação
98
+
99
+ ## JDL — Modelo de entidades
100
+
101
+ Usar JDL para definir entidades e gerar código:
102
+
103
+ ```jdl
104
+ entity Demand {
105
+ description TextBlob required
106
+ status DemandStatus required
107
+ priority Priority required
108
+ createdAt Instant required
109
+ completedAt Instant
110
+ }
111
+
112
+ entity Task {
113
+ description String required maxlength(500)
114
+ status TaskStatus required
115
+ branchName String maxlength(100)
116
+ startedAt Instant
117
+ completedAt Instant
118
+ }
119
+
120
+ enum DemandStatus {
121
+ CREATED, PLANNED, IN_PROGRESS, COMPLETED, CANCELLED
122
+ }
123
+
124
+ enum TaskStatus {
125
+ PENDING, IN_PROGRESS, COMPLETED, FAILED
126
+ }
127
+
128
+ enum Priority {
129
+ LOW, MEDIUM, HIGH, CRITICAL
130
+ }
131
+
132
+ relationship OneToMany {
133
+ Demand{tasks} to Task{demand required}
134
+ }
135
+
136
+ paginate Demand, Task with pagination
137
+ dto * with mapstruct
138
+ service * with serviceImpl
139
+ ```
140
+
141
+ ## Enriquecer JHipster com DDD
142
+
143
+ O JHipster gera entidades anêmicas por padrão. Enriqueça com comportamento:
144
+
145
+ ```java
146
+ // NÃO FAZER — entidade anêmica (padrão JHipster)
147
+ public class Demand {
148
+ private String description;
149
+ private DemandStatus status;
150
+ // apenas getters/setters
151
+ }
152
+
153
+ // FAZER — entidade rica
154
+ public class Demand {
155
+ private String description;
156
+ private DemandStatus status;
157
+ private List<Task> tasks = new ArrayList<>();
158
+
159
+ public List<Task> decompose(TaskPlanner planner) {
160
+ if (this.status != DemandStatus.CREATED) {
161
+ throw new DemandAlreadyDecomposedException(this.id);
162
+ }
163
+ this.tasks = planner.plan(this.description);
164
+ this.status = DemandStatus.PLANNED;
165
+ return Collections.unmodifiableList(this.tasks);
166
+ }
167
+
168
+ public void startTask(Long taskId) {
169
+ Task task = findTaskOrThrow(taskId);
170
+ long activeCount = tasks.stream()
171
+ .filter(t -> t.getStatus() == TaskStatus.IN_PROGRESS)
172
+ .count();
173
+ if (activeCount >= 3) {
174
+ throw new TooManyActiveTasksException();
175
+ }
176
+ task.start();
177
+ }
178
+ }
179
+ ```
180
+
181
+ ## Liquibase — Migrations
182
+
183
+ Sempre gerar changeset para mudanças de schema:
184
+
185
+ ```xml
186
+ <changeSet id="20260327-1" author="dev">
187
+ <createTable tableName="demand">
188
+ <column name="id" type="bigint" autoIncrement="true">
189
+ <constraints primaryKey="true"/>
190
+ </column>
191
+ <column name="description" type="clob">
192
+ <constraints nullable="false"/>
193
+ </column>
194
+ <column name="status" type="varchar(20)">
195
+ <constraints nullable="false"/>
196
+ </column>
197
+ <column name="created_at" type="timestamp">
198
+ <constraints nullable="false"/>
199
+ </column>
200
+ </createTable>
201
+ </changeSet>
202
+ ```
203
+
204
+ ## Testes
205
+
206
+ - **JUnit 5:** Testar services e entidades enriquecidas
207
+ - **MockMvc:** Testar controllers (status codes, validação)
208
+ - **Testcontainers:** Integração com PostgreSQL real
209
+ - **Jest:** Componentes Angular
210
+ - **Cypress:** E2E flows
211
+ - Cobertura mínima: 80%
212
+
213
+ ## Git
214
+
215
+ - Commits: `feat(demand): adicionar decomposição automática`
216
+ - Branches: `feature/<entity>-<descricao>`
217
+ - Nunca alterar arquivos gerados do JHipster sem necessidade
218
+ - Regenerar com `jhipster import-jdl` quando mudar modelo
219
+
220
+ ## O que NÃO fazer
221
+
222
+ - Não editar manualmente arquivos que o JHipster regenera (liquibase gerado, webpack config)
223
+ - Não colocar regras de negócio no REST controller
224
+ - Não usar `@Transactional` em todo lugar — só onde necessário
225
+ - Não criar services genéricos "God class"
226
+ - Não ignorar DTOs — nunca expor entidade JPA na API
227
+ - Não usar Lombok `@Data` (gera equals/hashCode perigoso com JPA)
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: clean-architecture
3
+ description: Implementar Clean Architecture com camadas de domínio, aplicação e infraestrutura. Use quando for criar módulos, organizar código em camadas, separar regras de negócio de infraestrutura, ou estruturar um projeto novo.
4
+ ---
5
+
6
+ # Clean Architecture
7
+
8
+ ## Camadas
9
+
10
+ ```
11
+ ┌──────────────────────────────┐
12
+ │ API / CLI │ ← Controllers, Routers
13
+ ├──────────────────────────────┤
14
+ │ APPLICATION │ ← Use Cases, DTOs
15
+ ├──────────────────────────────┤
16
+ │ DOMAIN │ ← Entities, VOs, Events, Repos (interface)
17
+ ├──────────────────────────────┤
18
+ │ INFRASTRUCTURE │ ← DB, HTTP clients, Frameworks
19
+ └──────────────────────────────┘
20
+
21
+ Dependency Rule: setas apontam para DENTRO (infra → domain)
22
+ Domain NUNCA importa de infrastructure
23
+ ```
24
+
25
+ ## Domain Layer
26
+
27
+ ```python
28
+ # domain/entities/demand.py
29
+ class Demand:
30
+ def __init__(self, id: DemandId, description: str):
31
+ self._id = id
32
+ self._description = description
33
+ self._status = DemandStatus.CREATED
34
+ self._events: list[DomainEvent] = []
35
+
36
+ def decompose(self, planner: TaskPlanner) -> list[Task]:
37
+ if self._status != DemandStatus.CREATED:
38
+ raise DemandAlreadyDecomposedException(self._id)
39
+ tasks = planner.plan(self._description)
40
+ self._status = DemandStatus.PLANNED
41
+ self._events.append(DemandDecomposed(self._id, [t.id for t in tasks]))
42
+ return tasks
43
+
44
+ @property
45
+ def pending_events(self) -> list[DomainEvent]:
46
+ return list(self._events)
47
+
48
+ # domain/repositories/demand_repository.py (PORT - apenas interface)
49
+ class DemandRepository(ABC):
50
+ @abstractmethod
51
+ def find_by_id(self, id: DemandId) -> Demand: ...
52
+ @abstractmethod
53
+ def save(self, demand: Demand) -> None: ...
54
+ ```
55
+
56
+ ## Application Layer
57
+
58
+ ```python
59
+ # application/use_cases/decompose_demand.py
60
+ class DecomposeDemand:
61
+ def __init__(self, repo: DemandRepository, planner: TaskPlanner, event_bus: EventBus):
62
+ self._repo = repo
63
+ self._planner = planner
64
+ self._event_bus = event_bus
65
+
66
+ def execute(self, demand_id: str) -> DecomposeDemandOutput:
67
+ demand = self._repo.find_by_id(DemandId(demand_id))
68
+ tasks = demand.decompose(self._planner)
69
+ self._repo.save(demand)
70
+ for event in demand.pending_events:
71
+ self._event_bus.publish(event)
72
+ return DecomposeDemandOutput(tasks=[TaskDTO.from_entity(t) for t in tasks])
73
+ ```
74
+
75
+ ## Infrastructure Layer
76
+
77
+ ```python
78
+ # infrastructure/persistence/pg_demand_repository.py (ADAPTER)
79
+ class PgDemandRepository(DemandRepository):
80
+ def __init__(self, session: Session):
81
+ self._session = session
82
+
83
+ def find_by_id(self, id: DemandId) -> Demand:
84
+ model = self._session.query(DemandModel).get(str(id))
85
+ if not model:
86
+ raise DemandNotFoundException(id)
87
+ return self._to_entity(model)
88
+
89
+ def save(self, demand: Demand) -> None:
90
+ model = self._to_model(demand)
91
+ self._session.merge(model)
92
+ self._session.commit()
93
+ ```
94
+
95
+ ## Regra de ouro
96
+
97
+ Use Case orquestra → Entity contém regra → Repository persiste
98
+
99
+ Nunca colocar regra de negócio no Controller, Repository ou "Service" genérico.
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: ddd-tactical
3
+ description: Implementar padrões táticos do DDD - Entities, Value Objects, Aggregates, Domain Events, Repositories e Domain Services. Use quando for modelar domínio, criar entidades ricas, ou aplicar DDD no código.
4
+ ---
5
+
6
+ # DDD Tático
7
+
8
+ ## Value Objects
9
+
10
+ Imutáveis, comparados por valor, contêm validação.
11
+
12
+ ```python
13
+ @dataclass(frozen=True)
14
+ class Email:
15
+ value: str
16
+
17
+ def __post_init__(self):
18
+ if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', self.value):
19
+ raise InvalidEmailException(self.value)
20
+
21
+ @dataclass(frozen=True)
22
+ class ComplianceScore:
23
+ value: float
24
+
25
+ def __post_init__(self):
26
+ if not 0 <= self.value <= 100:
27
+ raise ValueError("Score deve ser entre 0 e 100")
28
+
29
+ def is_passing(self) -> bool:
30
+ return self.value >= 80.0
31
+
32
+ def __str__(self) -> str:
33
+ return f"{self.value:.1f}%"
34
+ ```
35
+
36
+ ## Entities
37
+
38
+ Identidade única, mutáveis, contêm comportamento.
39
+
40
+ ```python
41
+ class Task:
42
+ def __init__(self, id: TaskId, description: str, agent_type: AgentType):
43
+ self._id = id
44
+ self._description = description
45
+ self._agent_type = agent_type
46
+ self._status = TaskStatus.PENDING
47
+ self._started_at: datetime | None = None
48
+ self._completed_at: datetime | None = None
49
+
50
+ def start(self) -> None:
51
+ if self._status != TaskStatus.PENDING:
52
+ raise TaskNotPendingException(self._id)
53
+ self._status = TaskStatus.IN_PROGRESS
54
+ self._started_at = datetime.now()
55
+
56
+ def complete(self, result: TaskResult) -> None:
57
+ if self._status != TaskStatus.IN_PROGRESS:
58
+ raise TaskNotInProgressException(self._id)
59
+ self._status = TaskStatus.COMPLETED
60
+ self._completed_at = datetime.now()
61
+
62
+ @property
63
+ def duration(self) -> timedelta | None:
64
+ if self._started_at and self._completed_at:
65
+ return self._completed_at - self._started_at
66
+ return None
67
+ ```
68
+
69
+ ## Aggregates
70
+
71
+ Cluster de entities com uma raiz que protege invariantes.
72
+
73
+ ```python
74
+ class Demand: # Aggregate Root
75
+ """Demand é a raiz. Tasks só são acessadas via Demand."""
76
+
77
+ def add_task(self, task: Task) -> None:
78
+ if len(self._tasks) >= 20:
79
+ raise TooManyTasksException("Máximo 20 tasks por demanda")
80
+ self._tasks.append(task)
81
+
82
+ def start_task(self, task_id: TaskId) -> None:
83
+ task = self._find_task(task_id)
84
+ # Verificar invariante: não ter mais de 3 tasks simultâneas
85
+ active = [t for t in self._tasks if t.status == TaskStatus.IN_PROGRESS]
86
+ if len(active) >= 3:
87
+ raise TooManyActiveTasksException()
88
+ task.start()
89
+ ```
90
+
91
+ ## Domain Events
92
+
93
+ Notificam que algo aconteceu no domínio.
94
+
95
+ ```python
96
+ @dataclass(frozen=True)
97
+ class DomainEvent:
98
+ occurred_at: datetime = field(default_factory=datetime.now)
99
+
100
+ @dataclass(frozen=True)
101
+ class TaskCompleted(DomainEvent):
102
+ task_id: TaskId
103
+ agent_id: AgentId
104
+ branch_name: str
105
+ duration_seconds: float
106
+
107
+ @dataclass(frozen=True)
108
+ class ComplianceViolationDetected(DomainEvent):
109
+ agent_id: AgentId
110
+ bundle_name: str
111
+ violations: list[str]
112
+ severity: str # "warning" | "critical"
113
+ ```
114
+
115
+ ## Domain Services
116
+
117
+ Lógica que não pertence a uma única entidade.
118
+
119
+ ```python
120
+ class TeamRecruitmentService:
121
+ def recruit_for_demand(self, demand: Demand, available: list[Agent]) -> AgentTeam:
122
+ complexity = demand.assess_complexity()
123
+ required = self._determine_roles(complexity)
124
+ team = AgentTeam()
125
+ for role in required:
126
+ agent = next((a for a in available if a.type == role and a.is_available), None)
127
+ if not agent:
128
+ raise NoAvailableAgentException(role)
129
+ team.add(agent)
130
+ return team
131
+ ```
132
+
133
+ ## Ordem de prioridade para regras
134
+
135
+ 1. **Value Object** — validação e comportamento simples
136
+ 2. **Entity** — regras que envolvem estado da entidade
137
+ 3. **Domain Service** — regras que envolvem múltiplas entidades
138
+ 4. **Use Case** — orquestração (NÃO contém regras)
@@ -0,0 +1,166 @@
1
+ ---
2
+ name: jhipster-angular
3
+ description: Desenvolver frontend Angular no JHipster com componentes, services, routing e formulários reativos. Use quando precisar criar telas, componentes Angular, ou customizar o frontend JHipster.
4
+ ---
5
+
6
+ # JHipster Angular
7
+
8
+ ## Estrutura gerada pelo JHipster
9
+
10
+ ```
11
+ src/main/webapp/app/
12
+ ├── entities/ # CRUD gerado por entidade
13
+ │ ├── demand/
14
+ │ │ ├── demand.model.ts
15
+ │ │ ├── demand.routes.ts
16
+ │ │ ├── service/
17
+ │ │ │ └── demand.service.ts
18
+ │ │ ├── list/
19
+ │ │ │ └── demand.component.ts
20
+ │ │ ├── detail/
21
+ │ │ │ └── demand-detail.component.ts
22
+ │ │ ├── update/
23
+ │ │ │ └── demand-update.component.ts
24
+ │ │ └── delete/
25
+ │ │ └── demand-delete-dialog.component.ts
26
+ │ └── task/
27
+ ├── shared/ # Componentes compartilhados
28
+ │ ├── date/
29
+ │ ├── filter/
30
+ │ ├── pagination/
31
+ │ └── sort/
32
+ ├── core/ # Services core
33
+ │ ├── auth/
34
+ │ ├── interceptor/
35
+ │ └── util/
36
+ ├── layouts/ # Layouts de página
37
+ │ ├── main/
38
+ │ ├── navbar/
39
+ │ └── footer/
40
+ └── config/
41
+ ```
42
+
43
+ ## Customizar componentes gerados
44
+
45
+ O JHipster gera CRUD básico. Customizar SEM modificar a estrutura gerada:
46
+
47
+ ```typescript
48
+ // entities/demand/list/demand.component.ts
49
+ @Component({
50
+ standalone: true,
51
+ selector: 'jhi-demand',
52
+ templateUrl: './demand.component.html',
53
+ imports: [SharedModule, RouterModule, SortDirective, SortByDirective, FormsModule],
54
+ })
55
+ export class DemandComponent implements OnInit {
56
+ demands?: IDemand[];
57
+ isLoading = false;
58
+
59
+ // ADICIONAR — filtros customizados
60
+ statusFilter: DemandStatus | null = null;
61
+ priorityFilter: Priority | null = null;
62
+
63
+ constructor(
64
+ protected demandService: DemandService,
65
+ protected activatedRoute: ActivatedRoute,
66
+ protected router: Router,
67
+ protected sortService: SortService,
68
+ ) {}
69
+
70
+ // ADICIONAR — método de filtro
71
+ filterByStatus(status: DemandStatus): void {
72
+ this.statusFilter = status;
73
+ this.loadDemands();
74
+ }
75
+
76
+ private loadDemands(): void {
77
+ this.isLoading = true;
78
+ this.demandService
79
+ .query({
80
+ page: this.page,
81
+ size: this.itemsPerPage,
82
+ sort: this.sort(),
83
+ 'status.equals': this.statusFilter,
84
+ 'priority.equals': this.priorityFilter,
85
+ })
86
+ .subscribe({
87
+ next: (res) => {
88
+ this.demands = res.body ?? [];
89
+ this.isLoading = false;
90
+ },
91
+ error: () => (this.isLoading = false),
92
+ });
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Criar componentes novos (fora do CRUD gerado)
98
+
99
+ ```typescript
100
+ // dashboard/dashboard.component.ts
101
+ @Component({
102
+ standalone: true,
103
+ selector: 'app-dashboard',
104
+ template: `
105
+ <div class="row">
106
+ <div class="col-md-3" *ngFor="let metric of metrics">
107
+ <div class="card">
108
+ <div class="card-body text-center">
109
+ <h5>{{ metric.label }}</h5>
110
+ <h2>{{ metric.value }}</h2>
111
+ </div>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ <div class="row mt-4">
116
+ <div class="col-md-8">
117
+ <app-agent-activity-feed />
118
+ </div>
119
+ <div class="col-md-4">
120
+ <app-active-demands />
121
+ </div>
122
+ </div>
123
+ `,
124
+ imports: [CommonModule, AgentActivityFeedComponent, ActiveDemandsComponent],
125
+ })
126
+ export class DashboardComponent implements OnInit {
127
+ metrics: Metric[] = [];
128
+
129
+ constructor(private dashboardService: DashboardService) {}
130
+
131
+ ngOnInit(): void {
132
+ this.dashboardService.getMetrics().subscribe(m => this.metrics = m);
133
+ }
134
+ }
135
+ ```
136
+
137
+ ## Reactive Forms com validação
138
+
139
+ ```typescript
140
+ @Component({...})
141
+ export class DemandUpdateComponent {
142
+ editForm = new FormGroup({
143
+ description: new FormControl('', [Validators.required, Validators.minLength(10)]),
144
+ priority: new FormControl<Priority>(Priority.MEDIUM, Validators.required),
145
+ status: new FormControl<DemandStatus>(DemandStatus.CREATED),
146
+ });
147
+
148
+ save(): void {
149
+ if (this.editForm.valid) {
150
+ const demand = this.editForm.getRawValue();
151
+ this.demandService.create(demand).subscribe({
152
+ next: () => this.router.navigate(['/demand']),
153
+ error: (err) => this.alertService.addAlert({ type: 'danger', message: err.message }),
154
+ });
155
+ }
156
+ }
157
+ }
158
+ ```
159
+
160
+ ## Regras
161
+
162
+ - Não modificar `navbar.component.ts` diretamente — usar menus configuráveis
163
+ - Usar `SharedModule` para imports comuns
164
+ - Lazy loading para todas as rotas de entidades
165
+ - Usar `TranslateService` do JHipster para i18n
166
+ - Manter compatibilidade com regeneração: marcar customizações claramente