> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devmob.app.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Trip Schedules

> Programações recorrentes que materializam viagens vendáveis: frequência, horizonte móvel de 90 dias, idempotência e conflitos.

Uma **TripSchedule** é um template recorrente que materializa viagens (`Trip`) futuras vendáveis. Ela combina rota, veículo, motorista, frequência e paradas-template, e o sistema gera as ocorrências em um **horizonte móvel de 90 dias**.

## Campos

| Campo            | Tipo                  | Descrição                                              |
| ---------------- | --------------------- | ------------------------------------------------------ |
| `tripScheduleId` | UUID                  | Identificador único                                    |
| `companyId`      | UUID                  | Empresa dona da programação (resolvida da rota)        |
| `routeId`        | UUID                  | Rota das viagens geradas                               |
| `vehicleId`      | UUID                  | Veículo das viagens geradas                            |
| `driverId`       | UUID                  | Motorista das viagens geradas                          |
| `name`           | string                | Nome da programação                                    |
| `frequency`      | TripScheduleFrequency | `DAILY`, `WEEKLY` ou `MONTHLY`                         |
| `interval`       | integer               | Intervalo entre ocorrências (padrão `1`)               |
| `status`         | TripScheduleStatus    | `ACTIVE`, `PAUSED` ou `ARCHIVED`                       |
| `departureAt`    | datetime              | Primeira partida programada                            |
| `endAt`          | datetime?             | Fim opcional da recorrência                            |
| `createdBy`      | UUID?                 | Usuário que criou o registro, quando aplicável         |
| `createdAt`      | datetime              | Data de criação                                        |
| `updatedBy`      | UUID?                 | Usuário que fez a última atualização, quando aplicável |
| `updatedAt`      | datetime              | Data de última atualização                             |
| `deletedBy`      | UUID?                 | Usuário que removeu o registro, quando aplicável       |
| `deletedAt`      | datetime?             | Data de remoção                                        |

## Templates de parada e itinerário

As paradas-template vivem em `TripScheduleStop`, e os itinerários-template vivem em `TripScheduleItinerary`. Na materialização, esses templates produzem os `TripStop` e `TripItinerary` de cada viagem gerada.

| Entidade                | Campos principais                                                        |
| ----------------------- | ------------------------------------------------------------------------ |
| `TripScheduleStop`      | `pointId`, `stopOrder`, `arrivalOffsetMinutes`, `departureOffsetMinutes` |
| `TripScheduleItinerary` | `fromStopOrder`, `toStopOrder`, `price`                                  |

## Ciclo de vida

```mermaid theme={null}
stateDiagram-v2
    [*] --> ACTIVE
    ACTIVE --> PAUSED : Pausar
    PAUSED --> ACTIVE : Retomar
    ACTIVE --> ARCHIVED : Arquivar
    PAUSED --> ARCHIVED : Arquivar
    ARCHIVED --> [*]
```

| Status     | Descrição                                                             |
| ---------- | --------------------------------------------------------------------- |
| `ACTIVE`   | Materializa viagens e participa da rotina diária de materialização.   |
| `PAUSED`   | Fica fora da rotina diária de materialização. Pode voltar a `ACTIVE`. |
| `ARCHIVED` | Arquivada. Não pode ser reativada.                                    |

A atualização altera **apenas** o `name`. Pausar, retomar e arquivar são operações dedicadas.

## Materialização

### Horizonte e ocorrências

As ocorrências são calculadas a partir do momento atual até 90 dias à frente. Se `endAt` for anterior ao fim do horizonte, ele é o limite. Apenas ocorrências futuras dentro do limite entram. Há um teto de segurança de 10.000 iterações.

A partir de `departureAt`, cada ocorrência `index` avança por frequência:

| Frequência | Avanço                        |
| ---------- | ----------------------------- |
| `DAILY`    | `+ index × interval` dias     |
| `WEEKLY`   | `+ index × interval × 7` dias |
| `MONTHLY`  | `+ index × interval` meses    |

<Warning>
  Na frequência `MONTHLY`, quando o dia de origem não existe no mês de destino, a ocorrência é **pulada**. Ex.: uma programação que parte dia 31 não gera ocorrência em fevereiro.
</Warning>

Para cada ocorrência, `estimatedArrivalAt = departureAt + max(route.estimatedDuration, maiorOffsetDeParada)`, e os horários das paradas são derivados dos offsets do template.

### Preview e criação

```mermaid theme={null}
flowchart TD
    PREVIEW["Preview calcula ocorrências do horizonte"] --> STATUS["Cada ocorrência recebe status e motivo"]
    STATUS --> SELECT["Operador escolhe as ocorrências desejadas"]
    SELECT --> CREATE["Programação é criada"]
    CREATE --> TRIPS["Ocorrências escolhidas são materializadas"]
```

* **Preview** calcula todo o horizonte de 90 dias e devolve, por ocorrência, `departureAt`, `estimatedArrivalAt`, `status` e uma descrição.
* **Criação** materializa **somente** as `occurrences` escolhidas pelo cliente e salva a programação. Candidatas conflitantes/duplicadas são ignoradas.

### Avaliação das candidatas

Cada viagem candidata recebe um status antes de ser criada:

| Status           | Quando                                                                         |
| ---------------- | ------------------------------------------------------------------------------ |
| `MATERIALIZABLE` | Sem duplicidade nem conflito — será criada.                                    |
| `DUPLICATE`      | Já existe uma viagem com a mesma chave.                                        |
| `CONFLICT`       | Sobreposição de horário com outra viagem que compartilha veículo ou motorista. |

A chave de agendamento é `companyId | departureAt | routeId | vehicleId | driverId`. Conflitos são detectados contra viagens `SCHEDULED`/`IN_PROGRESS` cujo intervalo `[departureAt, estimatedArrivalAt)` se sobrepõe.

<Info>
  Durante a materialização, candidatas `DUPLICATE` e `CONFLICT` são ignoradas. Somente as `MATERIALIZABLE` são criadas.
</Info>

### Idempotência

A idempotência é baseada na chave `companyId | departureAt | routeId | vehicleId | driverId`. Uma mesma viagem não é materializada duas vezes.

### Criação das viagens

As viagens `MATERIALIZABLE` são criadas junto com suas paradas e itinerários.

## Rotina diária de materialização

Uma rotina diária percorre as programações `ACTIVE` e rematerializa cada uma sobre o horizonte móvel de 90 dias, estendendo a cobertura conforme o tempo avança. Programações `PAUSED`/`ARCHIVED` são ignoradas. Falhas em uma programação não abortam as demais, e a idempotência impede a recriação de viagens já existentes.

## Capacidades OPS

| Capacidade           | Descrição                                                  |
| -------------------- | ---------------------------------------------------------- |
| Listar programações  | Lista programações recorrentes                             |
| Detalhar programação | Detalha uma programação                                    |
| Preview              | Calcula ocorrências do horizonte com status                |
| Criar programação    | Cria a programação e materializa as ocorrências escolhidas |
| Renomear programação | Atualiza o `name`                                          |
| Pausar               | Pausa a programação                                        |
| Retomar              | Retoma a programação                                       |
| Arquivar             | Arquiva a programação                                      |
