Tasks goals: auto metrics (tasks.goals.metric_key/metric_detail/metric_computed_at, tasks.metric_sources cache). €10k/month goal gets a live progress bar: Revolut recurring income (excl. Zorgtoeslag/Joint) computed on page load + trailing-12m paid Moneybird invoices / 12 cached by a daily goal-metrics user timer; stacked bar with %, amount vs target, salary/side-income breakdown, last-updated
Some checks failed
Deploy production / deploy (push) Failing after 1m14s
Some checks failed
Deploy production / deploy (push) Failing after 1m14s
This commit is contained in:
46
scripts/goal-metrics.ts
Normal file
46
scripts/goal-metrics.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
// Daily refresh of auto goal metrics (tasks.goals.metric_key):
|
||||
// 1. trailing-12-month paid Moneybird sales invoices -> tasks.metric_sources
|
||||
// 2. recompute every auto goal -> tasks.goals.metric_current/metric_detail (+ progress snapshot)
|
||||
//
|
||||
// bun --env-file=$HOME/.config/goal-metrics.env scripts/goal-metrics.ts [--dry-run]
|
||||
// Env: DB_URL (app role), MONEYBIRD_API_TOKEN, MONEYBIRD_ADMINISTRATION_ID. Mode 600, never committed.
|
||||
// Run by the goal-metrics.timer user unit (deploy/systemd). Page loads never call Moneybird.
|
||||
import postgres from 'postgres';
|
||||
import {
|
||||
SIDE_INCOME_SOURCE,
|
||||
fetchMoneybirdSideIncome,
|
||||
persistGoalMetrics,
|
||||
saveSource
|
||||
} from '../src/lib/server/goal-metrics/core';
|
||||
|
||||
const dry = process.argv.includes('--dry-run');
|
||||
const { DB_URL, MONEYBIRD_API_TOKEN, MONEYBIRD_ADMINISTRATION_ID } = process.env;
|
||||
if (!DB_URL) throw new Error('Set DB_URL');
|
||||
const sql = postgres(DB_URL, { max: 1, connect_timeout: 10, onnotice: () => {} });
|
||||
let failed = false;
|
||||
try {
|
||||
if (!MONEYBIRD_API_TOKEN || !MONEYBIRD_ADMINISTRATION_ID) {
|
||||
failed = true;
|
||||
console.error('[goal-metrics] Moneybird env missing; keeping the cached side income');
|
||||
} else {
|
||||
try {
|
||||
const mb = await fetchMoneybirdSideIncome(MONEYBIRD_API_TOKEN, MONEYBIRD_ADMINISTRATION_ID);
|
||||
console.log(`[goal-metrics] Moneybird: ${mb.invoices} paid invoices ${mb.from}..${mb.to}`);
|
||||
if (!dry) await saveSource(sql, SIDE_INCOME_SOURCE, mb.monthly, mb, null);
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
const msg = (e as Error).message.slice(0, 300);
|
||||
console.error(`[goal-metrics] Moneybird failed: ${msg}`);
|
||||
if (!dry) await saveSource(sql, SIDE_INCOME_SOURCE, null, null, msg);
|
||||
}
|
||||
}
|
||||
if (!dry) {
|
||||
for (const g of await persistGoalMetrics(sql))
|
||||
console.log(
|
||||
`[goal-metrics] goal ${g.id}: ${g.target ? ((g.value / g.target) * 100).toFixed(1) + '%' : 'no target'}`
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
await sql.end();
|
||||
}
|
||||
if (failed) process.exit(1);
|
||||
Reference in New Issue
Block a user