Open Net Worth
Open Net Worth is an open-source personal AI wealth assistant you run yourself: one ledger for your whole financial life, worked by an AI agent you control.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Finance, shift and scheduling PWA for gig delivery workers: real hourly earnings and daily targets. Minute-resolution push with the scheduler inside Postgres
翻訳待ち
Loading the full README. The saved excerpt is shown below.
Mobile-first PWA for personal finances, work shifts and scheduling, aimed at
gig delivery and rideshare workers: it tracks what you actually earn per hour
and how far you are from the day's target.
Stack: Next.js 16 (App Router) · TypeScript · Tailwind · Supabase
(magic-link auth, PostgreSQL, RLS) · web-push · pg_cron + pg_net · VercelRead the full README ↗Mobile-first PWA that answers two questions: how long will my money last this month? and, for rideshare and delivery drivers, how much do I really make per hour? — counting real kilometres with the phone's GPS.
Live: https://desempleo-inky.vercel.app
Stack: Next.js 16 (App Router) · React 19 · TypeScript · Tailwind · Supabase (Postgres + RLS, magic-link and Google auth) · web-push · pg_cron + pg_net · Leaflet · Vitest + Playwright · Vercel
Two kinds of people use it, and the navigation adapts to each (Hoy · Cuentas · + · Jornada or Métricas · Más).
Everyone — money in order
Drivers and couriers (Uber, Rappi, Didi, PedidosYa…) — the Jornada tab
Works without signal: entries logged offline queue on the phone and sync when connectivity returns; the app shell opens offline.
Also: agenda with push reminders, shared Trello-style boards, CSV export, download all my data and delete my account.
Browser (PWA) Vercel (Next.js) Supabase
───────────── ──────────────── ────────
Server Components ───────────────► SELECTs with the user's session ──► Postgres + RLS
Client Components ─── inserts/updates directly with the anon key ───► (RLS is the
security layer)
Service worker: push, offline cache
OfflineSync: queue → upsert by id
GPS: watchPosition → lib/geo ──────────────── rpc save_gig_track ───► gig_tracks
/api/share → Gemini / Claude
/api/push/* → web-push ◄─── pg_cron + pg_net
/api/account (delete / export)
/api/log → Vercel logs
auth.uid();
routes that need more (cron, invitations, account deletion) use the service
role on the server only.src/lib as pure functions (runway, GPS
distance, real earnings, budgets, dates, amount parsing, offline queue) and
is unit-tested in isolation.A scheduler inside the database. Vercel's Hobby plan can't run cron at
minute resolution, and scheduling reminders from the frontend depends on the
app being open. pg_cron fires every minute inside Postgres, pg_net POSTs to
/api/push/cron with a shared secret, and the handler sends due reminders
through web-push. Trade-off: two extensions and a secret to rotate, in
exchange for minute resolution without a paid plan or a separate worker.
GPS distance you can trust. Summing raw readings turns an 80 km day into
110 km: a parked phone jitters 5–30 m and occasionally jumps hundreds of metres.
lib/geo.ts drops readings with poor accuracy, ignores moves smaller than the
noise (without moving the anchor, so slow progress still adds up), rejects
impossible speeds, and adds a straight line when the signal comes back.
Saving is a single idempotent RPC, so a retry on a flaky connection never
double-counts kilometres. Auto-start (lib/motion.ts) looks at a two-minute
window and only fires when the movement holds without its first and without
its last reading, so a single GPS jump never starts a trip; the tracker lives
in a provider in the app layout, so it keeps measuring outside the Jornada tab. The heatmap is aggregated in Postgres
(gig_heat_cells) instead of shipping thousands of points to the phone.
Offline first where it matters. Drivers log trips in places with no data.
Failed inserts go to a local queue with a client-generated id; OfflineSync
flushes it with upsert … ignoreDuplicates when the connection returns, and
resolves the shift id at send time.
The user's day, not the server's. Vercel runs in UTC: after 9 p.m. in
Argentina it is already "tomorrow". Everything that depends on today
(shifts, runway, today's agenda, greeting) goes through lib/dates.ts with
the user's time zone.
Amounts from any country. "$12.345,67", "$1,234.50", "$ 15.990"
(CLP) and "Bs. 1.234,56" all parse correctly (lib/amount.ts) — both for
LLM output and for what users type.
This is the beginning of the README. Read the rest at the original. Read the full README ↗