Overview
Nolldiff is an account-reconciliation and closing platform built for a Swedish accounting-software company. An accounting firm adds its client companies, connects each one to Fortnox or uploads an SIE file, runs the reconciliation, approves it account by account and delivers the finished closing file. The reconciliation engine, the Fortnox and SIE integrations and the PDF output were already in place when I joined.
My role
I joined in October 2026 and made a little over 220 commits in my first weeks, working alongside the original developers. My work was the platform around the engine: codebase structure, background jobs and scheduling, firm isolation, sign-in and access control, a super-admin panel and an in-app AI assistant.
What it does
- Reconciles a company's accounts per period in AG Grid views, with preparer and approver steps; an approved account is frozen as a version and a change in source data withdraws the approval.
- Locks a closed month against all changes except comments.
- Runs reconciliations nightly on a per-client schedule, with a jobs panel to cancel or re-run and a report email after each run.
- Supports teams with per-client roles and client sharing, email verification and optional TOTP two-step sign-in.
- Offers an Ask AI panel that reads the page on screen and can navigate the app for the user.
How it's built
An async FastAPI backend on PostgreSQL with Alembic migrations; a React, TypeScript and Vite frontend with TanStack Query and AG Grid Enterprise; a Redis job queue with separate worker and scheduler processes; file storage on disk or Google Cloud Storage. Closing files are rendered with ReportLab, and filed annual reports are converted to PDF with Playwright.
Highlights
- Firm isolation in the database: a migration put the firm id on every tenant table, with PostgreSQL triggers that fill it from the parent row and reject cross-firm links, plus a test that replays every id-addressed route with another firm's ids.
- Reliable background runs: the database row stays the source of truth while Redis only says what to run next; every job gets a ledger row, the scheduler writes a heartbeat to the health check, and runs are all-or-nothing.
- A constrained AI assistant: OpenAI's Responses API streamed with storage off, actions limited to navigation the browser has listed, read-only lookups behind the same access checks, and a small classifier that turns away off-topic questions.
- Maintainability: split the API into per-area routers, cut the largest React page from about 3,300 to under 900 lines, and parallelised the backend tests with one database per worker.