The overview of the Orbit Analytics 2026 plan, with first-year revenue, EBITDA, ending cash, runway, ending MRR and break-even

The problem

Early-stage companies often plan in spreadsheets. A spreadsheet is quick, but it is easy to change an old number without noticing, there is no clear record of who changed what, and different tabs can disagree. I wanted to see how far a web app can go in the other direction: one calculation engine, one place for the assumptions, and a record that nobody can quietly rewrite.

The approach

A founder enters assumptions about customers, prices, costs and funding, and one deterministic engine turns them into monthly and yearly forecasts, a profit and loss statement, cash flow, runway and valuation figures. Base, Bull, Bear and custom scenarios run through the same engine, so the differences come only from the assumptions that were changed.

Once the company is running, the team loads real monthly results, compares them with the plan, explains the variances, sets KPI targets and closes finished months. Decisions, approvals, board reviews and board packs sit on top of the same numbers, and models live in workspaces with owner, editor and viewer roles, invitation links and saved versions.

A service layer sits between the pages and the database: pages call services for imports, approvals and closing a month, and the demo data script calls the same services, so the audit trail it leaves is real. Everything runs on a free stack with no paid APIs.

Who uses it

Founders
Enter the assumptions and see how long the cash lasts and what happens if the plan is wrong.
Finance teams
Load monthly results, explain the variances, close finished months and ask for approvals.
The board
Receives a board pack built from the same numbers, printed or saved as a PDF.

What it does

  • Assumptions for revenue, expenses and financing, and a planning timeline
  • Monthly and yearly forecasts, profit and loss, cash flow, runway and customer analytics from one engine
  • Base, Bull, Bear and custom scenarios, a scenario comparison and a sensitivity lab
  • Actuals against the forecast, forecast accuracy, variance review and a KPI scorecard
  • A data import center for actuals, KPI targets and variance comments, with a preview before anything is saved
  • A financial close that locks finished months, with a record of every close and reopen
  • A liquidity risk center, capital planning, a decision center and planning templates
  • An approval center with a separate requester and approver, and an activity center that nobody can edit
  • Saved versions, a model diff, a board room and a printable board pack
  • A portfolio dashboard, consolidation across models and executive reports as PDF
  • Workspaces with owner, editor and viewer roles, and invitation links
  • A read-only live demo, light and dark themes, a command palette and phone layouts

Where the engineering is

History that the database refuses to rewrite

Two rules live in PostgreSQL as triggers: the activity ledger is append-only, and the numbers of a closed month cannot be changed. Closing a month blocks every insert, update and delete of its actuals at the database boundary, so a bug or a missing check in the app cannot break the rule.

Reopening a month is a deliberate action, with a reason and an approval, and only a workspace owner can do it. Every close and every reopen stays on the record.

The financial close page, with closed and open periods, the close governance rules by role and the period register, Open the full-size image (opens in a new tab)
Closed months, and who may reopen them.

Writing nine months of believable history

The demo company needs nine months of history, but the ledger cannot be edited and a closed month cannot be changed. The obvious plan, create everything and then move the dates, is refused by the database itself.

So the demo data script sets a story clock before every step, and each row and each event is written with its own date from the start. A check on the first account stops the run early if the clock does not work, before anything permanent is written.

The activity center, with audit event counts by severity, filters and the project audit ledger, Open the full-size image (opens in a new tab)
An audit trail spread over the whole story.

Imports that match how people really save files

Finance teams do not send perfect CSV files. They save from Excel in other languages, write months in many ways, start the table below a title and name the columns as they like. The data import center reads those files and shows a preview with the problems first.

Nothing is written until an explicit apply. The import respects closed months, writes everything in one step and keeps a history of what was loaded.

The data import center, with import permissions by role and a form to preview and validate a CSV file, Open the full-size image (opens in a new tab)
A file is checked before anything is saved.

One engine, so two pages never disagree

Forecast, profit and loss, cash flow, scenarios, reports and the board pack all read the same calculated numbers. The engine is deterministic: the same assumptions always give the same result, so any change can be traced to the input that caused it.

Money is calculated with decimal.js, not with floating-point numbers. The scenario comparison picks any scenario as the reference and shows which drivers differ and how far each one is from it.

The scenario comparison center, comparing the Base and Bull cases, with driver changes and their divergence, Open the full-size image (opens in a new tab)
Two scenarios, and the drivers that differ.

Sign-in without email, and decisions that need a second person

The app sends no emails, so a forgotten password is reset with a recovery key calculated from the secret, the account and the current password hash. Passwords are hashed, sessions can be ended from the account page, sensitive routes are rate limited, every request gets an id, cross-origin requests that change data are rejected, and security headers are set on every page.

Important decisions go through the approval center. Editors and owners can submit a request, only owners can approve or reject it, and nobody can approve their own request. Each decision is final and recorded in the audit trail with its reason.

The approval center, with request counts by status, the approval rules by role and a form for a new request, Open the full-size image (opens in a new tab)
Requests, approvals and the rules behind them.

Screens

How it's built

LayerTechnology
FrameworkNext.js 16 App Router with server components and server actions, so the data code stays on the server, with React 19 and TypeScript
DatabasePostgreSQL with Prisma 7: 24 tables, 4 enums and 16 migrations, plus triggers for the rules that protect history
Sign-inAuth.js with email and password, hashed passwords and a recovery key instead of reset emails
Calculationdecimal.js for exact money maths, Zod schemas shared by the client and the server, and pdf-lib for PDF reports
InterfaceTailwind CSS 4 and shadcn/ui design tokens for light and dark themes, and Recharts charts that screen readers can read
OperationsA Docker image, backup and restore with a verify step, deploy and rollback scripts, and health, readiness and diagnostics endpoints

Testing

282 unit test files cover the calculation engine, the services and the components with Vitest, and 32 browser test files run the main flows in a real browser with Playwright, with automated accessibility checks.

A release check runs lint, the type check, the unit tests and the browser tests together, and a smoke test checks a running copy.

Results

  • 52 pages: 8 public, 7 in the app shell and 37 model pages.
  • 24 database tables and 4 enums over 16 migrations, and 10 API routes.
  • 282 unit test files and 32 browser test files.
  • Runs on a free stack with no paid APIs.

What I would build next

  • Put a public, read-only copy online with the demo data.
  • Move the rate limiter from memory to a shared store before running more than one copy of the app.
  • Cache the heavy analysis pages, since the engine is deterministic.
  • Move PDF creation to a background job.

What I learned

  • Put the rules that must never break into the database, then test them there.
  • A shared service layer pays off: the pages, the demo data and the tests all use the same code paths.
  • Accessibility and phone layouts are cheaper when every page is built for them from the start.
  • A believable demo needs a story with a timeline, not random numbers.

Built with

  • Next.js
  • React
  • TypeScript
  • Tailwind CSS
  • Prisma
  • PostgreSQL
  • Auth.js
  • Recharts
  • Vitest
  • Playwright

56 results