Rekstrarkerfið is one Express application on one PostgreSQL database, built on technology that changes slowly and does not need replacing in a few years. Everything below is taken from the code and the hosting as they run on rekstrarkerfi.is today, and customer installations are built from the same template.
Checked against the code on 19 September 2026 · Everything here is as it runs on rekstrarkerfi.is
Every customer runs the same core: website, shop, point of sale, accounting, users and access control, in one Express application on one PostgreSQL database. Nothing is synchronised between subsystems because there are none; a sale at the till and its ledger entry are rows in the same database.
What is specific to one business is written as an addition beside the core and does not edit core files, so a core update does not overwrite it. Schema changes are migrations in one ordered list in the repo, each applied in its own transaction. A release's migrations have to work with the previous release's code: a column is added in one release and the old one removed in a later release, so the previous image can be put back.
Figure 1. The path of a request (A) and the path of a release (B), as they run today.
The code is written with Anthropic's Claude models, and every change is reviewed before it is merged into the main branch. The contract is with Orange Smiley ehf., and which tool typed the code changes nothing about who answers for it.
Mistakes are expected, from models and from people alike, so no single check is trusted. Automated tests, code review, security rules on every request, a test environment before production and monitoring afterwards each catch what another one misses.
Chosen to be dull. Any Node developer can read this codebase on the first day, and none of it needs replacing in two years.
28 direct runtime dependencies; npm audit --omit=dev reported 0 known vulnerabilities on 19 September 2026. Exact versions are pinned in the repository and available on review.
Every request passes through these layers before it reaches any data. Access is always checked on the server; the route guards in the browser are a convenience and protect nothing.
The headers as served. Check them yourself with curl -sI https://rekstrarkerfi.is
All authentication goes through Lucia on the server. The table shows what happens at sign-in and how access is divided.
A release is a GitHub Actions run started by hand. The Docker image is built once per commit and scanned with Trivy. The test environment runs it first, pinned by its sha256 digest, and once /ready answers there the image is marked tested. Production gets exactly the same image and never builds its own.
Rolling the application back is pinning it to the previous digest again. Migrations that have been applied are not rolled back, which is why they have to be compatible with the previous release's code.
The database is backed up by Azure with point-in-time restore over 14 days, and the backup is geo-redundant.
The core also contains a self-update module. An instance reads a manifest over HTTPS from an allow-listed host, takes the image by its sha256 digest, waits for a maintenance window the customer chooses, refuses a release whose minimum compatible version is newer than the one the instance runs, and verifies itself after boot. It is built and tested, and it will be switched on when the release channel is in place: our own sites first, customers after.
The Jest integration tests run against a real PostgreSQL that is dropped and rebuilt from the whole migration chain on every run; pg is never mocked. Playwright drives whole user journeys in Chromium, against a throwaway database of its own per branch. A schema test checks that every table the SQL refers to exists. ESLint runs on every commit and push through git hooks.
Automated checks run on a CI server on every pull request: a dependency audit, ESLint, a translation-key check, the unit tests, a smoke set of the integration tests and a build of the production image, which is booted against an empty database. All the integration tests and the Playwright tests run at night when something new has come in, and the same run can be started by hand before a deploy. The working rule is that before a release that adds migrations goes out, the system is booted against an empty database to prove that the whole chain applies.
Server errors (5xx) and browser errors (uncaught exceptions and rejected promises) are recorded in the database with the request id, kept for 90 days and shown on an admin page. An Azure availability test calls the site every five minutes, around the clock, and alerts on a burst of 5xx responses or sustained slow responses are sent by e-mail. /health answers for the process and /ready for the database.
Every installation is set up from the same template in Azure. The table shows what each customer has to themselves and what is shared.
These are decisions we took on purpose, and what is next.
Design is not a final step added on top of the system. It is part of every page from the start. Your website gets its own look, with your company's colours, type and photos, on a base that is already well made. The same goes for the dashboard your staff use every day. It should be clear, calm and quick to find your way around.
Behind it are people who have designed both spaces and interfaces, from a café in Vestmannaeyjar to interfaces that Microsoft customers use. You do not have to take our word for it. The page you are reading is made the same way.
Orange Smiley ehf. The contract is with the company and it makes no difference which tool wrote the code. Every change is reviewed before it is merged into the main branch. If something breaks, the previous release can be put back while the fault is fixed.
So do programmers, which is why the checks are layered and none of them has to be perfect. Tests run against a real PostgreSQL and whole journeys are tested in a browser. A release goes to the test environment before production, and monitoring takes over after that. Migrations are written in two steps so that going back stays possible.
For many businesses that is plenty, and then there is no reason to switch. This system is for the ones who have started reconciling numbers between systems by hand, or who need a change no app provides. Here everything is in one database, so there is nothing to keep in sync. Changes are part of the service contract and are estimated before any work starts.
Custom work is written beside the core and does not change core files, so an update does not overwrite it. If it needs the database changed, those changes only add. It is run against the new core in the test environment before the release reaches production, and if something still goes wrong the previous release is put back.
The frontend is ES modules and the DOM, with no bundler, and that is deliberate. A system meant to last many years then has no framework upgrades and no build chain to go stale, and fewer dependencies means less surface for supply-chain attacks. The security parts come from known libraries: Lucia for sessions, helmet for CSP, csrf-csrf, express-rate-limit and sanitize-html.
In Microsoft Azure in Sweden, inside the EEA. Every customer has an installation and a database of their own. Access is by role, administrators sign in with two-factor authentication, and what administrators do is logged.
The data is the customer's and all of it is in one PostgreSQL database that nobody else shares. It is delivered both as a pg_dump and as CSV files, so another system or another developer can take it from there.
No, not unless the customer asks for it. Data goes to Anthropic only if a customer asks for an API or MCP connection to Claude. Changes are built and tested in the test environment, which is a copy of production refreshed weekly.
Send us the question if the answer is not here. We will answer it and add the answer to this page.