Rutba
Start free

Blog · Money

One price list, and no page carries a price

One product was advertised at three different prices depending on which Rutba site you opened, and nothing could tell. Every figure now comes from one record as the page renders — and a test fails the build if anybody types a price into the site.

· 3 min read

Share this

Here is a failure that never announces itself. A price changes. Somebody updates the pricing page. The same figure is also on a product page, in a comparison table, in three blog posts, in the checkout on a console and in a partner’s deck — and each of those was correct on the day it was written.

We had exactly that: each site carried its own compiled-in copy of the price list, so one product could be advertised at three different prices depending on which Rutba site you opened, and nothing in the system could detect the disagreement.

Prices are records now

The price list lives in one place: records in our own backend, with the allowances that go with each tier. Every site — rutba.io, Sign, the Relay, Office, the partner pages — and every console reads that when a page renders. There is one authored list behind it, one file that a person edits and reviews, and an importer that only ever creates what is missing: moving a live price takes a deliberate flag, prints every change, and writes an audit row.

Changing what a tier includes is the same kind of edit — a change to the plan’s allowances, made in the console or the importer. Not a code change, not a deploy, and not a sentence on a marketing page that drifts from what the licence actually grants.

Two different sentences that used to be one

A page that asks for prices has to cope with not getting them, and the wrong way is a dash or a blank where a number should be. So there are two answers, and they are deliberately not the same:

  • “Custom.” A tier we quote individually, because what it costs depends on what you need. That is an answer.
  • “We cannot tell you right now.” The price list could not be read. The page says so and points you at a person, and the checkout refuses to ask anybody to confirm a price it cannot read.

Treating the second as the first would be a lie by omission at the exact moment somebody is deciding to buy.

A test that fails on a typed price

None of this survives good intentions. The discipline is a test: a currency amount typed anywhere into the site’s content fails the build. When we moved to one list, twenty-two blog posts were carrying price tables somebody had typed; each now names the listing it is about and the table is drawn from the same record the pricing page reads.

There are exactly three exceptions, and they are the kind that prove the rule. The dated changelog, because that is history — “was this, now that” is a record of a day, and correcting it later would be rewriting the record. And two posts whose subject is the arithmetic itself, where replacing the worked example with a live price would make the sums stop adding up. Those are worth reading for their own sake: every rounding goes to the customer and ask for your money back.

Why a customer should care

  • The price you were shown is the price that is charged. One record answers the marketing page, the quote and the invoice.
  • A price change is visible. It is an edit with an audit row behind it, not a thousand pages quietly disagreeing.
  • Allowances are numbers, not adjectives. What a tier includes is a figure a licence carries, which is what makes it checkable.

The prices themselves were reviewed and cut at the same time, and the shop stopped paying per person — that is the previous post in this series.

Every price, in one place

The pricing page reads the same record every other page does.

See the prices

Read next

Privacy

One place for your second factor, and a code you can scan

Turning on two-factor used to mean typing a thirty-two character secret by hand. It is a code you scan now, or a button on a phone — and the factor itself lives in one store rather than two, which is the part that keeps a settings page honest.

4 min read

How we build

The password was right. The browser refused the last hop

A sign-in that looked like a wrong password was a security header doing its job too well: it allowed the form but not the page the form lands on. The fix was to build that rule from the list of places a sign-in is already allowed to end.

3 min read

How we build

Where a sign-in should leave you: the app you hold, not a lobby

Signing in used to send everybody to the customer console, including people who hold no customer account. It now sends you to the one app you can actually open — and when you hold several, each is a row you can click rather than a name on a page.

3 min read

Share this

One family

The rest of Rutba

One account across all of it. Sign in once and the products know each other.

PORTAL-BLOG-DETAIL · 7649699