---
# System prepended metadata

title: 'Documento de Design: PreAtendimentoEtapa'

---

> ⚠️ **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 |
