> ## 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.

# Seat Availability

> TripSeatSegment: controle de ocupação por segmento; disponibilidade = capacidade do veículo − assentos vendidos.

O **TripSeatSegment** controla a ocupação de assentos em nível de segmento. Cada registro é criado **apenas quando um ticket é vendido**, e a regra de unicidade impede que um assento seja vendido duas vezes para o mesmo segmento.

## Campos

| Campo               | Tipo     | Descrição                                              |
| ------------------- | -------- | ------------------------------------------------------ |
| `tripSeatSegmentId` | UUID     | Identificador único                                    |
| `tripId`            | UUID     | Viagem                                                 |
| `seatId`            | UUID     | Assento do veículo                                     |
| `segmentOrder`      | integer  | Número do segmento                                     |
| `ticketId`          | UUID     | Ticket que ocupa este assento neste segmento           |
| `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                             |

<Warning>
  Diferente de um modelo de pré-alocação, os TripSeatSegments **não são criados antecipadamente**. Eles só existem quando um ticket é vendido. A ausência de registro para um `[tripId, seatId, segmentOrder]` significa que o assento está **livre** naquele segmento.
</Warning>

## Prevenção de venda dupla

A chave de ocupação é `tripId + seatId + segmentOrder`. Uma segunda venda para a mesma combinação é rejeitada como assento já ocupado.

## Exemplo prático

Considere uma viagem SP → Campinas → Ribeirão com 2 segmentos:

| Segmento | Trecho              |
| -------- | ------------------- |
| 1        | SP → Campinas       |
| 2        | Campinas → Ribeirão |

### Cenário: Passageiro A compra SP → Ribeirão (assento 5)

| tripId | seatId | segmentOrder | ticketId |
| ------ | ------ | ------------ | -------- |
| trip-1 | seat-5 | 1            | ticket-A |
| trip-1 | seat-5 | 2            | ticket-A |

O assento 5 está ocupado nos dois segmentos. Ninguém mais pode comprá-lo para qualquer trecho desta viagem.

### Cenário: Compartilhamento de assento em trechos distintos

Se Passageiro A compra apenas SP → Campinas (segmento 1):

| tripId | seatId | segmentOrder | ticketId |
| ------ | ------ | ------------ | -------- |
| trip-1 | seat-5 | 1            | ticket-A |

O assento 5 no segmento 2 (Campinas → Ribeirão) **não tem registro**, portanto está livre. Passageiro B pode comprá-lo:

| tripId | seatId | segmentOrder | ticketId |
| ------ | ------ | ------------ | -------- |
| trip-1 | seat-5 | 1            | ticket-A |
| trip-1 | seat-5 | 2            | ticket-B |

<Tip>
  Esse modelo permite maximizar a ocupação do veículo — o mesmo assento físico pode ser utilizado por passageiros diferentes em trechos não-sobrepostos.
</Tip>

***

## Disponibilidade de um itinerário

A contagem de assentos disponíveis para um itinerário é calculada como **capacidade do veículo − assentos já vendidos no range de segmentos**.

Onde `vehicle_capacity` é a contagem de assentos ativos do veículo. A disponibilidade é derivada das vendas a cada consulta.

### Faixas de disponibilidade

A busca de ofertas classifica `availableSeats` em uma faixa (`AvailableSeatsStatus`):

| Faixa       | Condição                   |
| ----------- | -------------------------- |
| `SOLD_OUT`  | `availableSeats <= 0`      |
| `LIMITED`   | `1 <= availableSeats <= 5` |
| `AVAILABLE` | `availableSeats > 5`       |

<Info>
  A busca de ofertas (offerings) é paginada por cursor e retorna **somente** itinerários com `availableSeats > 0`. Itinerários esgotados ficam fora dos resultados.
</Info>

### Regra fundamental

Um assento conta como disponível para um itinerário se **nenhum** dos segmentos entre o `stopOrder` da parada de embarque (inclusive) e o `stopOrder` da parada de desembarque (exclusivo) possui um TripSeatSegment para aquele assento.

```mermaid theme={null}
flowchart TD
    Q[Query: assento 5 livre<br/>para SP → Ribeirão?<br/>segmentos 0 e 1]
    Q --> C1{Existe segment<br/>trip-1, seat-5, seg 0?}
    Q --> C2{Existe segment<br/>trip-1, seat-5, seg 1?}

    C1 -->|Não| OK1[Seg 0: livre]
    C1 -->|Sim| X[INDISPONÍVEL]
    C2 -->|Não| OK2[Seg 1: livre]
    C2 -->|Sim| X

    OK1 --> R{Todos livres?}
    OK2 --> R
    R -->|Sim| FINAL[DISPONÍVEL]
```

## Mapa de assentos

O mapa de assentos de um itinerário lista os assentos do veículo por andar. Cada assento é marcado como:

* `AVAILABLE` — o assento está ativo (`status = AVAILABLE`) **e** não possui nenhum TripSeatSegment no range do itinerário.
* `UNAVAILABLE` — o assento está inativo/bloqueado **ou** já ocupado em algum segmento do range.

***

## Reserva de assentos

Ao criar um Order com tickets, o DEVMOB reserva um TripSeatSegment por segmento entre as paradas do itinerário. Se algum segmento já estiver ocupado, a venda é rejeitada e nenhum trecho parcial é reservado.
