Skip to content

Security

Isolation, access and evidence, enforced in the database.

This page is written for the person who has to sign off. It describes how customer data is kept apart, who can reach it, and what is kept as evidence, in terms you can test on a call. Where a control is not in place, this page does not claim it.

Posture

Four properties to test first

  • Row-level security

    Roughly one hundred tables enforce organisation membership on every row.

  • Second factor, enforced below the app

    A session that has not completed its TOTP challenge is refused data.

  • Append-only evidence

    Validation runs and audit events are added beside, never written over.

  • Invite-only membership

    One email address belongs to one organisation. Removal deletes the account.

Simplest Energy keeps every customer’s data isolated by row-level security in the database itself: roughly one hundred tables each carry the organisation a row belongs to, and a query from outside that organisation returns nothing. Membership is invite-only and governed by 4 built-in roles over 11 permissions, with per-organisation overrides and custom roles, and TOTP two-factor enforcement applied in the database rather than the interface. Everything the engine concludes is written to append-only evidence tables that can be exported, and uploaded invoices live in private storage behind signed links that expire in minutes, are used for validation and nothing else, and are deleted on request.

Isolation

The walls between customers are the database’s, not the application’s.

Every organisation’s rows live behind row-level security in PostgreSQL. Roughly one hundred tables carry the organisation a row belongs to, and the database attaches the requester’s membership to every query it runs. The practical consequence is the one a reviewer should care about: a query that forgets its filter returns nothing, not everything. Isolation does not depend on every page remembering to ask.

Inside an organisation, sites can be divided into groups and a member can be restricted to the groups they are given. A bureau runs each client estate as a group inside its own organisation, so an analyst assigned to one client sees that client’s sites, meters and bills and nothing else. The restriction is applied in the database beside the organisation wall, and it reaches the places blanket rules usually miss: the audit trail a restricted member reads is scoped to their groups, and background jobs respect the same boundary.

Access

Nobody arrives uninvited, and nobody keeps a dormant key.

There is no self-service sign-up. A member joins by invitation from an organisation admin, one email address belongs to exactly one organisation, and removing a member deletes the account rather than leaving it dormant. 4 built-in roles, from read-only to admin, cover 11 distinct permissions: creating and editing data, approving bills, running financial exports, managing the team and so on. An organisation can override what a role may do and can define custom roles, so the permission an auditor reads in settings is the permission the server checks.

Two-factor authentication uses time-based one-time passwords, and enforcement sits below the application: once a member has enrolled a second factor, row-level security refuses their session access to business data until the challenge has been completed, so a bug in the interface cannot skip it. An organisation can also switch on an idle sign-out policy, ending sessions that stay quiet for longer than the period it sets.

Evidence

Conclusions are stored as evidence, not as state.

A validation run writes the expected bill it computed, every line comparison and every check result as new rows. Re-running a bill adds a new run beside the old one and overwrites nothing, so the verdict the platform gave last quarter can be produced this quarter, unchanged, with the working attached. Actions taken in the platform land in an append-only audit trail the same way, and both records can be exported.

Your documents

An uploaded invoice is used for validation, and for nothing else.

Uploaded invoices are stored in private storage that no public URL reaches. When a member opens a document, the server issues a signed link that expires after ten minutes: long enough to read, short enough that a copied link is not a lasting way in. A bill you upload is used for validating that bill, is not shared with anyone outside Simplest Energy, and is deleted on request.

Hardening

The smaller controls a review asks about. None earns a section of its own; all of them are the difference between a platform that was hardened and one that was merely deployed.

  1. 01

    Validation happens on the server.

    Every form is checked again on the server before anything is written. What the browser validates is a preview; the server’s check is the one that counts.

  2. 02

    Errors do not leak.

    A failed database operation reaches the member as a plain sentence. Raw database errors, table names and query shapes stay in the server logs.

  3. 03

    Every response carries security headers.

    Pages refuse to be framed by other sites, content-type sniffing is forbidden, and what referrer information leaves the page is limited.

  4. 04

    Scheduled jobs authenticate.

    The background jobs that send reports, chase bills and reconcile data require a secret on every request. An unauthenticated call to a job endpoint does nothing.

  5. 05

    Files are checked by content, not by label.

    An uploaded file’s leading bytes must match the type it claims to be. A payload with a forged content type is refused before it is stored.

  6. 06

    SVG uploads are refused.

    Everywhere an image can be uploaded, SVG is not an accepted type, because an SVG file can carry script. Logos and attachments are raster only.

Ask the questions this page did not answer.

Send the security questionnaire, or bring a real invoice and see the controls from the inside while the engine validates it.