# Timeline

One read of the household's life with cars: every ownership period with its approximate edges, arrival number, km and Moments, the wishlist, the header's stats and the years, with no plate, VIN or (by default) amount.

## What it does [#what-it-does]

The timeline is the household's life with cars (UX round 2, `docs/specs/ux-round-2.md` §Timeline): every car of the Organization the caller sees, current, sold or added from memory. `timeline.list` returns everything the life strip, the list, the header and the year rows draw; it writes nothing.

- **Periods.** One row per Ownership Period with its car (id, make, model, year), the cover's list-size preview (signed for 15 minutes), `open`, `from`/`to` as approximate dates (the bucket's widest bound and its precision, `@autofolio/domain/approx-date`), `endReason` (`sold` reads "Vendido" with a Disposal or an end reason `sold`; any other end reads "Saiu"), `arrivalNumber`, `km` and the car's Moments inside the period (not the dismissed ones).
- **Order.** Open periods first, then closed ones; each newest arrival first. On the seed: Corolla, M3, 911, then RS 5, Golf.
- **Arrival number.** The car's number in the household's life by its first period's start (the Golf is nº 1 on the seed). A sale never renumbers anyone. It is shown only in a car's chapter, never on rows or share cards.
- **Km with you.** The period's last reading minus its first, across a reset (RN07); without two readings, the period's `driven_km_estimate` with `estimate: true` ("cerca de"); else null.
- **Wishes** ("Próximo"), **stats** (cars ever owned, years of history as the union of every period so cars at once count once, and the first year) and **years** (every year from the first arrival to this one, newest first, with the cars owned and the Moments in it).
- **Amounts.** Only with `withAmounts: true`, and only on cars whose net-worth area the caller sees (owners and admins see every car): an open period's latest Valuation with its source, date and confidence (RN03), and a recorded sale's price, deal result and economic result (RF20, never "profit"). A sale's results also need the expenses area, since they are computed from that period's ledger. Everything else is `amounts: null`.

The life strip's rows are packed on the client by `packLanes` (`@autofolio/domain/lanes`): greedy by arrival, at most 3 rows, a car arriving the day another left shares its row, and a car that finds no row is returned in `more` for the "+N".

## Data and isolation [#data-and-isolation]

The timeline owns no table. It reads `vehicle` (archived cars left out), `ownership_period`, `odometer_reading`, `vehicle_photo`, `moment`, `disposal`, `valuation_snapshot` and, for a sale, the period's ledger, all as `app_tenant` under row-level security ([ADR-0009](/docs/adr/0009-row-level-security)): a Member gets only the cars granted to them, readings only with the odometer area, Valuations only with the net-worth area. The output schema strips anything it does not list, so plate, VIN and address never reach the wire.

## Procedures [#procedures]

| Procedure                          | Who          | Failures                                                 |
| ---------------------------------- | ------------ | -------------------------------------------------------- |
| `timeline.list` `{ withAmounts? }` | every Member | `INPUT_VALIDATION` only; a car not seen is simply absent |

## Key files [#key-files]

- [`packages/api/src/features/timeline/timeline.contract.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/timeline/timeline.contract.ts)
- [`packages/api/src/features/timeline/timeline.rules.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/timeline/timeline.rules.ts)
- [`packages/api/src/features/timeline/timeline.service.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/api/src/features/timeline/timeline.service.ts)
- [`packages/domain/src/lanes.ts`](https://github.com/CarlosZiegler/autofolio/blob/main/packages/domain/src/lanes.ts)

