/projects/dietbox-portal

← All projects

Dietbox Portal

The back office that handed the product’s daily operations to the operations team.

Head of Technology · 2023–2024

.NET 6C#CQRSMediatREF CoreSQL ServerASP.NET IdentityJWTVue 3VuexAzure DevOps
WebsitePrivate
Dietbox Portal screenshot

Overview

Until 2023, any change to the product’s data went through the technology team: adjusting a subscription, correcting a record, loading a food table. The portal put those actions on screens, with the product’s own rules in front of them and a sign-in separate from the customer’s. The operations team started doing them directly — forty-four actions across ten areas.

What I did

I decided what operations should be able to do without us, and built what it takes to let them do it safely: the staff identity and permissions the whole thing runs behind, the command surface under the screens, and the design the rest of the team built the eighteen business areas on top of.

  • Choosing the actions: which requests we were tired of receiving, and which of those were safe to hand over.
  • The identity building block: its own user store, a JWT builder and validator, access and refresh tokens, and claim-based authorization.
  • Impersonation, in both directions and both ways back out, and the rule that it lives behind a staff account rather than a customer one.
  • The design the team built the eighteen business areas on top of, so a new area was a day rather than an argument.

Across the service and the admin client together, roughly a third of the commits are mine — the rest, including most of the eighteen business-domain controllers and the client’s views, is the team’s.

The problem

Support could not adjust a subscription, marketing could not publish a banner, and nobody outside engineering could load a new food table. Each was a request to the technology team, and an engineer running the change by hand against the product database or the monolith’s admin surface — no rules in front of it and no name on it afterwards.

By the numbers

The commit share comes from the two repositories. The forty-four is a count of the write actions the service exposes — the commands behind the screens ops uses.

~276commits across both repositoriesmine, of ~780 total
44actions ops could take aloneacross ten areas of the product

Architecture

Someone on the operations team picks an action on a screen, and it travels as a named command through the product’s own rules before it reaches the product’s data.

  1. OpsSomeone on the operations team, signed in with a staff account, on the Vue screens for the ten areas — including the impersonate controls in the navbar and the patient view.
  2. PermissionsThe token decides which of the actions this person is allowed at all — a claim-requirement filter in front of every controller.
  3. CommandThe action runs as one of the forty-four commands, logged by name on the way through, rather than as an edit to a table.
  4. RulesThe same rules the product itself enforces stand in front of the write — which is the difference between ops doing this and an engineer doing it by hand.
  5. DatabaseThe change lands in the same database the product serves from — which is exactly why it goes through the rules above rather than around them.

What it does

  • Impersonation as a first-class feature: support can act as the nutritionist or patient they’re helping, from the client’s navbar or the patient view, and step back out.
  • Subscriptions: cancel one, grant a special one, change a plan’s limits, and move a nutritionist onto the new payment gateway.
  • The food catalogue: create, edit, retire and bulk-activate foods and food groups — or import a whole table from a file, which used to be an engineer with a script.
  • Vouchers, external vouchers and gift configuration, created and retired by whoever is running the campaign.
  • Marketing: featured banners, the customizable cards on the product’s own screens, and the material library.
  • Nutritionist and patient records: update details, correct an email, and clear a cache that is serving something stale.
  • A dashboard whose numbers come from the same commands that changed them, so ops reads its own results.

Engineering decisions

  • Handing over the actions instead of answering the requests

    The cheaper option was to keep answering the requests as they came. Answering does not get faster with repetition, though, and each request costs engineering time on work that is not engineering. The screens built here are the requests that arrived often enough to be worth replacing.

  • Staff identity is not customer identity

    The back office authenticates against its own store — an identity building block with its own user database, a JWT builder and validator, access and refresh tokens, and claim-based authorization — not the customer directory. Giving support staff accounts in the customer identity system would have meant handing customer-grade identities administrative scopes; keeping the two separate keeps a back-office session a different thing from a customer session, by construction.

  • An action, not a database edit

    Ops invokes one of forty-four named actions, each with the product’s own rules in front of it, and each logged by name as it passes through a pipeline behaviour. The manual route it replaced — an engineer writing an update statement against the database — ran none of those rules and left no record of having run.

  • Support sees the screen, instead of a description of it

    Part of what reached engineering was not a change request but a reproduction problem — someone unable to see what a customer was describing. Impersonation answers that directly: support steps into the nutritionist’s or the patient’s own session, sees what they see, and steps back out. It concentrates a lot of access in one feature, which is why it sits behind the staff identity rather than anywhere near a customer account.