feat/mrr-tables
safe6662df4 · incrementalpre-PRreviewed 2026-08-10 18:15 UTC0H · 0M · 2L · 4I- Purpose
- Build PostHog analytics dashboards for MRR tracking — hierarchical pivot tables and trend lines for Batu's recurring revenue.
- Goal
- Codify MRR taxonomy (recurring vs one-time), trend line graphs, and coverage gap analysis in Terraform PostHog IaC.
- Sub-goals
- SG-1: MRR dashboard v2 with hierarchical product/org tables
- SG-2: Monthly trend line graphs by product and by plan (Terraform-codified)
- SG-3: Unify taxonomy to recurring/one-time (drop false 'subs' product)
- SG-4: DRY shared CTEs and fix t=0 fallback classification
- What
- Extracted d3_mon_cte (monitoring-RPU CTE) as a shared Terraform local to eliminate duplication between mrr_coverage_gap and d3_mrr_monthly_base. Fixed t=0 fallback: when an org has a base subscription but zero downloads in a month, the base fee is now correctly classified as recurring (monitoreo_credit) instead of one-time (descarga). Widened churn tile to full-width to avoid layout gap after removing the subs tile. Renamed mrr_monthly_base → d3_mrr_monthly_base for namespace consistency.
- Why
- Four rounds of review polish on the MRR dashboard: the t=0 bug caused base subscription fees to be misclassified as one-time downloads when no RPU downloads occurred in a billing month. The DRY refactor reduces maintenance surface.
- Areas
- infra/posthog/dashboards.tf+14−27infra/posthog/insights.tf+170−368
- Blast
- 2 files, +184/-395 across infra/posthog/ (net reduction from dropping static tables in earlier commits). Analytics IaC only — no application code, no database schema, no API surface affected.
Findings · 6
tests2
No HogQL query validation in CI — errors only surface in PostHog UI
infra/posthog/insights.tf
The t=0 fix and DRY refactor are HogQL string changes with no automated syntax/semantic validation before terraform apply. A malformed query fails silently as an error tile. Consider a PostHog query API smoke-check in CI if these dashboards become more critical.
DRY refactor functional equivalence unverified without rendered diff
infra/posthog/insights.tf
Extracting d3_mon_cte into a Terraform local changes SQL composition at plan time. A terraform plan output or local render script comparing before/after strings would confirm interpolation is identical to the original inline CTE.
improvement4
Trailing newline in d3_mon_cte produces dangling comma on its own line
infra/posthog/insights.tf
The heredoc ends with ')\n', so interpolation as '${local.d3_mon_cte},' emits the comma on a blank line after the closing paren. SQL is valid but formatting is inconsistent with hand-written CTEs. Stripping the trailing newline (trimspace() or adjusting EOT placement) would keep the comma adjacent to the paren: 'mon AS (\n...\n),'.
d3_mon_cte uses SELECT DISTINCT where a semi-join would be clearer
infra/posthog/insights.tf
SELECT DISTINCT uc.contract_number with an INNER JOIN deduplicates by pulling all matching rows then discarding duplicates. An EXISTS semi-join expresses intent more directly and avoids the implicit DISTINCT-on-joined-columns footgun if the join ever grows additional columns.
Empty-string guard could include IS NOT NULL for explicitness
infra/posthog/insights.tf
ClickHouse three-valued logic: contract_number != '' passes NULLs through. If contract_number can be NULL, adding notEmpty(contract_number) or an explicit IS NOT NULL makes the guard match intent.
t=0 fallback branches asymmetric — inline comment would help future readers
infra/posthog/insights.tf
After the fix, monitoreo_credit gets v as the t=0 fallback and descarga gets 0. A brief inline comment on each arm (e.g. '-- full base fee to monitoring when t=0') would make the business rule legible without tracing the bug history.