stats: new public stats schema (source/series/obs/region/fetch_run + raw CBS, Eurostat, FRED, BIS tables) and the stats collector (scripts/stats-fetch.ts); preflight checks the stats tables
Some checks failed
Deploy production / deploy (push) Failing after 54s

This commit is contained in:
2026-10-25 20:27:04 +00:00
parent 902b1cadd5
commit 8ef291f586
14 changed files with 33128 additions and 2 deletions

View File

@@ -173,6 +173,18 @@ try {
groceries.public_usage
)
throw new Error(`groceries schema grants are wrong: ${JSON.stringify(groceries)}`);
// Public /stats section: open data, so the app role (and the host-side stats collector, which
// uses it) reads and writes, and personal_ro may read. Bump the count with every new stats table.
const STATS_TABLES = 12;
const [stats] = await client`
select
count(*) filter (where has_table_privilege(c.oid, 'select, insert, update, delete')) as app_rw,
count(*) as tables
from pg_class c join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'stats' and c.relkind = 'r'
`;
if (Number(stats.tables) !== STATS_TABLES || Number(stats.app_rw) !== STATS_TABLES)
throw new Error(`stats schema tables/grants are wrong: ${JSON.stringify(stats)}`);
// Energy tracker reads the ned-collector tables (SELECT only).
const [energy] = await client`
select count(*) as hours, max(valid_from) as latest from energy.ned_utilization
@@ -182,7 +194,7 @@ try {
if (!Number(energy.hours))
console.warn('Warning: energy.ned_utilization has no hourly data from the last 7 days');
console.log(
`health: ${health.tables} tables, tasks: ${tasks.tables} tables, groceries: ${groceries.tables} tables, app read/write, personal_ro none; energy: ${energy.hours} hourly rows, latest ${energy.latest ? new Date(energy.latest).toISOString() : 'none'}`
`health: ${health.tables} tables, tasks: ${tasks.tables} tables, groceries: ${groceries.tables} tables, stats: ${stats.tables} tables, app read/write, personal_ro none; energy: ${energy.hours} hourly rows, latest ${energy.latest ? new Date(energy.latest).toISOString() : 'none'}`
);
const [catalog] = await client`
select