# The pipeline board

`#/pipeline` is a column per stage and a card per opportunity, reading the same records as the deals sheet and the relationship view. Moving a card is not a display change: it calls `move`, the stage rules are consulted, and the move either happens and is audited, or is declined with a reason.

- **Status:** Available
- **Audience:** both
- **In the app:** #/pipeline, #/data
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/sales/pipeline/

## What a column and a card are

Each column is a stage; each card is one opportunity with its value, its person or company, and whatever marks it as needing attention. The board is a view, not a store — the authority is the record, which is why the same deal looks the same on `#/data`, on the person's relationship view and to the Assistant's `list_opportunities`.

This page does not print the stage names. The board itself is the authority for the vocabulary in your workspace, and a list written down here that drifts from it would be worse than no list at all. What is constant is the shape: ordered stages, a rule governing entry to each, and two terminal outcomes covered in [closing a deal](/docs/sales/won-and-lost/).

## What moving a card does

1. Drag a card to another column, or move it from the record.
   - Result: `move` is called with the target stage. Nothing has changed yet.
2. The stage rules are evaluated against the deal as it stands.
   - Result: Either the move is permitted, or it is declined with the specific thing that is absent. A decline leaves the card where it was.
3. On success the stage is written and the change is audited.
   - Result: The decision log holds what moved, who moved it and under which rule — including refusals, because a refusal is a decision.
4. Anything the new stage implies is raised.
   - Result: Typically a follow-up with a reason and a due time, so the next commitment is a record rather than somebody's memory.

> **Note** A refusal is not a bug report. Read what it names as missing — that is the fastest description of what the deal still needs. [Stage rules](/docs/sales/stage-rules/) covers each one.

## Counting on a board, honestly

Every number on the board — the count per column, the value per column — is computed in the database rather than over whatever page of rows the screen happens to be holding. That distinction is not pedantry. Elsewhere in this product a list that read a fixed slice of rows and did its counting, filtering and paging in Python over that slice reported a tab as empty when it was not, and a total that stopped at the slice.

- Counts come from one grouped query, so they describe the workspace and not the page.
- Filtering and paging happen in SQL, so page five holds what page five should hold.
- A search term containing `%` or `_` is matched as a character, not as a wildcard.
- Two currencies are never added together into one figure.

If a board total ever disagrees with the deals sheet, treat that as a defect worth reporting rather than a rounding difference — see [headline numbers that stop at the page size](/research/counting-past-the-limit/).

## The board for two audiences

The Owner and a customer see the same board over the same implementation. A customer session reaches it through the tenant facade, which rewrites the path; anything the facade does not recognise is refused rather than guessed at. What differs is volume, not capability: a plan bounds how much a workspace may do, never which screens exist.

## Questions

### Why did my card snap back to its old column?

A stage rule declined the move. The message names what the target stage requires and the deal does not have; supply that and the same move goes through.

### Does moving a card notify the customer?

No. A stage change is an internal fact. Anything the customer sees is a message, and messages go out under the autonomy rules of their channel like every other outbound.

### Can I work the pipeline from the grid instead?

Yes. The deals sheet in `#/data` edits the same records through the same service, which means the same stage rules apply there. The grid is a different view of one truth, not a bypass.

## Related

- [Sales in Connect](https://connectbyjbrh.com/docs/sales/)
- [Opportunities: the deal record](https://connectbyjbrh.com/docs/sales/opportunities/)
- [Stage rules and refusals](https://connectbyjbrh.com/docs/sales/stage-rules/)
- [Moving a deal from stage to stage, end to end](https://connectbyjbrh.com/docs/workflows/move-opportunity/)
- [Headline numbers that stop at the page size](https://connectbyjbrh.com/research/counting-past-the-limit/)
- [Sales for the Owner and for a customer](https://connectbyjbrh.com/docs/sales/sales-owner-tenant/)

## What this page is based on

- docs-source/sources/CHANNELS.md §5 and §6 — query-cost defects and the sales verbs
- docs-source/sources/GENERAL.md §1 and §11 — the tenant facade and measured query costs
- Connect capability registry (docs-source/facts.py)
