Deployment

One deployment is one institution

Bilnax is single-tenant. An installation serves exactly one bank, NBFC or practice — its accounts, its model versions and its approval trail belong to it and to nobody else. A second customer is a second installation, not a second row in a shared table.

What reaches the server

Your loan book does not. That is the point, and it is checkable.

The loan tape, and every portfolio derived from itNever leaves the browser

Held in that browser's own storage, and in no database of ours. Reading and measuring happen on the server, so the tape does travel there in the request — and is kept nowhere once the answer comes back.

Assessments, mappings and reconciliationsNever leaves the browser

The same. A backup file the preparer downloads is the only copy that leaves the machine.

Model versions, and who approved themOn the server

The four-eyes trail has to survive a restart or it is not a control. This is the reason there is a database at all.

Accounts and sessionsOn the server

So that a role is server-side state and never something a browser asserts about itself.

Enquiries sent through the contact formOn the server

A message addressed to the operator of the installation. Absent on a deployment with no public site in front of it.

It is checkable rather than asserted: open the network tab and import a loan tape. The calculation endpoint takes the portfolio in the request and returns the result; nothing is written, and there is no endpoint that would write it.

What an installation needs

It is a Next.js application and a Postgres database. It runs on a platform that serves Node, or in your own environment — there is nothing platform-specific in it beyond the runtime.

Required
Node 24 or later

The runtime. Earlier versions are refused by `package.json`, and the platform's default is usually older than this.

DATABASE_URL

A Postgres connection string, pointed at the TRANSACTION POOLER rather than the direct port. A serverless deployment opens a pool per instance and exhausts the connection limit on the direct port, which presents as intermittent failure rather than a clear error. The application warns when it can tell.

SETUP_TOKEN

A long random value, used once to create the first administrator and then never again. Without it the first account cannot be created — which is deliberate, because the alternative is that the first person to find the sign-in page gets it.

NEXT_PUBLIC_SITE_URL

The address this installation is served from. Canonical links, the sitemap and the structured data all key off it.

Optional
DATABASE_CA_CERT

The certificate authority for a self-hosted Postgres. Supabase's own root is bundled, so this is only needed elsewhere. Certificate verification is never switched off — a connection carrying an approval trail has to be able to say who is on the other end of it.

CONTACT_WEBHOOK_URL and CONTACT_EMAIL

Where an enquiry from the contact form is announced, and the address it falls back to. Enquiries are recorded either way; without these nobody is notified and somebody has to go and look.

What this is not

There is no installer, no support contract and no uptime commitment, because none of those exist yet. Standing up an installation today is a conversation with one of two named people, and what that conversation produces is an environment somebody is answerable for — which is the thing being bought, and the only thing worth paying for in this market.

The alternative is available and costs nothing: use it on this site, on your own data, in your own browser, with no account and no agreement. Everything except the approval trail works that way, and that is the honest way to find out whether it is worth a deployment at all.