# Tours & inventory (Phase 05)

A tour/departure is the centre of group operation and is a **separate entity**
from bookings: a *group* booking relates to a tour; an *individual* booking never
does, regardless of passenger count.

## Derived, limiting-resource capacity

Each package declares **requirements**; each mandatory requirement consumes
inventory pools. The **sellable capacity is derived**, never a manual counter:

```
capacity(package) = min over mandatory requirements of  floor(requirement_availability / units_per_passenger)
requirement_availability = Σ available across the requirement's pools   (alternatives sum)
pool.available = capacity − blocked − active holds − consumptions
```

- **Alternative** hotels → one requirement, several pools → availabilities **sum**.
- **Consecutive** hotels → several mandatory requirements → the **minimum** wins.

Example: hotel 60, bus 50, mandatory activity 45 → **45**. The dashboard reports
the limiting resource (`InventoryService::limitingResource`).

## No overselling

`HoldService::place` opens a transaction, **locks every pool** the package
touches (`lockForUpdate`), then allocates. Two concurrent requests for the last
seat cannot both succeed — the second recomputes availability under the lock and
is refused (`NoAvailabilityException`). We never trust prior UI validation.

## Holds → consumptions, idempotent expiry

A **hold** is a temporary, expiring reservation. **Confirm** converts its
allocations into a **consumption** (totals unchanged, availability consistent) and
is idempotent. **Expiry** flips an active hold once, releasing the seat exactly
once; `expireDue()` is a safe, repeatable batch job.

## Per-passenger operation & transfers

`tour_passengers` gives every traveler their own operational identity and four
independent states, even sharing a booking. A **transfer** replaces the active
traveler **without deleting** the previous one (kept, `is_active=false`), moves
authorized assignments (seats) to the replacement, keeps the consumption, and is
audited in `passenger_transfers` with a snapshot. Future QR/access invalidation
lands in phase 09.

## Deferred

Provider costs/margins are wired in phase 07; final reports in phase 08. The
tables here (`transports`, `waitlist_entries`, provider ids) are the contracts.

## API

`GET/POST /tenant/tours` (permission `tours.view` / `tours.manage`),
`GET /tenant/tours/{uuid}` — returns pools (with derived availability) and each
package's sellable capacity + limiting resource.
