> ⚠️ **Aviso:**
Este documento tem caráter apenas de apoio e referência técnica.
As informações aqui descritas — incluindo entradas, saídas, estruturas de dados, fluxos e validações — não são definitivas e podem ser alteradas conforme evolução do entendimento do negócio, ajustes da arquitetura, revisões de API ou decisões de implementação.
# Documento de Design: PreAtendimentoEtapa
## Visão Geral
Este documento descreve o design para implementação da funcionalidade `PreAtendimentoEtapa`, que rastreia checkpoints de progresso para um `PreAtendimento`.
**Decisão de Design Principal:** O modelo de domínio `PreAtendimentoEtapa` contém `PreAtendimento` dentro dele. Esta abordagem evita modificar a classe `PreAtendimento` existente.
## Tabela do Banco de Dados
```sql
PreAtendimentoEtapa {
Long id (PK)
Long PreAtendimentoId (FK)
String Etapa (PATIENT, MEDICAL_REQUEST, OVERVIEW)
}
```
## Link Diagrama completo
https://drive.google.com/file/d/1sCmmch8ntIbNZ7In2FHymMVKulHrxgbg/view?usp=sharing
---
## Componentes da Implementação
### 1. Enum de Checkpoint
**Arquivo:** `core/domain/model/EtapaEnum.java`
Enum que representa os possíveis checkpoints de progresso do pré-atendimento:
```java
package br.com.shift.preatendimento.core.domain.model;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum EtapaEnum {
PATIENT,
MEDICAL_REQUEST,
OVERVIEW
}
```
---
### 2. Modelo de Domínio
**Arquivo:** `core/domain/model/PreAtendimentoEtapa.java`
O `PreAtendimentoEtapa` contém `PreAtendimento` dentro:
```java
package br.com.shift.preatendimento.core.domain.model;
@Data
@Builder
public class PreAtendimentoEtapa {
Long id;
EtapaEnum etapa;
// PreAtendimento está contido dentro de PreAtendimentoEtapa
PreAtendimento preAtendimento;
}
```
---
### 3. Camada de Entidade
**Arquivo:** `core/adapter/out/db/entity/PreAtendimentoEtapaEntity.java`
```java
package br.com.shift.preatendimento.core.adapter.out.db.entity;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Entity(name = "PreAtendimentoEtapa")
@Table(schema = "preatendimento", name = "PreAtendimentoEtapa")
public class PreAtendimentoEtapaEntity {
@Id
@Column(name = "ID")
@EqualsAndHashCode.Include
@GeneratedValue(strategy = GenerationType.UUID)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PreAtendimentoId", foreignKey = @ForeignKey(name = "FkPreAtendimentoId"))
private PreAtendimentoEntity preAtendimento;
@Column(name = "Checkpoint")
private Integer checkpoint;
public static PreAtendimentoEtapaEntity fromDomain(
PreAtendimentoEtapa progresso,
PreAtendimentoEntity preAtendimentoEntity) {
return PreAtendimentoEtapaEntity.builder()
.id(progresso.getId())
.preAtendimento(preAtendimentoEntity)
.checkpoint(progresso.getCheckpoint() != null
? progresso.getCheckpoint().getCodigo()
: null)
.build();
}
public PreAtendimentoEtapa toDomain() {
return PreAtendimentoEtapa.builder()
.id(getId())
.checkpoint(getCheckpoint() != null
? CheckpointEtapa.fromCodigo(getCheckpoint())
: null)
.preAtendimento(getPreAtendimento() != null ? getPreAtendimento().toDomain() : null)
.build();
}
}
```
---
### 4. Repository Port (Porta de Saída)
**Arquivo:** `core/application/port/out/PreAtendimentoEtapaRepositoryPort.java`
Criar uma nova porta de repositório para `PreAtendimentoEtapa`:
```java
package br.com.shift.preatendimento.core.application.port.out;
import br.com.shift.preatendimento.core.domain.model.PreAtendimentoEtapa;
import java.util.Optional;
public interface PreAtendimentoEtapaRepositoryPort {
// não considerar esse salvar, caso nao esteja na parte de salvar de fato o passo
void salvar(PreAtendimentoEtapa progresso);
Optional<PreAtendimentoEtapa> buscarPorPreAtendimentoId(Long preAtendimentoId);
}
```
---
### 5. Implementação do Adapter de Banco de Dados
**Arquivo:** `core/adapter/out/db/PreAtendimentoEtapaDbAdapter.java`
```java
package br.com.shift.preatendimento.core.adapter.out.db;
@ApplicationScoped
public class PreAtendimentoEtapaDbAdapter
implements PreAtendimentoEtapaRepositoryPort,
PanacheRepositoryBase<PreAtendimentoEtapaEntity, UUID> {
@WithSpan
@Override
@Transactional
public void salvar(PreAtendimentoEtapa progresso) {
PreAtendimentoEtapaEntity entity = PreAtendimentoEtapaEntity.builder()
.id(progresso.getId())
.checkpoint(progresso.getCheckpoint() != null
? progresso.getCheckpoint().getCodigo()
: null)
.build();
persist(entity);
}
@WithSpan
@Override
public Optional<PreAtendimentoEtapa> buscarPorPreAtendimentoId(Long preAtendimentoId) {
// alguma query...
}
}
```
---
### 6. Use Case Port (Porta de Entrada)
**Arquivo:** `core/application/port/in/BuscarPreAtendimentoEtapaUseCase.java`
```java
package br.com.shift.preatendimento.core.application.port.in;
import br.com.shift.preatendimento.core.domain.model.PreAtendimentoEtapa;
public interface BuscarPreAtendimentoEtapaUseCase {
PreAtendimentoEtapa buscarPorPreAtendimentoId(Long preAtendimentoId);
}
```
---
### 7. Implementação do Service
**Arquivo:** `core/application/service/PreAtendimentoEtapaService.java`
Criar um novo service para `PreAtendimentoEtapa`:
```java
package br.com.shift.preatendimento.core.application.service;
@Slf4j
@ApplicationScoped
public class PreAtendimentoEtapaService implements BuscarPreAtendimentoEtapaUseCase {
@Inject
PreAtendimentoEtapaRepositoryPort preAtendimentoEtapaRepositoryPort;
@Override
@WithSpan
public PreAtendimentoEtapa buscarPorPreAtendimentoId(Long preAtendimentoId) {
return preAtendimentoEtapaRepositoryPort
.buscarPorPreAtendimentoId(preAtendimentoId)
.orElseThrow(() -> {
log.error("Etapa não encontrado para o pré-atendimento id: {}", preAtendimentoId);
return new PreAtendimentoEtapaInexistenteException();
});
}
}
```
---
### 8. Exceção (Opcional)
**Arquivo:** `core/domain/exception/PreAtendimentoEtapaInexistenteException.java`
```java
package br.com.shift.preatendimento.core.domain.exception;
public class PreAtendimentoEtapaInexistenteException extends RuntimeException {
public PreAtendimentoEtapaInexistenteException() {
super("Etapa do pré-atendimento não encontrado");
}
}
```
---
### 9. REST Resource (Opcional)
**Arquivo:** `core/adapter/in/rest/resource/PreAtendimentoEtapaResource.java`
```java
package br.com.shift.preatendimento.core.adapter.in.rest.resource;
@Path("steps")
public class PreAtendimentoEtapaResource {
@Inject
BuscarPreAtendimentoEtapaUseCase buscarPreAtendimentoEtapaUseCase;
@GET
@Path("/pre-services/{preAtendimentoId}")
@Produces(MediaType.APPLICATION_JSON)
public Response buscarPorPreAtendimentoId(@PathParam("preAtendimentoId") Long preAtendimentoId) {
PreAtendimentoEtapa progresso =
buscarPreAtendimentoEtapaUseCase.buscarPorPreAtendimentoId(preAtendimentoId);
return Response.ok(progresso).build();
}
}
```
---
## Auditoria
Implementação manual de auditoria para registrar alterações no `PreAtendimentoEtapa`.
### Tabelas
```sql
PreAtendimentoEtapaAuditoria {
Long ID (PK)
Long REV (FK -> Revisao)
Long PreAtendimentoId (FK)
String Checkpoint (PATIENT, MEDICAL_REQUESTS, OVERVIEW)
String TipoOperacao (INSERT, UPDATE, DELETE)
}
Revisao {
Long ID (PK)
DateTime DataHora
String Usuario
}
```
### Enum
**Arquivo:** `core/domain/model/TipoOperacaoAuditoria.java`
```java
public enum TipoOperacaoAuditoria {
INSERT,
UPDATE,
DELETE
}
```
### Modelo de Domínio
**Arquivo:** `core/domain/model/PreAtendimentoEtapaAuditoria.java`
```java
@Data
@Builder
public class PreAtendimentoEtapaAuditoria {
private Long id;
private Long preAtendimentoEtapaId;
private Long preAtendimentoId;
private CheckpointEtapa checkpoint;
private TipoOperacaoAuditoria tipoOperacao;
private Revisao revisao;
}
```
**Arquivo:** `core/domain/model/Revisao.java`
```java
@Data
@Builder
public class Revisao {
private Long id;
private LocalDateTime dataHora;
private String usuario;
}
```
### Entidades
**Arquivo:** `core/adapter/out/db/entity/PreAtendimentoEtapaAuditoriaEntity.java`
```java
@Entity
@Table(schema = "preatendimento", name = "PreAtendimentoEtapaAuditoria")
public class PreAtendimentoEtapaAuditoriaEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "REV")
private RevisaoEntity revisao;
@Column(name = "PreAtendimentoId")
private Long preAtendimentoId;
@Column(name = "Checkpoint")
private Integer checkpoint;
@Enumerated(EnumType.STRING)
@Column(name = "TipoOperacao")
private TipoOperacaoAuditoria tipoOperacao;
// fromDomain e toDomain...
}
```
**Arquivo:** `core/adapter/out/db/entity/RevisaoEntity.java`
```java
@Entity
@Table(schema = "preatendimento", name = "Revisao")
public class RevisaoEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "DataHora")
private LocalDateTime dataHora;
@Column(name = "Usuario")
private String usuario;
// fromDomain e toDomain...
}
```
### Port e Adapter
**Arquivo:** `core/application/port/out/PreAtendimentoEtapaAuditoriaRepositoryPort.java`
```java
public interface PreAtendimentoEtapaAuditoriaRepositoryPort {
void registrar(PreAtendimentoEtapaAuditoria auditoria);
List<PreAtendimentoEtapaAuditoria> buscarPorPreAtendimentoId(Long preAtendimentoId);
}
```
**Arquivo:** `core/adapter/out/db/PreAtendimentoEtapaAuditoriaDbAdapter.java` e `RevisaoDbAdapter.java`
> Implementações seguem o mesmo padrão dos demais adapters do projeto.
---
## Exemplo de Resposta
Ao chamar `GET /pre-service-progress/pre-service/{preAtendimentoId}`, a resposta será:
```json
{
"step": "PATIENT",
"preAtendimento": {
"id": 1,
"idExterno": "abc-123",
"status": "UNDER_REVIEW",
"pacienteId": 100,
"telefoneOrigem": "11999999999",
"telefoneLaboratorio": "1133333333",
"dataCriacao": "2025-12-17T10:00:00",
"dataAtualizacao": "2025-12-17T10:30:00",
"visualizado": true,
"codigo": "PA001"
}
}
```
---
## Resumo dos Arquivos
| Camada | Arquivo | Descrição |
|--------|---------|-----------|
| Domain | `CheckpointEtapa.java` | Enum dos checkpoints de progresso |
| Domain | `TipoOperacaoAuditoria.java` | Enum dos tipos de operação de auditoria |
| Domain | `PreAtendimentoEtapa.java` | Modelo de domínio do progresso |
| Domain | `PreAtendimentoEtapaAuditoria.java` | Modelo de domínio da auditoria |
| Domain | `Revisao.java` | Modelo de domínio da revisão |
| Domain | `PreAtendimentoEtapaInexistenteException.java` | Exceção customizada |
| Entity | `PreAtendimentoEtapaEntity.java` | Entidade JPA do progresso |
| Entity | `PreAtendimentoEtapaAuditoriaEntity.java` | Entidade JPA da auditoria |
| Entity | `RevisaoEntity.java` | Entidade JPA da revisão |
| Port Out | `PreAtendimentoEtapaRepositoryPort.java` | Interface do repositório de progresso |
| Port Out | `PreAtendimentoEtapaAuditoriaRepositoryPort.java` | Interface do repositório de auditoria |
| Adapter Out | `PreAtendimentoEtapaDbAdapter.java` | Implementação do repositório de progresso |
| Adapter Out | `PreAtendimentoEtapaAuditoriaDbAdapter.java` | Implementação do repositório de auditoria |
| Adapter Out | `RevisaoDbAdapter.java` | Implementação do repositório de revisão |
| Port In | `BuscarPreAtendimentoEtapaUseCase.java` | Interface do caso de uso |
| Service | `PreAtendimentoEtapaService.java` | Implementação do caso de uso |
| Adapter In | `PreAtendimentoEtapaResource.java` | Endpoint REST |