Sorry, you need to enable JavaScript to visit this website.

Drupal

Environment Detector, one reliable answer to where your site is running

The question a site answers before anything else: which environment is this?

A surprising amount of what a website does depends on knowing where it is running:

  • debug output belongs on a developer's machine and nowhere near the public site
  • caching should be aggressive in production and out of the way while someone is working
  • sample content and test users are useful in a throwaway preview build and unwelcome anywhere else
  • emails should only reach real customers from the real site

So every project asks the same question early in its startup: what kind of environment is this?

The awkward part is that each hosting platform answers it differently, with its own signals and its own vocabulary for its tiers, so the environment a team integrates in goes by a different name on each one.

The result is familiar. Each project grows its own small block of detection code, written fresh, a little different from the last one.

It holds up until a platform adds a tier or a project gains an environment that block was never told about. Then the site behaves as though it were somewhere else, in the one place where being wrong is expensive.

One call, nothing to configure: 6 environment types

environment-detector(Opens in a new tab/window) answers the question in a single call, with no setup. It resolves the environment to one of 6 types:

  • local
  • CI (an automated build)
  • development
  • preview
  • stage
  • production

Everything else in the codebase simply branches on the answer.

It recognises where that code is running:

  • the hosting platforms teams actually run on: Acquia, Lagoon, Pantheon, Platform.sh, Skpr and Tugboat
  • the automated build systems where the same code also runs: GitHub Actions, GitLab CI and CircleCI
  • what it is sitting in underneath: a plain machine, a container, or a local development tool such as DDEV or Lando

Telling a preview apart from development is worth more than it sounds. A short-lived environment built for a single change is not the shared space a team integrates in, and once the difference is visible in code, the settings that follow can finally be right.

For a client, that reads as a preview link that behaves like a preview, and a production site that behaves like production.

Built so a wrong answer is loud: it stops instead of guessing

A detector is only worth having if you can trust it, so the design prefers certainty over cleverness.

A single hosting platform can be active at a time. If 2 announce themselves at once, that is a genuine misconfiguration rather than a riddle to solve, so the library stops instead of guessing.

When a platform is active but cannot place an environment in a tier it recognises, the fallback leans the safe way, towards a shared development environment, and it does not downgrade a platform already known to be production.

There are 2 failures worth engineering against: local settings reaching the live site, and production settings reaching a laptop. The design guards against both rather than relying on everyone remembering.

For a client, that reads as one less way for a site to misbehave after a deploy: debug output, caching and test data follow the environment the code landed in.

One line in a Drupal settings file, and a plain call anywhere in PHP

For Drupal(Opens in a new tab/window) the integration is a single line in the site's settings file. That line works out the environment and applies the settings that belong with it, so trusted hosts, file paths and caching are correct wherever the code has landed, with no per-project block to maintain.

Outside Drupal it works through a plain call in any PHP application. It is also built to be extended, with the same pieces the built-in platforms and frameworks use.

Drupal is the framework integration that ships today, and the model underneath it was designed to be framework-agnostic from the start.

Why we keep it public: shipped in Vortex, free to adopt

Solving this once is the entire argument. It ships as part of Vortex(Opens in a new tab/window), our open-source Drupal project template, so every project we start already knows where it is running, and supporting a new host becomes a package update rather than an edit in every codebase.

One call, 6 environment types, and the same answer on every supported host.

It is open source and free to use, published on GitHub(Opens in a new tab/window), so any team can adopt it without ever speaking to us. That is deliberate.

This is unglamorous plumbing, it is the same in every project, and no budget should be paying to write it a second time.

When we take on a platform, that habit comes with us: the generic parts are already solved, so the effort goes where your platform is actually different.

For teams whose environment logic is hand-written in every project

Everything on this page is 2 of our services pointed at our own tooling: the development of the library itself, and the ongoing support and maintenance that keeps it current as hosting platforms change. The same standard applies to our AI-assisted delivery: whatever writes the change, the environment it lands in is decided by one tested library rather than by a block of code copied between projects.

If you run a Drupal or PHP platform whose settings file carries its own environment logic, or a team working across several hosts that each name their tiers differently, this is the shape the engagement takes. The detection moves into one tested library, the per-environment settings follow from it, and adding a host later is a version bump instead of an edit in every repository.

If nobody on your team can say for certain what your production site would do on the day it decided it was staging, send us your settings file.

A Defence portfolio agency's website, built to a government design system

When the design system is already decided: a fixed identity and a fixed date

If you are standing up a public website inside a government identity, most of the visual decisions were made before your project started. The typography, the colour, the header, the footer and the accessibility bar all arrive as a standard you have to meet, and the launch date is usually set at the same time.

What is left to decide is how the site gets built. Which components exist, what each one is worth, and where the effort actually sits. That last question is where the cost hides, because the effort rarely lands where people expect it to.

How we came into the work: Drupal build partner behind a Canberra agency

In 2024 a Canberra digital agency working across Australian federal government brought us in as their Drupal(Opens in a new tab/window) build partner on a public website for a Defence portfolio agency. Their team carried the client relationship, the design and the delivery management. We provided the estimating and the Drupal engineering behind it, front end and back end.

That split works well for both sides. The agency keeps its client relationship whole and keeps owning the work it does best, while the build capability sits behind it without the client having to manage 2 conversations.

Mapping the build feature by feature: 2 figures on every line

Before any code, we mapped the site feature by feature and costed every line twice, once for the back end and once for the front end. Header, footer, banners, breadcrumbs, side navigation, the landing page system, news, search and the content migration all sat on one sheet with 2 figures each.

3 useful things fall out of an estimate shaped that way:

  • the front end carries most of the cost, roughly 60 percent of the total on this build, which is the reverse of what most people assume
  • accessibility gets a price, with skip-to-main-content and the Acknowledgement of Country appearing as their own costed lines rather than being folded into other features
  • contingency stays in the open, sitting beside the base figure as its own line, which makes it something to discuss rather than something to absorb

Mobile navigation alone was an order of magnitude heavier on the front end than on the back. If a design-system site has ever felt more expensive than it looked, that ratio is why.

Naming the accessibility lines makes them visible, and visible things are harder to drop quietly when a number has to come down. For a client, that reads as a priced map rather than a single number: you can see what each component is worth before anyone commits to it.

What we built: a landing page system, news, search and a content migration

The site carries the full set of parts a public government site needs:

  • a landing page system with sliders, embedded frames, and card lists that either assemble themselves from published content or are curated by hand
  • news with authors, related links and its own search
  • a results page for site-wide search
  • content pages carrying resources and related links alongside the body

Underneath that sits the furniture a government site lives on: static and video banners, breadcrumbs, side navigation, a back-to-top control, a skip link, an Acknowledgement of Country in the footer, and content styling for typography, quotes, tables and icons. The existing content came across through a manual migration.

The engagement did not stop at the build. Feature work continued into 2025, a year on from the original build. For an agency partner, that reads as continuity: the team that built the components is the team that extends them.

What we kept from it: the dual estimate for component-heavy builds

The dual estimate is now how we cost component-heavy builds. One sheet, 2 figures per feature, accessibility priced on its own line, contingency stated separately.

On this build, roughly 60 percent of the estimate sat in the front end, the reverse of what most people assume.

It gives a client something more useful than a blended number: a picture of where the money actually goes, and 2 halves that can be sequenced, resourced or trimmed independently of each other. For an agency partner, it is also a far easier conversation to have with an end client than a lump sum.

For teams building inside a design system they did not choose

Everything on this page is 2 of our services on one government website build: Drupal development across the front end and the back end, to an identity that was already set, and a manual migration of the existing content. The feature-by-feature estimate sat in front of both.

If you are a digital agency carrying a government client, or a team standing up a public site inside a design system you did not choose, this is the shape the engagement takes: a build partner behind your own team, an estimate that prices every component twice, and accessibility and contingency named as their own lines. The same engineering is available with AI-assisted delivery where it suits the work.

If you are pricing a design-system build and want to know where the effort will actually land, send us the component list.

Moving a federal statutory body's website onto CivicTheme

When the website is the public record: a federal publication estate

Some organisations have a website because they need one. Others have a website because it is the record. If your work is to give public advice, the site is where that advice gets published, cited, downloaded and checked again years later, long after the news cycle that produced it has moved on.

The organisation here is an independent federal statutory body that advises government on national policy. Its website carries:

  • annual reports
  • corporate plans
  • strategic frameworks
  • the outcomes of its meetings
  • public submissions filed by industry and community organisations

The people who come looking are usually after a specific document.

That is a publication estate, not a brochure site. It sets a different bar: findable, readable, accessible, and stable for a very long time.

Our part in the work: a CivicTheme migration in 2023

We were brought in for a single job: to move the site onto CivicTheme(Opens in a new tab/window), the Australian government design system. We help build and maintain CivicTheme itself, so this was familiar ground. A migration onto a design system tends to go faster when the people doing it know why each component is shaped the way it is.

It was a short and precise engagement in 2023. Across it we:

  • built the site's CivicTheme sub-theme and the configuration around it
  • set up the front-end build and the component workflow the theme depends on
  • added the local tooling the next developer would reach for
  • handed the platform back

The organisation's own team and its partners have carried the site forward since, which is how a migration should end.

Theme and configuration only: building where the platform allows no custom code

The site runs on a shared government hosting platform. There are no custom modules on that platform, and there structurally cannot be. Core, the distribution and the contributed modules all arrive in the platform image, and an automated check refuses a deployment if anything unexpected turns up in it.

That sounds like a limit on what you can build. It is really a limit on how. Everything we delivered lives in the theme and in configuration, and that turns out to be a discipline rather than a compromise:

  • no bespoke module to maintain
  • no bespoke upgrade path to plan around
  • a platform free to keep the software underneath the site patched

For a client, that reads as fewer things to own: what we hand back is a theme and a set of configuration, not a codebase somebody has to keep alive.

Constraints like these reward knowing the platform well. The front-end build had to fit a host that runs no build step of its own, and the platform's own code checks had to pass cleanly on files that nobody writes by hand. Both are the kind of problem you solve once and then stop paying for.

What a design system actually buys you: a stock content model

The site uses CivicTheme's content model exactly as it comes: no bespoke content types, no bespoke fields.

That is easy to skim past, and it is the whole cost argument for design systems. Every custom field is something a person has to understand, document, test and carry through the next upgrade, indefinitely.

A federal publication estate needed none of them, because the design system already covered the job. What is left to look after is a thin layer of styling on top of a library that other people keep improving. For a client, that reads as a maintenance bill that stops growing: the fields nobody built are the fields nobody has to test, document or upgrade.

Accessibility works the same way. In a design system it is a property of the shared components, maintained once for everyone who uses them, rather than a line item in each agency's budget.

Where it landed: live on CivicTheme, carried on by the organisation's own team

The site is live and runs CivicTheme.

A federal publication estate rebuilt on a shared design system, with no bespoke content types and no bespoke fields.

Our part was brief and deliberately so. A migration done well ends with a client who no longer needs the specialists, and that is what happened here: development continued in the hands of the organisation's team and its partners.

The design system underneath is still maintained and still improving, and the site inherits that work without commissioning any of it.

For government sites that have to stay findable for years

Everything on this page is 2 of our services on one federal publication estate: a migration onto a government design system, and the development that makes that design system fit a hosting platform which allows no custom code.

If you run a site whose value is the documents on it, an agency, a statutory body or a regulator, this is the shape the engagement takes: a short bounded migration, everything delivered in theme and configuration, and a handover to the team who will run it afterwards. The same work is available with AI-assisted delivery where it suits the job, at the same tested standard.

If your site still carries a bespoke theme, and every accessibility fix and every new component lands on your own budget, ask us what moving onto CivicTheme would take.

Climate Change Authority CivicTheme migration

When the website is the public record: a federal publication estate

Some organisations have a website because they need one. Others have a website because it is the record. If your work is to give public advice, the site is where that advice gets published, cited, downloaded and checked again years later, long after the news cycle that produced it has moved on.

The Climate Change Authority is an independent statutory body that advises the Australian Government on climate policy: emissions reduction targets, the Emissions Reduction Fund, the Renewable Energy Target, the Carbon Farming Initiative.

Its website carries that record:

  • annual reports
  • corporate plans
  • strategic frameworks
  • the outcomes of Authority meetings
  • public submissions filed by industry and community organisations

More than 1,000 documents, and the people who come looking are usually after one specific thing.

That is a publication estate, not a brochure site. It sets a different bar: findable, readable, accessible, and stable for a very long time.

Our part: the CivicTheme sub-theme, build and configuration

We were brought in for one thing: to move the site onto CivicTheme(Opens in a new tab/window), the Australian government design system. We help build and maintain CivicTheme itself, so this was familiar ground. A migration onto a design system tends to go faster when the people doing it know why each component is shaped the way it is.

It was a short and precise engagement in 2023. We delivered:

  • the site's CivicTheme sub-theme and the configuration around it
  • the front-end build and the component workflow the theme depends on
  • the local tooling the next developer would reach for

Then we handed the platform back. The Authority's own team and its partners have carried the site forward since, which is how a migration should end. For a client, that shape reads as a bounded cost: a specialist engagement with an end date, not a dependency.

Building inside GovCMS SaaS, a platform that allows no custom code

The site runs on GovCMS(Opens in a new tab/window) SaaS, the Australian Government's shared Drupal(Opens in a new tab/window) platform. There are no custom modules on that platform, and there structurally cannot be. Core, the distribution and the contributed modules all arrive in the platform image, and an automated check refuses a deployment if anything unexpected turns up in it.

That sounds like a limit on what you can build. It is really a limit on how. Everything we delivered lives in the theme and in configuration, and that turns out to be a discipline rather than a compromise:

  • no bespoke module to maintain
  • no bespoke upgrade path to plan around
  • a platform free to keep the software underneath the site patched

Constraints like these reward knowing the platform well. The front-end build had to fit a host that runs no build step of its own, and the platform's own code checks had to pass cleanly on files that nobody writes by hand. Both are the kind of problem you solve once and then stop paying for.

What a design system actually buys you: no bespoke content types or fields

The site uses CivicTheme's content model exactly as it comes. Not one bespoke content type, not one bespoke field.

That is easy to skim past, and it is the whole cost argument for design systems. Every custom field is something a person has to understand, document, test and carry through the next upgrade, indefinitely. A federal publication estate needed none of them, because the design system already covered the job.

What is left to look after is a thin layer of styling on top of a library that other people keep improving. For a client, that reads as a smaller bill to carry: you maintain the styling, not the system underneath it.

Accessibility works the same way. In a design system it is a property of the shared components, maintained once for everyone who uses them, rather than a line item in each agency's budget.

Where it landed: live on CivicTheme, carried by the client's own team

The Climate Change Authority's website is live at climatechangeauthority.gov.au(Opens in a new tab/window) and runs CivicTheme.

More than 1,000 documents on a federal publication estate, and not one bespoke content type behind them.

Our part was brief and deliberately so. A migration done well ends with a client who no longer needs the specialists, and that is what happened here: development continued in the hands of the Authority's team and its partners.

The design system underneath is still maintained and still improving, and the site inherits that work without commissioning any of it.

For agencies whose website is the public record

Everything on this page is 2 of our services on one federal publication estate: a migration onto a government design system, and development delivered entirely in theme and configuration on a platform that allows no custom code.

If you run a GovCMS site, or any publication estate that has to stay findable and accessible for years, this is the shape the engagement takes: a short specialist migration onto CivicTheme, a stock content model wherever the design system already covers the job, and your own team carrying the site afterwards. The same work is available with AI-assisted delivery where it suits the scope.

If you are weighing a move onto CivicTheme, or wondering what GovCMS SaaS will and will not let you build, tell us what your site has to keep publishing.

CivicTheme, an open-source design system for government

Everyone builds the same components, separately: navigation, cards and accessible forms

Every public-sector website needs the same handful of things:

  • a navigation people can actually use
  • a card, a button, a form that works with a screen reader
  • pages that read unmistakably as official

Most organisations pay to build all of it again, from scratch, on every project.

The cost is not only the first build. It shows up again when a component changes and nobody can say which of your sites carries which version, and again when accessibility arrives late as a remediation ticket rather than early as a default. And the sites drift apart until services meant to feel like one government no longer do.

A shared design system converts that repeated spend into a single maintained asset. Designing one is the easy half. The hard half is maintaining it so that the teams downstream can take an update without fear.

What CivicTheme is: a UI Kit, a Drupal theme, modules and a Figma source

CivicTheme(Opens in a new tab/window) is an open-source, component-based design system published by Salsa Digital(Opens in a new tab/window). Its own documentation puts the purpose plainly: it was created "so governments and corporations can rapidly assemble modern, consistent and compliant digital experiences".

4 parts ship, and they stay in step:

  • a CMS-agnostic UI Kit of components built with HTML, CSS and JavaScript, browsable in Storybook
  • a Drupal(Opens in a new tab/window) theme that connects the content model to those components
  • supporting modules, including one that adapts the theme to the federal GovCMS(Opens in a new tab/window) platform
  • a Figma design source that carries the same version number as the code, so a designer and a developer are provably looking at the same release

Accessibility sits in the baseline rather than in each agency's budget. The documentation is explicit: "The components have been built and assessed to comply with WCAG accessibility standards 2.1 AA out-of-the-box."

Our part in the work: architecture, release engineering and maintenance since 2021

Salsa Digital publishes CivicTheme, hosts it and runs its community. We wrote its first commit in September 2021 and have provided the engineering behind it ever since:

  • architecture of the component system
  • development of the components, the theme and the supporting modules
  • release engineering, to drupal.org and to npm
  • ongoing maintenance as Drupal, PHP and GovCMS move forward

Everything is developed in one repository and published out to the separate ones people install from. Develop together, ship separately: that one decision lets a small team keep a theme, a component library, companion modules and a documentation site moving in step.

Underneath it, the build and continuous integration run on our own open-source project tooling, the same tooling we bring to client platforms. For a client, that reads as inheritance: the build and test discipline behind a public design system arrives with us on your own platform.

Making an update safe to take: visual regression and schema update tests

Components exist in 2 forms, Twig templates and Drupal Single Directory Components, so that Drupal consumers and non-Drupal consumers each get the implementation they need. Keeping 2 versions of every component honest by hand would be untenable, so parity is machine-enforced: tooling synchronises them, and a check command fails the build the moment they drift.

The primary defence is visual. A unit test cannot tell you that a button moved 4 pixels, and teams downstream notice.

So every pull request captures screenshots of the components, publishes a side-by-side comparison and posts the link back into the review conversation where someone will actually read it. The same pipeline does double duty: one comparison catches a visual regression against the released version, the other catches drift between the 2 component implementations.

Then there is the question every organisation actually asks: what happens to our site when we take the update? Because the system ships configuration for content types, fields and site settings, updates are rehearsed against committed database snapshots, both schema-only and schema-with-content, before they reach anyone.

For a team downstream, that is what makes an update routine rather than a project: the change has been rehearsed against a database shaped like yours before it reaches you.

Release rules follow the same instinct: on drupal.org, where a release cannot be deleted, only the development branch is ever pushed.

Where it is now: Drupal 10 and 11, GovCMS, and 4 content profiles

Live and in service. Published on drupal.org and on npm, documented at docs.civictheme.io(Opens in a new tab/window), with the component library and a live demonstration site online.

4 industry content profiles ship alongside a default:

  • Corporate
  • Government
  • Higher Education
  • Health

Each is a complete worked example rather than a starter shell, so a team can watch the system do the job before committing to it.

It tracks the platform forward: Drupal 10 and Drupal 11, current PHP, GovCMS support kept current. A steady release cadence has carried it across 4 years, with a pre-release channel so teams can test a release candidate before they take it.

A single maintained design system, 4 industry content profiles, and 4 years of steady releases.

4 years on, we are still the engineering behind it.

For teams rebuilding the same components on every site

Everything on this page is 4 of our services running on one public open-source design system: the architecture of the component system, the development of the components and modules, the DevOps and release engineering that ships them, and the ongoing support and maintenance that keeps all of it current. The same standard applies to our AI-assisted delivery: whatever writes a component, the visual comparison and the schema update tests are what decide it is safe to release.

If you run a government agency, a university, or any organisation with a family of sites that keep drifting apart, this is the shape the engagement takes: a component library that is genuinely shared, accessibility in the baseline rather than in a remediation ticket, and updates rehearsed before they reach your site.

If you are weighing up CivicTheme for your next site, or you already run it and want taking an update to be routine, tell us which sites you are trying to keep in step.

Behat Steps, ready-made Behat test steps for Drupal

The tests every Drupal project writes twice: logins, content, email, logs

Automated tests for a website are usually written in near-English, a sentence per action. "Given I am logged in as a user with the administrator role." "Then an email should be sent to the applicant."

That is deliberate: the people who decide what a site must do can read what is being checked.

Behind each of those sentences sits real code. Someone has to implement, in PHP, what "logged in as an administrator" means, what counts as an email being sent, and how a test knows a file actually downloaded.

And the sentences repeat from project to project:

  • sign in as a role
  • create content
  • check an email went out
  • confirm nothing landed in the site's error log

Writing them the first time costs a few days. Keeping them is the part nobody budgets for.

They live in your repository, and they need attention every time Drupal(Opens in a new tab/window) moves. They are never what your project is actually about, and when they break, testing quietly stops.

A library you take a piece at a time: Behat steps as PHP traits

behat-steps(Opens in a new tab/window) is that set of steps, written once, tested and maintained. It ships as PHP traits, so a project imports the pieces it wants and nothing else.

Take the email assertions without inheriting anything you did not ask for, and keep every step your team has already written sitting alongside them.

Small parts rather than a single base class is what makes the library safe to adopt gradually. You add a piece, nothing you had before changes, and you decide about the rest later.

It covers the common ground of Drupal testing:

  • authentication and roles
  • content
  • email
  • file downloads
  • media
  • error-log checks

For a client, that reads as a shorter start: the test suite on your project begins with the common ground already written and already maintained.

Where it came from: a Drupal test context cut from 300 lines to 46

It started on a real project in 2018, a Victorian government health department website reached through a government digital agency.

That project had built itself a thorough set of test steps:

  • email assertions
  • file downloads
  • media handling
  • error-log checks

All of it solid work, and none of it specific to a health department.

So we pulled the generic parts out into a package we would maintain. The project's own test class went from roughly 300 lines of bespoke step definitions to 46 lines that simply compose the imported ones, with every check it had before still in place.

The department kept its coverage and stopped owning the plumbing underneath it. Every project we have worked on since has had those steps for free.

The decisions that make it safe to rely on: strict error-log checks

A library like this earns trust in the details. Checking Drupal's error log after every scenario is the classic source of false alarms, because some scenarios are supposed to trigger an error.

The easy answer is to soften the check for everyone. Instead, a test can declare that it expects an error, so the check stays strict everywhere else.

Sometimes the behaviour that needs adjusting sits further upstream, in the shared Drupal testing driver the library builds on. When that is the right home for a fix, it goes there rather than being worked around on every project, and we have been contributing to that driver for years.

Where it ended up: whole-of-government Victoria and community radio

A library extracted from a single health department project went on to underpin the Victorian Government's Single Digital Presence, the shared platform behind vic.gov.au and the agency sites around it. Years later it was doing the same job on a community radio station's rebuild.

It ships as part of Vortex(Opens in a new tab/window), our open-source Drupal project template, so every project we start inherits it.

It has been maintained since 2018, across Drupal 7 through to Drupal 11, which is a long time for a package to stay useful in a platform that changes as much as Drupal does.

300 lines of test glue became 46 lines of composition, and a package maintained since 2018 across Drupal 7 to Drupal 11.

It also carries contributions from developers with no connection to DrevOps. People do not send patches to code they are not depending on.

For a client, that track record is the point: the steps your suite depends on have outlived the projects that introduced them.

What it adds up to: Drupal testing that starts already built

The library is public, so any Drupal team can use it without ever talking to us. Testing gets skipped when it is expensive to start, and the quickest way to make it cheap is to stop asking every project to rebuild the same foundations.

When we take on a platform, that groundwork is already done and maintained. The effort goes into the parts that are actually yours.

For teams rewriting the same Drupal test steps

Everything on this page is 2 of our services pointed at our own tooling: development of the library, and the ongoing support and maintenance that has kept it current from Drupal 7 through to Drupal 11. The same standard applies to our AI-assisted delivery: however fast the code arrives, the automated checks are what decide it is safe to ship.

If you run a Drupal site whose test suite nobody wants to open, or a team writing the same step definitions on every new project, this is the shape the engagement takes. The generic steps come from a maintained library, your own steps sit beside them, and the only checks you own are the ones specific to your business.

If your last Drupal upgrade was verified by hand because nobody trusts the automated suite, tell us what it covers today.

Victorian Department of Health and Human Services websites

When a website is where people go for health, housing and concessions

People arrive at a health and human services website with a real question, often at a difficult moment:

  • someone checking whether they qualify for a concession
  • a parent trying to understand a family service
  • a nurse looking up clinical guidance
  • an adult asking for the records of their own childhood in care

The site either answers the question or it does not.

The Victorian Department of Health and Human Services ran one of the largest web estates in the state, covering consumer health information, concessions, housing, disability, family services, records access, and clinical guidance for the health sector. Many audiences, many editorial teams, one shared expectation that the information will be right and reachable.

Drupal engineering inside the Salsa Digital partnership

The work reached us through Salsa Digital(Opens in a new tab/window), a government digital agency whose teams carried strategy, design and content across the department's properties. We joined as their engineering partner and stayed for 4 years, providing:

Some of it was new architecture. A lot of it was the quieter work of making several teams' releases predictable.

Several audiences, one Drupal codebase and one content platform

3 of the department's public websites, serving citizens, funded organisations and service providers, were consolidated into a single Drupal codebase. One map of the estate drives everything downstream: the build, each site's settings, deployment, the test suite and the theme. Each site keeps its own visual identity through configuration rather than code, so an editorial team can change how their site looks without waiting for a developer release.

A separate content platform then decoupled the department's content from its presentation, so several front ends could share one editorial spine. It carried a consumer health encyclopaedia, professional guidance published as open data, service directories with eligibility and access details, and a records access service. Editors describe intent, such as whether a page offers text to speech or a printable version, and each front end decides how to honour it.

Built for the people on the other end: accessibility and a link-safe migration

The front ends built on that platform are server-rendered JavaScript applications, and 2 things matter about how they behave. Every part of a page is assembled independently, so one troublesome component degrades on its own instead of taking the page with it.

The second is accessibility, treated as implementation rather than aspiration:

  • screen-reader headings
  • focus management on dialogs
  • proper tab and panel semantics for medical citations
  • built-in text to speech

Migration mattered for the same reason. People bookmark government pages, print them, cite them in letters and share them in community groups, and search engines have years of them indexed.

The migration was built so those links survived: content from the legacy system was rebuilt as structured, reusable page components, and old-style page and document addresses were resolved on the new platform and served the right file. For a client, that is what a link-safe migration buys: the address saved in a bookmark or printed in a letter still leads somewhere after launch day.

Built once, released safely: containers and continuous integration

Underneath all of it we changed how the code was built and shipped. In 6 days in 2018, a live government Drupal site moved onto containers and managed dependencies, with the application built exactly once, in continuous integration, and that identical build used everywhere afterwards.

One self-documenting set of commands ran it, so every developer and the pipeline did the same thing. Releases were designed to fail quietly: a dry run by default, and a release that did not complete cleanly left visitors seeing the site exactly as it was. For a client, that is what a safe release means: a release that does not land costs you a wait, not a broken site.

What it left behind: 2 open-source tools still shipping

We worked across 4 of the department's properties over 4 years, and the tooling outlived the engagement.

2 things that began as answers to real problems on these sites are open source today and still maintained. drevops/behat-steps(Opens in a new tab/window), a library of reusable automated test steps for Drupal, was extracted from the department's sport and recreation site and later became a dependency of the Victorian Government's central content platform.

And the containerised project template built in that week in 2018 is the direct ancestor of Vortex(Opens in a new tab/window), the open-source Drupal project template we ship on every project today.

4 properties over 4 years, and 2 of the tools built for them are open source and maintained today.

That is the part we are proudest of: solving a real problem twice, then giving the answer away.

For government estates where the information has to be right

Everything on this page is 4 of our services running across one government web estate: architecture and development on a shared Drupal codebase, content migration that keeps the addresses people already have, build and release engineering, and accessibility built in rather than bolted on.

If you run a government web estate, a health service, or several public sites that share one editorial team, this is the shape the engagement takes: one codebase behind several sites, migrations that keep existing addresses resolving, and releases safe enough to be routine. The same engineering is available with AI-assisted delivery where it suits the work, at the same tested standard.

If your estate has spread across several ageing sites, or a migration is coming and the links people already have worry you, tell us what the estate looks like.

An energy retailer's website, where signing up is the hard part

When a website has to sell a regulated product: energy pricing before a quote

Most websites show a price. An energy retailer's website has to work one out first.

Before anyone can be quoted, the platform has to establish:

  • which meter sits at their address
  • which distributor serves it
  • which tariffs apply
  • which offers may legally be sold in that state

Only then is there a number to put on the screen. That chain runs live, while someone waits on a form.

Everything attached to it is regulated too, from the fact sheet that accompanies every offer to the wording on the offer itself. It is a transaction engine wearing a website's clothes, and it still has to stay editable by the marketing team.

Our part in the work: Drupal architecture and the delivery toolchain

The client is a national energy retailer, selling electricity and gas to households and small businesses across several states and territories. In 2020 it replatformed its public website onto Drupal(Opens in a new tab/window).

We were engaged through a partner agency, which ran the delivery programme, as the Drupal architecture and platform engineering partner, while a specialist design agency supplied the experience design.

Alongside the architecture, we stood up and ran the delivery toolchain the whole engineering team worked through:

  • the source-control organisation
  • the continuous integration account
  • the automated code quality checks
  • a containerised local environment so every developer ran the same stack

For a client, that shared setup reads as consistency: every developer on the programme worked to the same checks, whoever they worked for.

The brief itself was easy to state and hard to build: let the marketing and sales teams manage their own offers and content.

5 sign-up journeys, and one of them is moving house

The platform carries 5 separate sign-up journeys rather than one, because a household, a home office, a small business and a specialist offer are each sold and priced differently. The main one is a 5-step checkout.

Moving house has its own 7-step flow. Relocating is the highest-intent moment in energy retail, and it asks different questions: when the power needs to be on, and what a technician will find at the property.

That last part is what separates this from an ordinary web form. The output of the funnel is a work order for someone who will physically attend a house.

Around them sit the things regulation requires:

  • energy fact sheets issued as part of the flow
  • separate concession forms for the states that administer them their own way
  • payment handled by dedicated providers

An address is not an address: validating it into a regulated meter identity

The hinge the whole funnel turns on is a translation the customer never sees. Someone types a street address the way they would write it on an envelope.

The platform validates it, then converts it into the shape the national electricity market registry expects, so a typed address becomes a regulated meter identity.

If one meter matches, the journey continues without the customer noticing. If several do, they pick from a short list. Electricity and gas resolve separately.

Everything downstream depends on that one step. Without a meter identity there is no distributor, without a distributor there are no tariffs, and without tariffs there is nothing that can lawfully be sold. It looks like a form field and it is actually the architecture.

Editable by the people who own the offers: a content model marketing can run

Energy offers change often and their presentation is regulated, so the people accountable for the wording need to change it without waiting for a release.

The offer model was built so every element of an offer card is separately editable, and page structure lives in a visual layout builder rather than in code. Giving the business that control was the stated goal of the replatform, and it is the part that outlasts a redesign.

For a marketing team, that reads as autonomy: changing the wording on an offer is a content edit, not a release.

What we carried forward: request logging and integration health

2 ideas from this build have shaped how we approach integration-heavy platforms since.

The first is request-scoped debug logging: when one page depends on a dozen live calls to other systems, you want the story of a whole request in one place, not scattered across log lines.

The second is treating the health of those integrations as a feature, so anyone can see which upstream systems are answering. We have since built that idea into a package of our own.

5 sign-up journeys and a 7-step move-home flow, all hanging off a single address lookup.

Most people picture Drupal as a content site. This was a regulated transaction engine with a content site attached, and the content management was the least interesting part of it.

For platforms where signing up is the product

Everything on this page is 3 of our services running on one regulated acquisition platform: Drupal architecture for a transaction-heavy build, development against live upstream systems, and the delivery toolchain and containerised environments the engineering team worked through.

If you sell a regulated product online, in energy, insurance or telecommunications, this is the shape the engagement takes: an architecture built around the one lookup everything downstream depends on, sign-up journeys designed per customer type, and a content model the business can change without a release. The same engineering is available with AI-assisted delivery where it suits the work.

If your sign-up funnel is the slowest part of your platform to change, or your quoting depends on systems you do not control, tell us what the funnel has to do.

An economic regulator's website, migrated without losing the record

When the website is the public record: a regulator's statutory publication channel

The organisation behind these websites is a state economic regulator. Its work is public and procedural:

  • it sets the maximum prices people pay for essential services
  • it licenses some of the utilities that provide them
  • it runs formal public reviews with consultation periods, submissions and hearings

Its website is not a brochure. It is the regulator's statutory publication channel, and a determination is published at the moment it appears there.

The organisations it regulates, and the lawyers who advise them, cite that site, and those citations are expected to keep resolving for years. So the content cannot simply be copied across. Every document has to arrive with its identity, its dates, its attachments and its editorial state intact, which makes a replatform a records problem long before it is a website problem.

Migration architecture and platform engineering inside a government programme

A partner agency led the programme and brought us in as their engineering partner for the move onto a government-managed Drupal(Opens in a new tab/window) platform. We worked across both properties, the regulator's main site and a second site for one of the schemes it administers, and provided:

  • migration architecture
  • platform development
  • front-end engineering

Government delivery is rarely a single team. Several suppliers and the regulator's own developer all worked in the same codebase alongside the design and content teams, and keeping that shared build coherent was part of our work.

2 systems, a single set of documents, reconciled across 3 identifiers

The documents the site publishes did not live in the old website. They live in the regulator's enterprise records management system, held as formal records with their own numbers and revisions.

That left 2 sources describing the same material, each holding half the answer. The legacy site knew which document belonged to which review, in what order and on what date. The records system held the authoritative file.

The same document could also be known by 3 different identifiers, depending on which system you asked. So we built the reconciliation. A single lookup resolves a document across all 3 and settles which wins.

Anything the records system has not yet sent gets a placeholder, so a review can be assembled now and completed on the next sync.

A migration you can run more than once, without republishing what was withdrawn

A migration this size is never a single run. You run it, review what landed, correct something, run it again, and that only works if the second run recognises what the first one created.

Legacy pages were known by their web addresses, so we derived each item's identifier from its own path: same path, same identifier, every run. Reviews that reference other reviews are built in a second pass. For a client, that is the difference between a migration you can rehearse and one you get a single attempt at.

The decision we would lead with, though, is smaller and matters more. If an editor had unpublished a page, re-running the migration left it unpublished. On a regulator's site that is not a nicety: a withdrawn determination that quietly reappears is a regulatory problem, not a content bug.

And we proved the result rather than asserting it, comparing the source data against what actually landed in Drupal.

Where the regulator's publishing rules live: review types encoded in the site

Which documents appear under which tab of a review depends on the kind of review it is, and those rules belong to the regulator, so we encoded them in the site itself. An editor publishes a document once, sees only the fields that apply to that review type, and it lands where the rules say it should.

The public gets a timeline that opens at today, and every review page offers an accessible copy of a document on request. For a client, that means the publishing rules live in the platform rather than in a style guide someone has to remember.

What it added up to: a migration delivered in releases, not a single cutover

The work began in 2020 and the build ran across 2021, released more than 70 times inside that single year. That is a release rhythm rather than a big-bang cutover, which is what most government teams are quietly hoping for. The legacy address structure was kept wholesale, including the front page, so published citations pointed at addresses that still existed after the move.

More than 70 releases inside a single year, then 2 years of upgrades by the next team.

Then we handed it over, and it kept going: the team that received the platform carried on releasing and upgrading it through the next 2 years of Drupal work. For a migration, that is the outcome worth measuring. Not only that it landed, but that the next team could keep it moving.

For migrations where the content carries legal weight

Everything on this page is 4 of our services on one government replatform: migration architecture, platform development, front-end engineering, and the deployment work that put both sites on a government-managed platform.

If you run a regulator, a department, or any public body whose website is where decisions are formally published, this is the shape the engagement takes: the records reconciliation settled before the content moves, a migration that can be re-run without republishing anything withdrawn, and the legacy addresses kept so published citations still have somewhere to land. The same engineering is available with AI-assisted delivery where it suits the work, at the same tested standard.

If you are replatforming a site whose documents are cited elsewhere, and nobody can yet tell you what happens to those citations, send us the address structure you have to keep.

Independent Pricing and Regulatory Tribunal website replatform

When the website is the public record: a regulator's statutory publication channel

The Independent Pricing and Regulatory Tribunal(Opens in a new tab/window) is the New South Wales independent economic regulator. Its statutory work includes:

  • setting the maximum prices for water, public transport and council rates
  • licensing private water utilities
  • running formal public reviews with consultation periods, submissions and hearings

Its website is not a brochure. It is the regulator's statutory publication channel, and a determination is published at the moment it appears there.

Councils, utilities and the lawyers who advise them cite that site, and those citations are expected to keep resolving for years. So the content cannot simply be copied across.

Every document has to arrive with its identity, its dates, its attachments and its editorial state intact, which makes a replatform a records problem long before it is a website problem.

Our part in the programme: migration architecture on GovCMS

Salsa Digital(Opens in a new tab/window) led the programme and brought us in as their engineering partner for the move onto GovCMS(Opens in a new tab/window), the Australian government's shared Drupal(Opens in a new tab/window) platform.

We worked across both properties, the regulator's main site and the second site for the energy savings scheme it administers. Our part covered:

  • migration architecture
  • platform development
  • front-end engineering

Government delivery is rarely a single team. Several suppliers, the regulator's own developer and the platform operator all worked in the same codebase alongside the design and content teams, and keeping that shared build coherent was part of our work.

2 systems, a single set of documents: reconciling the records

The documents the site publishes did not live in the old website. They live in the regulator's enterprise records management system, held as formal records with their own numbers and revisions.

That left 2 sources describing the same material, each holding half the answer. The legacy site knew which document belonged to which review, in what order and on what date. The records system held the authoritative file.

The same document could also be known by 3 different identifiers, depending on which system you asked. So we built the reconciliation.

A single lookup resolves a document across all 3 and settles which wins, and anything the records system has not yet sent gets a placeholder, so a review can be assembled now and completed on the next sync.

A migration you can run more than once, without republishing withdrawn content

A migration this size is never a single run. You run it, review what landed, correct something, run it again, and that only works if the second run recognises what the first one created.

Legacy pages were known by their web addresses, so we derived each item's identifier from its own path: same path, same identifier, every run. Reviews that reference other reviews are built in a second pass. For a client, that is the difference between a migration you can correct and one you have to redo.

The decision we would lead with, though, is smaller and matters more. If an editor had unpublished a page, re-running the migration left it unpublished.

On a regulator's site that is not a nicety: a withdrawn determination that quietly reappears is a regulatory problem, not a content bug. And we proved the result rather than asserting it, comparing the source data against what actually landed in Drupal.

Where the regulator's publishing rules live: encoded in the site

Which documents appear under which tab of a review depends on the kind of review it is, and those rules belong to the regulator, so we encoded them in the site itself.

An editor publishes a document once, sees only the fields that apply to that review type, and it lands where the rules say it should. For a client, that means the complexity sits in the platform rather than in an editor's training.

The public gets a timeline that opens at today, and review pages offer an accessible copy of a document on request.

What it added up to: 73 releases, then 2 years of upgrades

The work began in 2020 and the build ran across 2021, released 73 times inside that single year. That is a release rhythm rather than a big-bang cutover, which is what most government teams are quietly hoping for.

The legacy address structure was kept wholesale, including the front page, so the addresses behind inbound links and published citations were preserved rather than replaced.

Then we handed it over, and it kept going: the team that received the platform carried on releasing and upgrading it through the next 2 years of Drupal work.

73 releases inside a single year, then 2 more years of upgrades by the team that received it.

For a migration, that is the outcome worth measuring. Not only that it landed, but that the next team could keep it moving.

For migrations where the content carries the risk

Everything on this page is 3 of our services on one government replatform: migration architecture across 2 sources of truth, platform development on a shared government Drupal platform, and front-end engineering that put the regulator's own publishing rules into the site.

If you run a regulator, a department or any site whose content is the public record, this is the shape the engagement takes: a migration you can re-run and correct, editorial decisions preserved across re-runs, and legacy addresses carried across rather than dropped. The same engineering is available with AI-assisted delivery where it suits the work, at the same tested standard.

If your next replatform has to carry documents that live in a records system rather than in the website, tell us where your documents actually live.