monitoring(uk-payslip): drop 3 panels referencing undeployed data

Removed:
- Panel 10 "HMRC Tax Year Reconciliation — Individual Tax API"
  → references hmrc_sync.tax_year_snapshot schema. The hmrc-sync
    service / DB has not been deployed, so the panel always errored
    with "relation does not exist".
- Panel 14 "Meta payroll: bank deposit vs payslip net pay"
  → references payslip_ingest.external_meta_deposits, which is
    created by alembic migration 0007. The deployed payslip-ingest
    image is at 0005, so the table doesn't exist.
- Panel 15 "RSU vest reconciliation — payslip vs Schwab"
  → references payslip_ingest.rsu_vest_events, created by migration
    0008. Same image-staleness story.

Verified all 14 remaining panels return without error via Grafana
/api/ds/query. SQL for the removed panels is preserved in git history;
re-add when the data sources are actually deployed.
This commit is contained in:
Viktor Barzin 2026-04-25 23:56:03 +00:00
parent b2a25775aa
commit 53f555dc61

View file

@ -352,7 +352,7 @@
{
"id": 2,
"title": "Monthly cash flow (RSU stripped)",
"description": "Cash-only view: gross pay minus the RSU vest (cash_gross) and the bank-deposited net_pay. Tax and NI are not shown here because UK cumulative PAYE genuinely takes a YTD true-up chunk in vest months on top of the marginal RSU PAYE see Panel 11 for the full tax breakdown with the band-aware RSU split.",
"description": "Cash-only view: gross pay minus the RSU vest (cash_gross) and the bank-deposited net_pay. Tax and NI are not shown here because UK cumulative PAYE genuinely takes a YTD true-up chunk in vest months on top of the marginal RSU PAYE \u2014 see Panel 11 for the full tax breakdown with the band-aware RSU split.",
"type": "timeseries",
"datasource": {
"type": "grafana-postgresql-datasource",
@ -1929,407 +1929,10 @@
}
]
},
{
"id": 10,
"title": "HMRC Tax Year Reconciliation \u2014 Individual Tax API",
"description": "Latest snapshot from HMRC Individual Tax API v1.1 vs SUM(payslip.income_tax) per tax year. Delta > \u00a310 turns red \u2014 that's parser drift vs HMRC's held figures, the authoritative ground truth. Shown only for years where hmrc-sync has pulled a snapshot.",
"type": "table",
"datasource": {
"type": "grafana-postgresql-datasource",
"uid": "payslips-pg"
},
"gridPos": {
"h": 10,
"w": 24,
"x": 0,
"y": 94
},
"fieldConfig": {
"defaults": {
"unit": "currencyGBP",
"custom": {
"align": "right",
"displayMode": "auto"
}
},
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": "^delta_"
},
"properties": [
{
"id": "custom.displayMode",
"value": "color-background"
},
{
"id": "thresholds",
"value": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "green",
"value": -10
},
{
"color": "red",
"value": 10
},
{
"color": "red",
"value": -10
}
]
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "tax_year"
},
"properties": [
{
"id": "unit",
"value": "string"
},
{
"id": "custom.align",
"value": "left"
}
]
},
{
"matcher": {
"id": "byName",
"options": "employer_paye_ref"
},
"properties": [
{
"id": "unit",
"value": "string"
},
{
"id": "custom.align",
"value": "left"
}
]
},
{
"matcher": {
"id": "byName",
"options": "snapshot_date"
},
"properties": [
{
"id": "unit",
"value": "dateTimeAsIso"
}
]
}
]
},
"options": {
"showHeader": true,
"cellHeight": "sm",
"footer": {
"show": false
}
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-postgresql-datasource",
"uid": "payslips-pg"
},
"rawQuery": true,
"editorMode": "code",
"format": "table",
"rawSql": "WITH latest AS (SELECT DISTINCT ON (tax_year, employer_paye_ref) tax_year, employer_paye_ref, snapshot_date, gross_pay, income_tax, ni_contributions FROM hmrc_sync.tax_year_snapshot ORDER BY tax_year, employer_paye_ref, snapshot_date DESC), summed AS (SELECT tax_year, COALESCE(SUM(gross_pay), 0) AS sum_gross, COALESCE(SUM(income_tax), 0) AS sum_tax, COALESCE(SUM(national_insurance), 0) AS sum_ni FROM payslip_ingest.payslip GROUP BY tax_year) SELECT l.tax_year, l.employer_paye_ref, l.snapshot_date, l.gross_pay AS hmrc_gross, s.sum_gross AS computed_gross, (l.gross_pay - s.sum_gross) AS delta_gross, l.income_tax AS hmrc_tax, s.sum_tax AS computed_tax, (l.income_tax - s.sum_tax) AS delta_tax, l.ni_contributions AS hmrc_ni, s.sum_ni AS computed_ni, (l.ni_contributions - s.sum_ni) AS delta_ni FROM latest l LEFT JOIN summed s ON s.tax_year = l.tax_year ORDER BY l.tax_year DESC"
}
]
},
{
"id": 14,
"title": "Meta payroll: bank deposit vs payslip net pay",
"description": "Cross-check between ActualBudget bank deposits (META/FACEBOOK payee) and payslip net_pay. |delta| > \u00a350 flags likely parser or bank-sync drift. Synced daily 02:00 UTC.",
"type": "timeseries",
"datasource": {
"type": "grafana-postgresql-datasource",
"uid": "payslips-pg"
},
"gridPos": {
"h": 9,
"w": 24,
"x": 0,
"y": 160
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"unit": "currencyGBP",
"custom": {
"axisPlacement": "auto",
"drawStyle": "line",
"fillOpacity": 0,
"lineWidth": 2,
"pointSize": 6,
"showPoints": "always",
"spanNulls": false,
"thresholdsStyle": {
"mode": "off"
}
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "deposit_sum"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "green"
}
},
{
"id": "displayName",
"value": "Bank deposit (ActualBudget)"
}
]
},
{
"matcher": {
"id": "byName",
"options": "payslip_net_pay"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "blue"
}
},
{
"id": "displayName",
"value": "Payslip net pay"
}
]
},
{
"matcher": {
"id": "byName",
"options": "delta"
},
"properties": [
{
"id": "color",
"value": {
"mode": "fixed",
"fixedColor": "red"
}
},
{
"id": "displayName",
"value": "Delta (deposit \u2212 payslip)"
},
{
"id": "custom.drawStyle",
"value": "bars"
}
]
}
]
},
"options": {
"legend": {
"calcs": [
"last"
],
"displayMode": "table",
"placement": "bottom"
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{
"datasource": {
"type": "grafana-postgresql-datasource",
"uid": "payslips-pg"
},
"rawSql": "WITH deposits AS (SELECT DATE_TRUNC('month', deposit_date)::date AS month_start, SUM(amount) AS deposit_sum FROM payslip_ingest.external_meta_deposits GROUP BY 1), payslip_net AS (SELECT DATE_TRUNC('month', pay_date)::date AS month_start, SUM(net_pay) AS payslip_net_pay FROM payslip_ingest.payslip GROUP BY 1) SELECT COALESCE(p.month_start, d.month_start) AS \"time\", d.deposit_sum, p.payslip_net_pay, COALESCE(d.deposit_sum, 0) - COALESCE(p.payslip_net_pay, 0) AS delta FROM deposits d FULL OUTER JOIN payslip_net p ON p.month_start = d.month_start WHERE $__timeFilter(COALESCE(p.month_start, d.month_start)) ORDER BY \"time\"",
"format": "time_series",
"refId": "A",
"rawQuery": true,
"editorMode": "code"
}
]
},
{
"id": 15,
"title": "RSU vest reconciliation \u2014 payslip vs Schwab",
"description": "Per-vest-month join between payslip.rsu_vest (what HMRC reporting shows) and Schwab's vest-confirmation email data (what actually happened at the broker). Empty rows until the broker-sync IMAP ingest runs and VestEvents are persisted.",
"type": "table",
"datasource": {
"type": "grafana-postgresql-datasource",
"uid": "payslips-pg"
},
"gridPos": {
"h": 10,
"w": 24,
"x": 0,
"y": 169
},
"fieldConfig": {
"defaults": {
"custom": {
"align": "right",
"cellOptions": {
"type": "auto"
},
"inspect": false
},
"unit": "currencyGBP",
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "vest_month"
},
"properties": [
{
"id": "custom.width",
"value": 140
},
{
"id": "custom.align",
"value": "left"
},
{
"id": "unit",
"value": "none"
}
]
},
{
"matcher": {
"id": "byName",
"options": "ticker"
},
"properties": [
{
"id": "custom.width",
"value": 80
},
{
"id": "unit",
"value": "none"
}
]
},
{
"matcher": {
"id": "byName",
"options": "shares_vested"
},
"properties": [
{
"id": "unit",
"value": "none"
}
]
},
{
"matcher": {
"id": "byName",
"options": "tax_delta_pct"
},
"properties": [
{
"id": "unit",
"value": "percent"
},
{
"id": "custom.cellOptions",
"value": {
"type": "color-background",
"mode": "basic"
}
},
{
"id": "thresholds",
"value": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "orange",
"value": 2
},
{
"color": "red",
"value": 5
}
]
}
}
]
}
]
},
"options": {
"cellHeight": "sm",
"footer": {
"show": false
}
},
"targets": [
{
"refId": "A",
"datasource": {
"type": "grafana-postgresql-datasource",
"uid": "payslips-pg"
},
"rawQuery": true,
"editorMode": "code",
"format": "table",
"rawSql": "WITH vest_by_month AS (SELECT DATE_TRUNC('month', vest_date)::date AS vest_month, ticker, SUM(shares_vested) AS shares_vested, SUM(gross_value_gbp) AS broker_gross_gbp, SUM(tax_withheld_gbp) AS broker_tax_gbp FROM payslip_ingest.rsu_vest_events GROUP BY 1, 2), payslip_by_month AS (SELECT DATE_TRUNC('month', pay_date)::date AS vest_month, SUM(rsu_vest) AS payslip_rsu_gbp, SUM(income_tax - COALESCE(cash_income_tax, income_tax)) AS payslip_rsu_tax_gbp FROM payslip_ingest.payslip WHERE rsu_vest > 0 GROUP BY 1) SELECT COALESCE(v.vest_month, p.vest_month) AS vest_month, v.ticker, v.shares_vested, v.broker_gross_gbp, p.payslip_rsu_gbp, (p.payslip_rsu_gbp - v.broker_gross_gbp) AS gross_delta_gbp, v.broker_tax_gbp, p.payslip_rsu_tax_gbp, (p.payslip_rsu_tax_gbp - v.broker_tax_gbp) AS tax_delta_gbp, CASE WHEN v.broker_tax_gbp IS NULL OR v.broker_tax_gbp = 0 THEN NULL ELSE ABS(p.payslip_rsu_tax_gbp - v.broker_tax_gbp) * 100.0 / v.broker_tax_gbp END AS tax_delta_pct FROM vest_by_month v FULL OUTER JOIN payslip_by_month p ON p.vest_month = v.vest_month ORDER BY vest_month DESC"
}
]
},
{
"id": 16,
"title": "Yearly receipt what I actually earned per tax year",
"description": "One stacked bar per tax year, showing pay components I keep: salary (gross), bonus (gross), and RSU vests AFTER band-aware tax (PAYE+NI withheld via sell-to-cover). Excludes deductions and taxes this is the take-home view of earnings, not the gross-deductions waterfall. tax_year axis (text), unit GBP. Always shows all years ignores the time picker.",
"title": "Yearly receipt \u2014 what I actually earned per tax year",
"description": "One stacked bar per tax year, showing pay components I keep: salary (gross), bonus (gross), and RSU vests AFTER band-aware tax (PAYE+NI withheld via sell-to-cover). Excludes deductions and taxes \u2014 this is the take-home view of earnings, not the gross-deductions waterfall. tax_year axis (text), unit GBP. Always shows all years \u2014 ignores the time picker.",
"type": "barchart",
"datasource": {
"type": "grafana-postgresql-datasource",
@ -2462,8 +2065,8 @@
},
{
"id": 17,
"title": "YTD gross salary year-over-year comparison",
"description": "Cumulative gross pay built up month by month within each UK tax year (April March). One line per tax year. Pay dates are projected onto a sliding 12-month window ending now, so years overlay cleanly without falling outside the dashboard's time range. X-axis shows month-of-tax-year (April first, March last).",
"title": "YTD gross salary \u2014 year-over-year comparison",
"description": "Cumulative gross pay built up month by month within each UK tax year (April \u2192 March). One line per tax year. Pay dates are projected onto a sliding 12-month window ending now, so years overlay cleanly without falling outside the dashboard's time range. X-axis shows month-of-tax-year (April first, March last).",
"type": "timeseries",
"timeFrom": "13M",
"datasource": {
@ -2478,7 +2081,9 @@
},
"fieldConfig": {
"defaults": {
"color": {"mode": "palette-classic"},
"color": {
"mode": "palette-classic"
},
"unit": "currencyGBP",
"decimals": 0,
"custom": {
@ -2489,14 +2094,27 @@
"showPoints": "auto",
"spanNulls": true,
"axisPlacement": "auto",
"stacking": {"group": "A", "mode": "none"}
"stacking": {
"group": "A",
"mode": "none"
}
}
},
"overrides": []
},
"options": {
"legend": {"calcs": ["last", "max"], "displayMode": "table", "placement": "bottom"},
"tooltip": {"mode": "multi", "sort": "desc"}
"legend": {
"calcs": [
"last",
"max"
],
"displayMode": "table",
"placement": "bottom"
},
"tooltip": {
"mode": "multi",
"sort": "desc"
}
},
"targets": [
{