Pipeline Management

How the sales pipeline works day-to-day — moving deals, automatic probability, forecasting and the kanban board.

Pipeline Management

The pipeline is the sum of all your open opportunities. HotCRM gives you a governed pipeline where stage progression, win probability and forecast values are all kept in sync automatically — reps focus on selling, not on data hygiene.

How probability is set

Win probability is set from the stage automatically, so every rep's forecast uses the same numbers:

StageDefault win probability
Prospecting10 %
Qualification25 %
Needs Analysis40 %
Proposal60 %
Negotiation80 %
Closed Won100 %
Closed Lost0 %

You can override the probability manually on an individual deal if you have a special situation, but the override is reset the next time the stage changes. This prevents reps from inflating their forecast by hand.

Admins can adjust the percentages per stage — see Administration › Automation.

How expected revenue is calculated

Expected Revenue = Amount × Probability ÷ 100

This number is the heart of the weighted forecast. It's recalculated automatically every time the amount or probability changes (including the auto-updates from stage changes).

The weighted forecast is a list-view total, not a dashboard number. The Open Deals and All Opportunities views on Opportunities each carry an Expected Revenue column with a column sum (src/views/opportunity.view.ts), and that sum over the open pipeline is the weighted forecast.

No dashboard can give you the same figure. The Sales Performance dashboard (sales_dashboard) reads the opportunity_metrics dataset, and that dataset declares no measure over expected_revenue — every amount measure it exposes (Total Amount, Avg Deal Size, Won Revenue, Lost Revenue) reads the raw amount field. So its Total Pipeline tile is the unweighted open pipeline; the two numbers differ by the probability weighting, which is the whole point of the calculation above.

The pipeline kanban view

The kanban board is the Sales Pipeline view on Opportunities (pipeline_kanban), and the sidebar entry that opens it reads Pipeline. It shows the pipeline one column per stage, open deals only: the board carries its own filter — stage not_in [closed_won, closed_lost] in src/views/opportunity.view.ts — so only the five active stages, Prospecting, Qualification, Needs Analysis, Proposal and Negotiation, can ever hold a card. Closed business is not hidden, it is elsewhere: All Opportunities and the Sales Performance dashboard both include it. Whether the two closed stages are drawn as permanently empty columns or left off the board altogether is the console's rendering choice and not something this app declares — either way there is no closed deal on this board to find.

Each card carries the four fields the board binds (kanban.columns):

  • Opportunity name
  • Account
  • Amount
  • Close date

Owner is not on the card. owner_id sits in the view's top-level columns list, which is what the grid renderings read, but the card binding names those four fields and stops there. To see the owner next to a deal, use All Opportunities, which carries an Owner column, or the Deal Cards gallery, whose cards do show it.

To advance a deal, just drag the card to the next column. The stage rules are advice, not a gate. opportunity_stage_progression (src/objects/opportunity.object.ts) declares which moves are legal — Prospecting straight to Closed Won is not one of them — but the rule carries warning severity, so a move outside the table writes one line to the server log, "Invalid opportunity stage transition", and the save still goes through. Nothing in the board stops you. What the log buys you is that a bad import or a misbehaving integration can be found afterwards; see Administration › State Machines for what the table is and is not good for.

At the top of each column you'll see one number: the sum of Amount across that column's deals — the unweighted total for that stage. One is all a kanban column can carry, by design: a board declares a single summarizeField (src/views/opportunity.view.ts), and this board binds it to amount.

The board has no weighted total. As How expected revenue is calculated says above, the weighted forecast is a list-view total: the Expected Revenue column sum on Open Deals and All Opportunities.

Pipeline health signals

A few derived fields surface deal risk so you can act on them in your weekly review:

SignalWhat it tells you
Days in current stage > 30Deal is stagnant — push or close it.
Close date in the past AND stage still openForecast is wrong; reset the date or accept the loss.
Amount > $500K with no submitted approvalDiscount approval is required before this can close.
Closed lost with no loss reasonThe deal's story is gone — nothing can learn from it.

The AI assistant surfaces at-risk deals when you ask "what's slipping?" or "how does my pipeline look?"

Pipeline reports worth bookmarking

Only the first of these is on the sidebar. There is no Reports group: the reports group is called Insights (src/apps/crm.app.ts), and it pins three reports — Pipeline Coverage, Lead Inflow and SLA Performance — alongside the CRM Overview dashboard and Forecasts. The other four below are opened from the reports screen. Names here are the labels the report library lists, which is not always the shorter name on the nav entry.

ReportWhat it shows
Pipeline Coverage by Forecast × QuarterAre we covering 3x the quota for the upcoming quarter? A matrix of open pipeline: forecast category down the rows, close quarter across the columns. The sidebar entry for it reads Pipeline Coverage.
Opportunity Funnel by Owner → StagePer-rep funnel health — spot leaky stages.
Opportunities by StageBar chart of pipeline by stage.
Won Opportunities by OwnerLeaderboard for quarter-end recognition.
Customer Churn SignalsOpen cases + low NPS on existing customers = churn risk.

See Analytics › Reports for details.

CadenceWhat to do
DailyOpen the Pipeline board. Find stalled cards (in-stage > 14 days). Push or close.
WeeklyRun Pipeline Coverage. Ask the AI assistant: "what's at risk?"
MonthlyRun Opportunity Funnel by Owner → Stage. Coach reps with leaky stages 1:1.
Quarter-endRun Won Opportunities by Owner for commissions. Archive lost deals with a loss reason.

Forecasting roll-up

The Sales Manager / Director view of the forecast is built from:

  • The Opportunity Metrics dataset (opportunity_metrics) — measure Total Amount (sum of amount), dimension Stage
  • The Sales Performance dashboard (sales_dashboard) — widgets for pipeline by stage, win rate, and open pipeline by owner
  • The Pipeline Coverage report (pipeline_coverage_by_quarter, whose own label reads Pipeline Coverage by Forecast × Quarter) — a matrix of open pipeline: forecast category down the rows, close quarter across the columns

Together they answer: "do we have enough pipeline to make the quarter, and where are the risks?"

What that dashboard will not give you is a top deals ranking, and no renaming would fix it: a dashboard table binds to an analytics dataset and can only aggregate — it cannot list raw records (ADR-0021). The Top Open Opportunities table that once held that slot was replaced by Open Pipeline by Owner, a per-rep ranking, for exactly that reason; the Row 5 comment in src/dashboards/sales.dashboard.ts records the swap. For a deal-by-deal ranking, open an opportunity list view.

Tips for sales reps

  • ✅ Move stage promptly — your forecast is wrong if your stage is wrong.
  • ✅ Use Next Steps — your manager reads it every Monday standup.
  • ❌ Don't slide the close date to hide slippage; use Closed Lost with a reason.

Tips for sales managers

  • ✅ Run Opportunity Funnel by Owner → Stage monthly to catch reps with leaky funnels.
  • ✅ Use Pipeline Coverage in QBRs to set the next quarter's targets.
  • ✅ Coach reps to fill in Loss Reason and Loss Details on every closed-lost deal — it is the only competitive data the app keeps.

Tips for admins

  • Add or remove stages? You need to update three places in the source, none of them a Setup screen: the OPPORTUNITY_STAGE_OPTIONS picklist the stage field renders (src/objects/_picklists.ts), the STAGE_PROBABILITY map that sets probabilities inside the opportunity_lifecycle hook (src/objects/opportunity.hook.ts), and the opportunity_stage_progression state-machine validation rule that controls transitions (src/objects/opportunity.object.ts). See Customization › Extending Objects.
  • The $100K large deal notification threshold is not a Setup field either: it is the CEL start condition of the opportunity_won_alert flow — record.amount >= 100000 in src/flows/opportunity-won-alert.flow.ts. Who gets the alert is that flow's notify node, whose recipients list is the single entry {record.owner_id} — the deal owner alone.

On this page