Skip to content

alexnsolo/banksync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

banksync dashboard

Personal finance dashboard for one user. Reads balances from BankSync, snapshots them into Neon Postgres, and renders a mobile-first dashboard on Vercel.

The architecture and behavior live as an OpenSpec change at openspec/changes/init-balances-dashboard/.

Stack

  • Next.js 16 (App Router) + React 19 + TypeScript
  • Tailwind v4
  • Postgres + Drizzle ORM (Neon HTTP driver in production, node-postgres for local Docker — chosen automatically by lib/db/client.ts from the DATABASE_URL)
  • Zod-validated BankSync REST client (no SDK exists yet)
  • Vercel hosting + Vercel Cron + Deployment Protection (password) for auth

Setup

Option A — Docker Compose (recommended for local dev)

Spins up Postgres 16 and the Next.js dev server side-by-side. App is exposed at http://localhost:7777.

cp .env.example .env.local           # only BANKSYNC_API_KEY is needed locally
docker compose up --build            # builds image and starts both services
# in a second terminal — apply schema to the local Postgres
docker compose exec web pnpm db:push

docker-compose.yml injects a local DATABASE_URL automatically and sets a dev-only CRON_SECRET. The repo is bind-mounted into /app so edits hot- reload as usual.

Postgres is also exposed on localhost:5777 (user/pass/db: banksync) for psql / TablePlus / etc.

Option B — Run Next.js on the host

pnpm install
cp .env.example .env.local
# Fill in BANKSYNC_API_KEY, DATABASE_URL, CRON_SECRET

pnpm db:push                          # apply schema
pnpm smoke                            # optional: hit BankSync end-to-end
pnpm dev

How data flows

Browser → Next.js (RSC) → Postgres            (read path, instant)
                ▲
                │
Vercel Cron ──▶ /api/refresh ──▶ BankSync API   (write path, every 6 hours)
"Refresh now" ▶ server action ─▶ runSync()
  • Pages never call BankSync. Only lib/sync.ts::runSync() does, called from /api/refresh (cron) or the server action behind the "Refresh now" button. The API key never reaches the browser.
  • Snapshots are append-only. balance_snapshots has a unique constraint on (account_id, as_of) so re-syncing within an institution's update window is a no-op.
  • Money is numeric end-to-end. No JS number between BankSync and Postgres.

Deploy (Vercel + Neon)

1. Provision Neon Postgres

  1. Create a new Neon project at https://console.neon.tech.
  2. From the project dashboard, copy the pooled connection string (host contains -pooler). It looks like: postgres://user:pass@ep-xxx-pooler.region.neon.tech/dbname?sslmode=require. The HTTP driver in lib/db/client.ts auto-activates when it sees a neon.tech host, so this is the only DB knob you need to set.
  3. (Optional but recommended for previews) install the Neon Vercel integration so each preview deploy gets its own DB branch.

2. Create the Vercel project

pnpm dlx vercel@latest link        # link the repo to a new/existing project

Set the three production env vars (dashboard or CLI):

vercel env add BANKSYNC_API_KEY production
vercel env add DATABASE_URL       production
vercel env add CRON_SECRET        production       # openssl rand -hex 32

Vercel Cron will automatically send Authorization: Bearer ${CRON_SECRET} to /api/refresh — no extra wiring needed.

3. Gate access

Project Settings → Deployment Protection → enable Password Protection for All Deployments. This is the only auth layer the app has; there is no user table or sign-in flow.

4. Deploy

vercel --prod

On every production build the prebuild hook in package.json runs pnpm db:migrate, applying any pending Drizzle migrations from ./drizzle/ to DATABASE_URL before next build starts. Preview and local builds skip migrations so a feature branch never mutates the prod schema. To run migrations against previews too, install the Neon Vercel integration and broaden the check in scripts/prebuild.ts.

5. Verify

  1. Hit the deployed URL, satisfy the password prompt.
  2. Trigger a first sync from the dashboard (REFRESH button) and confirm accounts + balances populate.
  3. vercel.json schedules /api/refresh every 6 hours; the next cron run shows up in Vercel → Deployments → Cron Jobs.

Function timeout

/api/refresh declares export const maxDuration = 60 (Hobby ceiling). On Pro, you can raise this to 300 in app/api/refresh/route.ts if the sync ever grows past a minute.

Working on this

pnpm lint
pnpm build
pnpm drizzle-kit generate    # produce a migration after editing lib/db/schema.ts
pnpm drizzle-kit push        # apply schema directly (dev convenience)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors