Skip to Content
Bronit HotelWhat happens when a module lapses

What happens when a module lapses

A module that can be bought can stop being paid for. What the product does at that moment is the difference between a system that feels modular and one that feels broken, so it is decided once here and every module behaves the same way.

Decided in #204, part of #199.

The policy

Hide access. Retain data. Never destroy.

Three sentences, in priority order. When they conflict, the earlier one wins.

1. Access disappears

  • The module’s screens leave the dashboard. Not greyed out with a padlock — gone, with the module listed on the Modules screen as something to re-enable.
  • Its API routes answer 403. A request that used to work stops working, and says why.
  • Its contributions stop. The dashboard revenue row, the Telegram report section, the topic in the settings list: absent, not zero. A section reading “0 orders” is a claim about the business; a section that is not there is a claim about the subscription, and only the second one is true.

2. Data stays exactly where it is

Nothing is deleted, archived, anonymised or moved. A hotel that re-subscribes finds its four hundred menu items, its categories, its photographs and its order history as it left them.

This is not sentiment. A module that empties itself on lapse is a module nobody will risk buying, because the cost of a failed card becomes the cost of rebuilding a catalogue.

3. Work in flight completes

An order placed before the lapse still reaches the kitchen. A booking made minutes ago still notifies. The subscription ended; the guest’s dinner did not, and the person who has already paid for it is not part of this dispute.

Guest-facing surfaces degrade deliberately

The rules above are about staff. A guest never learns anything about a hotel’s billing, and never meets a failure caused by it.

SurfaceOn lapse
QR menuA polite “this service is currently unavailable” page. Not a 404, not an error, not an empty menu that can be ordered from
Bronit TVThe welcome screen with the hotel’s wallpaper. Never a black screen
Anything else guest-facingWhatever the calm version is. If in doubt, fewer features, never an error page

The TV rule is the one to be careful about. A television in an occupied room is the most visible thing this product owns, and a black screen there is the worst possible way for a payment state to express itself — it does not read as “the hotel did not pay”, it reads as “the hotel is broken”, in front of the guest.

lapsed is not off

They grant the same access — none — and they are different situations. off is a business that never bought the module. lapsed is a customer whose card failed. The screens they should see are not the same: one is an offer, the other is a renewal.

effectiveState() keeps them apart for exactly this reason, and any surface that says something to the user should read it rather than the boolean.

Retention has a limit, and it is a decision

Data is kept for 12 months after a lapse, then eligible for deletion.

Two things make that a policy rather than a hope:

  • The business is told before it happens, not after — at lapse, and again before the window closes.
  • The deletion is a deliberate, logged action. There is no cron job quietly removing customer data on an anniversary.

Nothing implements deletion today, and that is the correct state: the first lapse is a year away from mattering, and a destructive job written now would run for eleven months without anyone checking it.

For whoever adds the next module

You inherit all of this. What you owe:

  • No delete-on-lapse anywhere in your module.
  • A guest-facing surface, if you have one, with a calm unavailable state.
  • Your ModuleContribution returning nothing when the business does not have you — which is free, because core filters contributions by entitlement before asking.