Skip to content

Add feature flags that can be turned on per organisation - #3178

Draft
theseanything wants to merge 8 commits into
mainfrom
organisation-feature-flags
Draft

theseanything wants to merge 8 commits into
mainfrom
organisation-feature-flags

Conversation

@theseanything

Copy link
Copy Markdown
Contributor

What problem does this pull request solve?

Trello card:

Feature flags can be turned on for individual groups, but not for a whole organisation. This adds the same mechanism for organisations, managed by super admins from the organisation page.

  • FeatureService.new(organisation:).enabled?(:some_feature) checks features marked enabled_by_organisation: true in the settings, using a matching <feature>_enabled column on organisations.
  • Organisation features are separate from group features. A feature is scoped to one or the other, and callers pass the organisation explicitly.
  • A new page at /organisations/:id/feature-flags lets super admins turn flags on. As with groups, flags cannot be turned off there: the input only ever sets them to true, and flags that are already on are shown checked and disabled.
  • The organisation page has a new "Feature flags" table showing each flag's status, with a link to manage them.

No feature is organisation-scoped yet. This is the mechanism only, so there is no migration, and the only visible change is the new section on the organisation page saying there are no organisation feature flags available. The README explains how to add one.

The hint on the group feature flags page has been reworded to match the new organisation page.

Things to consider when reviewing

  • Because there is no real organisation flag, the input, request and view specs stub Organisation.feature_flag_attributes to use the existing internal and closed columns as stand-ins.
  • To try the full flow locally, add an organisations.<name>_enabled column and an enabled_by_organisation: true entry in config/settings/development.local.yml.
  • Is the copy on the new page and in the empty state right?
  • Do the commit messages explain why the changes were made?
  • Has all relevant documentation been updated?

Features can be turned on for a single group by marking them as
enabled_by_group. Some features make more sense to turn on for a whole
organisation, and enabling them group by group does not cover groups
created later.

Add an enabled_by_organisation setting, which is checked against a
matching `<feature>_enabled?` method on the organisation passed to the
service. This is separate from group features: a feature is scoped to
one or the other, and callers pass the organisation explicitly.
The pages for managing organisation feature flags need to know which
flags exist. As with groups, derive them from the features marked
enabled_by_organisation in the settings that also have a matching
`<feature>_enabled` column on the organisations table.

No feature is organisation-scoped yet, so the list is empty for now.
The settings spec checks that any flag column added later comes with
a settings entry and a label.
Super admins need a way to turn a feature on for an organisation
without asking a developer. Add a page under an organisation that
lists its feature flags as checkboxes, following the equivalent page
for groups.

Flags can only be turned on. Enabling a feature can change an
organisation's groups or forms in ways that need manual work to
reverse, so the input only ever sets flags to true and the page shows
flags that are already on as checked and disabled.

Reword the hint on the group feature flags page to match the new
page, so both explain the rule in the same way.

There are no organisation flags yet, so the specs use existing boolean
columns on the organisations table as stand-ins.
Super admins had no way to see which features an organisation has
turned on, or to reach the page for turning them on. Add a table of
the organisation's feature flags and their status to the organisation
page, with a link to manage them.

When there are no organisation feature flags, show a message instead
of an empty table and a link to an empty form.
The README only covered global flags and the settings-based
organisation override, so adding a flag that super admins can turn on
for a group or an organisation meant reading the code.

Explain the steps for adding one, and fix the FeatureService example
for users, which was missing the `user:` keyword.
@theseanything
theseanything force-pushed the organisation-feature-flags branch from b88092b to c70050e Compare October 7, 2026 07:49
FeatureService called `<feature>_enabled?` on the organisation without
checking it exists. A feature marked enabled_by_organisation before
its migration had been deployed, or with a typo in its name, would
raise NoMethodError and give users a 500, while the feature flags
page silently left the flag out.

Return false when the organisation has no such method, so the feature
stays off until its column exists.

Add a settings spec that every enabled_by_organisation feature has a
matching column, so a typo or a missing migration fails in CI rather
than leaving the feature quietly off.
The organisation feature flags page was built by copying the group
one, so the model method, input object and form view each existed
twice. A fix made to one copy had to be repeated in the other: the
group page still showed a flag as checked and locked after a failed
save, which had already been fixed for organisations.

Move `feature_flag_attributes` into a FeatureFlaggable concern that
works out the settings key from the model name, replace the two input
objects with one FeatureFlagsInput that takes a record, and render
both pages from a shared form partial. The form params are now under
`feature_flags_input` on both pages.

Simplify the input while merging the copies. It used to define an
accessor per flag on each instance's singleton class and look the
flags up from the settings several times a request. It now looks them
up once and keeps the ticked flags in an array. The controllers no
longer build a permit list, as the input only reads the flag
attributes from the submitted params.
The shared feature flags form looks labels up with
`t(flag, scope: label_scope)`, which i18n-tasks cannot trace back to a
key. Since the group page moved to that partial, the three
`groups.feature_flags.flags.*` labels were reported as unused and
spec/i18n_spec.rb failed, although the labels are still rendered.

Add the keys to `ignore_unused`. The organisation labels need no entry
because the organisation page looks them up with a literal key prefix.
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

🎉 A review copy of this PR has been deployed! You can reach it at: https://pr-3178.admin.review.forms.service.gov.uk/

It may take 5 minutes or so for the application to be fully deployed and working. If it still isn't ready
after 5 minutes, there may be something wrong with the ECS task. You will need to go to the integration AWS account
to debug, or otherwise ask an infrastructure person.

For the sign in details and more information, see the review apps wiki page.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant