ETCR (Beta) is a leadership scoreboard in Signal (Power Digital's internal BI web app) at route /etcr that shows, for every Account Director, Group Director, and Division, the Expansion-to-Churn Ratio — closed service-expansion MRR divided by confirmed churn MRR — measured against the company-wide 60% goal, plus forecasted "floor" and "ceiling" versions of the ratio built from pipeline and expected churn. It is visible to any Signal user with an elevated role (Team Lead and above; base-tier Members are redirected away) and answers the question "which leaders are covering the revenue they lose to churn with expansion revenue, and which are falling behind the 60% goal?" All numbers come from an upstream ETCR data pipeline maintained by the AI/ML team (owner: Lily) outside the Signal repo; Signal reads the pipeline's four monthly output tables and computes ratios and aggregations in the browser. The view is read-only.
Field | Value |
Route | /etcr |
Access | Team Lead+ (any elevated role; base-tier Members are redirected to /summary by the MemberAllowedRoute guard) |
Nav section | People → "ETCR (Beta)" |
Primary data sources | Upstream ETCR pipeline (AI/ML team, owner: Lily) — four monthly tables (FINAL_ETCR_MONTHLY_AD / _GD / _DIVISION / _DIVISION_DETAILED); all ratios/aggregations computed client-side |
Writes | None to business data. Browser-only UI preference (sessionStorage key etcr.showDetails) + automatic page-view usage event (module etcr) written to Signal's own records |
Key code refs | src/views/ETCRView.tsx; src/App.tsx:389 (nav) and :1172 (route guard); src/services/api.ts:1857 (getEtcr); server/index.ts:11355 (GET /api/etcr) |
Last verified | staging @ 98df0c4, verified 2026-07-07 |
Purpose
ETCR stands for Expansion-to-Churn Ratio: closed service-expansion monthly recurring revenue (MRR) divided by confirmed churned MRR. Power Digital loses recurring revenue every month when clients churn and recovers it by expanding services with clients that stay; the company goal is an ETCR of 60% — for every dollar of confirmed MRR lost, at least 60 cents won back through expansion. The ETCR (Beta) module in Signal makes that accountability visible at the person level: it shows the ratio for each Account Director, each Group Director, and each Division, colored against the 60% goal, and pairs the actuals with a forecasted ETCR Floor (only what is already closed vs. all churn expected) and ETCR Ceiling (if all commit + best-case pipeline closes vs. all churn expected), so leaders can see whether a month or year is trending toward or away from goal before it ends. ETCR is the primary outcome metric of Power Digital's Service Expansion initiative. Note: "Expansion-to-Churn Ratio" as the expansion of the acronym is consistent with the math but is not spelled out anywhere in the Signal codebase.
Access & visibility
The ETCR (Beta) view in Signal is reachable at /etcr and appears in the left navigation under the People section with the label "ETCR (Beta)" (src/App.tsx:389). Gate mechanics as of staging @ 98df0c4 (verified 2026-07-07):
Route guard: the /etcr route is wrapped in MemberAllowedRoute (src/App.tsx:1172, guard defined around src/App.tsx:825). This guard blocks only the base tier: if the signed-in user is a "Member," they are redirected to /summary. Any elevated user falls through and can load the page.
Who counts as a Member: a Member is a signed-in user with none of the elevated role flags — not a Team Lead, not an Admin, not Gandalf, not Sauron, not Growth-allowed, and (added in the July 2026 Growth-access restructure) not a Performance Radar viewer and not a Growth access manager (src/context/AuthContext.tsx:634). Role flags come from Signal's own user records (the app_users table: is_team_lead, is_admin, is_gandalf), resolved at sign-in and cached in the browser session.
Nav flag: the "ETCR (Beta)" nav link has no dedicated permission flag of its own — it is visible to every user who passes the base nav filter. Members' navigation is stripped down to exactly Summary and Employees, so Members never see the ETCR link; every non-Member (Team Lead and above, plus Growth-capability users) sees it under People.
How access is granted: there is no ETCR-specific grant. A user gets ETCR by holding any elevated role in Signal's user records (typically is_team_lead or is_admin set by a Signal admin on the Users screen). Practically the audience is Team Leads, Group Directors, admins, and leadership.
Backend: the single data endpoint GET /api/etcr requires authentication (requireAuth in server/index.ts:11355) but has no additional role check server-side; role enforcement for this view is frontend routing.
Data sources & lineage
The ETCR (Beta) view makes exactly one data request on page load: api.getEtcr() (src/services/api.ts:1857) → GET /api/etcr (server/index.ts:11355). The backend runs SELECT * on four monthly output tables of the upstream ETCR pipeline (schema NOVAX_CUSTOMER_MANAGEMENT.PROD_MODEL) and returns them unmodified. All filtering, aggregation, and ratio math then happens in the browser (src/views/ETCRView.tsx). The ETCR pipeline is built and owned by the AI/ML team (Lily) outside the Signal repo; the business-system origins of its inputs (what counts as confirmed churn, and where "Commit"/"Best Case" expansion pipeline stages come from) are not defined in the app repo.
On-screen element | Origin system | Code path | Refresh | Caveat |
Account Director tab (rows, cards, totals) | Upstream ETCR pipeline (AI/ML team, owner: Lily) — table FINAL_ETCR_MONTHLY_AD, one row per AD per month | api.getEtcr() → GET /api/etcr → executeQuery (server/index.ts:11355) | Fetched once per page load; upstream refresh cadence not defined in the app repo | Signal reads only; no ETCR math is done upstream of what the tables contain |
Group Director tab | Upstream ETCR pipeline — FINAL_ETCR_MONTHLY_GD, one row per GD per month | Same single GET /api/etcr response (gd key) | Same | Same |
Division tab | Upstream ETCR pipeline — FINAL_ETCR_MONTHLY_DIVISION, one row per Division per month | Same response (division key) | Same | Same |
Division drill-down (per-employee sub-table inside an expanded division row) | Upstream ETCR pipeline — FINAL_ETCR_MONTHLY_DIVISION_DETAILED (Employee + Role rows per division per month) | Same response (divisionDetailed key); fetched fail-soft (server/index.ts:11366) | Same | If this table errors, the rest of the page still loads and division rows expand to an empty detail |
Summary cards (Total ETCR, SE Closed MRR, Confirmed Churn MRR, Goal 60%) | Computed client-side from the pipeline rows | summaryTotals in src/views/ETCRView.tsx:333 | Recomputed on every filter change | SE Closed MRR = Σ(TOTAL_RETAINER_MRR + TOTAL_PROJECT_MRR ÷ 6); Total ETCR = SE Closed ÷ Σ CONFIRMED_CHURN_MRR. The ÷6 project conversion and the 60% goal (ETCR_GOAL = 0.60, ETCRView.tsx:31) are frontend code constants as of Jul 2026 |
Forecast-inputs drawer (Forecasted Expansion MRR, Forecasted Churn MRR, Fcst. ETCR Ceiling, Fcst. ETCR Floor) | Pipeline columns PROJECTED_EXPANSION_MRR and PROJECTED_CHURN_MRR summed client-side; ratios computed client-side | summaryTotals in ETCRView.tsx:338-352 | Recomputed on filter change | Ceiling card is a churn-weighted average of row-level PROJECTED_ETCR_CEILING values (Σ(ceiling × projected churn) ÷ Σ projected churn), not Expansion ÷ Churn; Floor = SE Closed ÷ Σ PROJECTED_CHURN_MRR |
YTD cards (YTD Forecasted Expansion/Churn MRR, YTD Fcst. ETCR Ceiling/Floor) | Computed client-side from pipeline rows for Jan → latest selected month of that calendar year | ytdTotals in ETCRView.tsx:355-390 | Recomputed on filter change | YTD Expansion = Σ(closed + commit + best-case, retainer + project÷6); YTD Churn = Σ FORECASTED_CHURN_MRR only (does not add confirmed churn); respects the person filter but ignores which specific months are date-filtered beyond the latest one |
Close Date and name filter options | Derived client-side from distinct values in the pipeline rows | dateOptions / nameOptions in ETCRView.tsx; date column auto-detected among CLOSE_DATE, CLOSE_DT, DATE, MONTH, MONTH_YEAR, PERIOD | Per page load | Defaults to the last calendar month; if that month is not yet in the data, the newest available month is used |
"Show forecast inputs" drawer open/closed state | Browser only | sessionStorage key etcr.showDetails (ETCRView.tsx:242-247) | Per browser tab session | Not stored server-side |
The ETCR (Beta) module uses no data from Signal's own user-entered records (team assignments, overrides, targets), no Google Sheets, no payroll systems, and no Nova. It also does not read Signal's global DataContext — the app-wide month selector does not affect this view; ETCR has its own Close Date filter.
Metrics & definitions
All metrics on the ETCR (Beta) view (/etcr in Signal). Dollar inputs come from the upstream ETCR pipeline's monthly tables (AI/ML team, owner: Lily); ratios are computed in the browser (src/views/ETCRView.tsx). The ÷6 divisor converts one-time project revenue into a monthly-recurring equivalent (assumed ~6-month amortization; a frontend code convention as of Jul 2026 — no code comment documents the rationale). The 60% goal is the frontend constant ETCR_GOAL = 0.60 (ETCRView.tsx:31), not read from any targets table.
ETCR (Expansion-to-Churn Ratio) — headline ratio per row: how much of confirmed churned MRR was offset by closed expansion MRR. Single-month view shows the pipeline's ETCR column as delivered; multi-month / all-dates views recompute it as Σ(TOTAL_RETAINER_MRR + TOTAL_PROJECT_MRR÷6) ÷ Σ CONFIRMED_CHURN_MRR. Green at ≥ 60%, red below (zero values uncolored).
SE Closed MRR — service-expansion revenue already closed, in MRR terms: TOTAL_RETAINER_MRR + TOTAL_PROJECT_MRR ÷ 6. Card sub-label reads "Retainer + Project / 6".
Retainer MRR / Project MRR (table columns) — the closed expansion dollars split by contract type, as delivered by the pipeline (TOTAL_RETAINER_MRR, TOTAL_PROJECT_MRR).
Confirmed Churn MRR — churned MRR already confirmed (CONFIRMED_CHURN_MRR, from the pipeline). The card shows "+ $X forecasted" when additional churn is expected.
Fcst. Churn / Forecasted Churn MRR — all churn expected: pipeline column PROJECTED_CHURN_MRR (single-month), or Σ(CONFIRMED_CHURN_MRR + FORECASTED_CHURN_MRR) when the view aggregates multiple months. Card sub-label reads "Confirmed + Forecasted".
Fcst. Expansion / Forecasted Expansion MRR — closed + pipeline expansion: pipeline column PROJECTED_EXPANSION_MRR (single-month), or Σ(closed + COMMIT_* + BEST_CASE_*, each retainer + project÷6) when aggregating. Card sub-label reads "Closed + Commit + Best Case". What qualifies as "Commit" vs "Best Case" is defined upstream, not in the app repo.
ETCR Floor (Fcst. ETCR Floor) — worst-case ratio: SE Closed MRR ÷ Forecasted Churn MRR (counts only already-closed expansion against all expected churn).
ETCR Ceiling (Fcst. ETCR Ceiling) — best-case ratio: Forecasted Expansion MRR ÷ Forecasted Churn MRR (assumes all commit + best-case pipeline closes). The summary-card version is a churn-weighted average of row-level ceilings.
Goal 60% card — gap to goal in percentage points: (Total ETCR − 0.60) × 100, labeled "At or above" (green) or "Below" (red).
YTD Forecasted Expansion / Churn MRR, YTD Fcst. ETCR Ceiling / Floor — the same forecast metrics summed across every month from January of the latest selected month's year through that month. YTD Churn sums only the FORECASTED_CHURN_MRR column. Pipeline-delivered *_YTD columns, when present, are cumulative and are taken from the latest month's row rather than summed.
How it's used
Real workflows on the ETCR (Beta) view (/etcr in Signal):
Monthly ETCR review of Account Directors. Open /etcr (defaults to last month's close date), stay on the Account Director tab. The table sorts by ETCR ascending by default, so the ADs covering the least of their churn with expansion sit at the top; rows below the 60% goal are highlighted. These are the coaching conversations for this month's 1:1s.
Find the source of a division's miss. Switch to the Division tab, spot the division below goal, click its row. An inline drill-down lists every employee and role in that division with their own ETCR, independently sortable — showing whether the gap is one person's book or systemic.
Judge whether the current month can still hit goal. Click "Show forecast inputs." If the Fcst. ETCR Ceiling (all commit + best-case pipeline closing) is above 60% but the Floor is below, the month is winnable — push the pipeline. If even the Ceiling is under 60%, expected churn cannot be offset; escalate retention instead.
Quarter or year-to-date accountability. Multi-select months in the Close Date filter for a quarter view — monthly dollars are summed and every ratio recomputed from the summed dollars (never averaged), and an on-screen note explains this — or read the YTD cards for the calendar-year position against 60%.
Prep a specific director's performance conversation. Filter to one AD/GD/Division by name; cards and table collapse to their book. Pair their confirmed churn dollars with their forecasted expansion to frame the ask: "you need $X of the commit pipeline to close to cover your churn."
What users can change here
Nothing — the ETCR (Beta) view is read-only. There are no edit, override, or annotation actions on /etcr, and nothing a user does here changes business data anywhere. The only persistence:
Browser-local UI preference: whether the "Show forecast inputs" drawer is open is saved in sessionStorage (key etcr.showDetails), per browser tab session only. It never leaves the browser.
Automatic usage logging: visiting /etcr writes a page_view event with module name etcr into Signal's own usage records (entered automatically by the app, via the app-wide usage-tracking hook src/hooks/useUsageTracking.ts). This is telemetry for Signal's internal Analytics dashboard, not user-editable data.
Caveats & data quality
Known caveats for the ETCR (Beta) view (/etcr in Signal), as of staging @ 98df0c4 (verified 2026-07-07):
Beta. A hardcoded "BETA" badge renders next to the tabs and the nav label is "ETCR (Beta)". Metric definitions and layout may still change.
The 60% goal is a frontend code constant (ETCR_GOAL = 0.60, src/views/ETCRView.tsx:31, as of Jul 2026). It is not read from Signal's KPI-targets records and is not role- or division-specific. If the company target moves, a code deploy is required.
The ÷6 project-MRR conversion is a frontend code constant (as of Jul 2026): project revenue is divided by 6 to approximate monthly-recurring value. No code comment or repo doc states the rationale; confirm with the metric owner (Lily / Service Expansion team) before treating the formula as policy.
Upstream definitions are not in the app repo. What qualifies as "Confirmed Churn" vs "Forecasted Churn," and how "Commit" vs "Best Case" pipeline stages are sourced, is defined in the upstream ETCR pipeline owned by the AI/ML team (Lily). Not defined in the app repo.
Refresh cadence unknown. The page fetches once per load; the update cadence of the four upstream FINAL_ETCR_MONTHLY_* tables is not visible in the app repo. Not defined in the app repo.
Division drill-down is fail-soft. If the FINAL_ETCR_MONTHLY_DIVISION_DETAILED table is unavailable, the page still loads but expanded division rows show an empty detail (a warning is logged server-side).
Default month logic. The Close Date filter defaults to the last calendar month; early in a month, before the upstream pipeline publishes it, the newest available month is used instead.
Clearing all dates aggregates everything. With no Close Date selected ("All Dates"), the table aggregates each person/division across every month in the data — the numbers are all-time sums with recomputed ratios, not a single month.
Two summary formulas differ subtly from the table. The Fcst. ETCR Ceiling summary card is a churn-weighted average of row-level ceilings, and the YTD Forecasted Churn card sums only the FORECASTED_CHURN_MRR column (not confirmed + forecasted). Whether the latter matches the intended YTD definition is not documented in the repo.
Zero-valued ETCR is uncolored. Cells and rows are flagged red only when ETCR is non-zero and below 60%; a 0% ETCR (e.g., no churn recorded) gets no color and sorts first ascending.
Per-client ETCR does not exist yet. TODO(etcr): wire when Lily's pipeline ships markers remain in server/predictions.ts and src/services/api.ts; the Portfolio Review view renders "—" placeholders for per-client ETCR and Confirmed Churn MRR. Do not expect client-level ETCR anywhere in Signal today.
Planned loading rework. Internal loading-assessment docs (docs/loading-assessment/) flag this view for refactor (lazy-load the drill-down table, skeleton states); loading behavior may change.
Related views
Service Expansion (/predictions/se) — surfaces which clients to expand; ETCR (Beta) measures whether expansion actually closed and covered churn. ETCR is the outcome metric of the Service Expansion initiative.
Churn Risk (/predictions/churn) and Division Forecast (/predictions/retention) — the churn side of the story. Note the "forecasted churn" inside ETCR's floor/ceiling comes from the upstream ETCR pipeline, not from Signal's churn-prediction models.
Portfolio Review (/predictions/portfolio) — contains placeholder columns for Per-Client ETCR and Confirmed Churn MRR that render as "—" with tooltip "ETCR pipeline pending — owned by Lily". When per-client ETCR ships, Portfolio Review becomes the client-level companion to the person-level ETCR (Beta) view.
KPI Targets (/kpi-targets, admin-only) — not connected today: the 60% ETCR goal is hardcoded in the frontend, not read from Signal's KPI-targets records.
Iris (in-app assistant) — recognizes the /etcr route, so questions asked in Iris chat from this page carry ETCR context.
Unlike most Signal views, ETCR (Beta) does not use the global month selector (DataContext); it has its own Close Date filter and its own single data fetch.
FAQ
Q: What does ETCR stand for and how is it calculated? A: ETCR is the Expansion-to-Churn Ratio: closed service-expansion MRR divided by confirmed churned MRR. In Signal's ETCR (Beta) view, closed expansion MRR = retainer MRR + project revenue ÷ 6 (the ÷6 converts one-time project revenue into a monthly-recurring equivalent; frontend code convention as of Jul 2026). Example: $60k of expansion closed against $100k of confirmed churn = 60% ETCR, which is exactly the company goal. Note the "Expansion-to-Churn Ratio" wording is consistent with the math but is not spelled out in the Signal codebase itself.
Q: Why can't I see the ETCR page in Signal? A: The /etcr route is blocked for base-tier Members — users with no elevated role. If you are a Member you are redirected to the Summary page and the "ETCR (Beta)" link does not appear in your navigation. Access comes with any elevated Signal role (Team Lead, Admin, and above), which is set in Signal's user records by a Signal admin. There is no ETCR-specific permission to request; ask your manager or a Signal admin about your role tier.
Q: What is the difference between ETCR Floor and ETCR Ceiling? A: Both are forward-looking versions of ETCR on the ETCR (Beta) view. The Floor is the worst case: only expansion already closed, divided by all churn expected (confirmed + forecasted) — the ratio if no more pipeline closes. The Ceiling is the best case: closed + commit + best-case pipeline expansion, divided by all churn expected — the ratio if everything in the pipeline closes. If the Ceiling is above 60% but the Floor is below, the period is still winnable by closing pipeline; if even the Ceiling is below 60%, expected churn cannot be offset by the current pipeline.
Q: Where do the ETCR numbers come from? Do they match Vena? A: The dollar inputs come from an upstream ETCR data pipeline built and owned by the AI/ML team (owner: Lily), outside the Signal codebase — Signal only reads the pipeline's four monthly output tables (per Account Director, Group Director, Division, and division-employee detail) and computes ratios in the browser. The exact definitions of confirmed churn, forecasted churn, and commit/best-case expansion stages live in that pipeline, not in the Signal app, so the ETCR view's churn dollars are not guaranteed to reconcile line-for-line with Vena revenue screens elsewhere in Signal. For questions about the input definitions, ask the AI/ML team (Lily).
Q: Why is the 60% goal used everywhere on the ETCR page, and can it be changed per division? A: 60% is the current company-wide goal and it is a hardcoded frontend constant (ETCR_GOAL = 0.60 in the code, as of Jul 2026). It is the same for every Account Director, Group Director, and Division, and it is not read from Signal's KPI Targets records — changing it requires a code deploy. Green/red coloring, row highlighting, and the "Goal 60%" card all key off this constant.
Q: Why does project revenue get divided by 6 on the ETCR view? A: The "SE Closed MRR" card and all ETCR ratios convert one-time project revenue into a monthly-recurring equivalent by dividing the project total by 6 (roughly a six-month amortization). This is a frontend code convention as of Jul 2026; no repo documentation states the business rationale, so confirm with the Service Expansion metric owner before quoting the formula as policy.
Q: I selected multiple months on the ETCR page — how are the numbers combined? A: When more than one Close Date is selected (or when all dates are cleared, which aggregates every month), the ETCR (Beta) view sums the monthly dollar values per person/division and then recomputes every ratio from the summed dollars — ratios are never averaged across months, so one strong month cannot mask a weak one. An on-screen note appears explaining this. Multi-month forecasted expansion is rebuilt as closed + commit + best-case dollars, and forecasted churn as confirmed + forecasted churn dollars, before the floor/ceiling ratios are recomputed.
Q: What do the YTD cards on the ETCR page cover? A: The YTD Forecasted Expansion MRR, YTD Forecasted Churn MRR, and YTD Fcst. ETCR Ceiling/Floor cards (inside the "Show forecast inputs" drawer) sum every month from January of the latest selected month's calendar year through that month — regardless of which specific months are selected in the Close Date filter. They do respect the person/division name filter. One nuance: YTD Forecasted Churn sums only the pipeline's forecasted-churn column, without adding confirmed churn.
Q: Can I see ETCR for a single client? A: No. Per-client ETCR does not exist in Signal yet. The Portfolio Review view (/predictions/portfolio) has Per-Client ETCR and Confirmed Churn MRR columns, but they render as "—" placeholders with the tooltip "ETCR pipeline pending — owned by Lily." The ETCR (Beta) view itself only goes down to person level (Account Director / Group Director) and, inside a division row, to individual employees within that division.
Q: I clicked a division on the ETCR page and the drill-down is empty — is that a bug? A: Not necessarily. The division drill-down comes from a separate upstream table (division-employee detail) that is loaded fail-soft: if that table is unavailable, the rest of the ETCR page still works but expanded division rows show no team members. The drill-down also honors the Close Date filter — if the selected months have no detail rows for that division, it shows "No records match your filters." If it stays empty across dates while the main table has data, report it to the Signal team; the detail table may be down upstream.
