feat: gate auto-updates behind license entitlement (#48) #58

Merged
maximus merged 1 commit from issue-48-gate-auto-updates into issue-46-license-commands-entitlements 2026-04-10 13:55:40 +00:00
Owner

Fixes #48

Depends on #46 (chain-branched from issue-46-license-commands-entitlements).

Summary

  • useUpdater.ts calls check_entitlement('auto-update') before fetching update metadata; new notEntitled status
  • ErrorPage.tsx (recovery screen) also gates the manual update check for consistency
  • New i18n keys settings.updates.notEntitled and error.updateNotEntitled (FR + EN)
  • Bilingual CHANGELOG entries

Architecture note

The gate name ('auto-update') maps to the centralized FEATURE_TIERS list in commands/entitlements.rs. To move auto-updates to a different tier later, edit the single mapping in that module — no need to touch components.

Test plan

  • Free edition: clicking "Check for updates" shows the notEntitled message instead of querying the updater endpoint
  • Base/Premium edition: normal update flow works
  • ErrorPage check button gated identically
Fixes #48 Depends on #46 (chain-branched from `issue-46-license-commands-entitlements`). ## Summary - `useUpdater.ts` calls `check_entitlement('auto-update')` before fetching update metadata; new `notEntitled` status - `ErrorPage.tsx` (recovery screen) also gates the manual update check for consistency - New i18n keys `settings.updates.notEntitled` and `error.updateNotEntitled` (FR + EN) - Bilingual CHANGELOG entries ## Architecture note The gate name (`'auto-update'`) maps to the centralized `FEATURE_TIERS` list in `commands/entitlements.rs`. To move auto-updates to a different tier later, edit the single mapping in that module — no need to touch components. ## Test plan - [ ] Free edition: clicking "Check for updates" shows the notEntitled message instead of querying the updater endpoint - [ ] Base/Premium edition: normal update flow works - [ ] ErrorPage check button gated identically
maximus added 1 commit 2026-04-09 12:59:10 +00:00
Both code paths that touch the updater now consult `check_entitlement`
from the Rust entitlements module before calling `check()`:

- `useUpdater.ts` adds a `notEntitled` status; on Free, the check
  short-circuits and the Settings page displays an upgrade hint instead
  of fetching update metadata.
- `ErrorPage.tsx` (recovery screen) does the same so the error path
  matches the main path; users on Free no longer see network errors when
  the updater would have run.

The gate name (`auto-update`) is the same string consumed by
`commands/entitlements.rs::FEATURE_TIERS`, so changing which tier
unlocks updates is a one-line edit in that file.

Bilingual i18n keys for the new messages are added to both `fr.json`
and `en.json`. CHANGELOG entries in both languages.
Author
Owner

Review (sprint inline) — APPROVE

Points vérifiés

  • Gate dans useUpdater ET dans ErrorPage — pas de chemin de contournement
  • Le nom du feature ('auto-update') match exactement la clé dans FEATURE_TIERS (entitlements.rs)
  • Modularité respectée : pour gater une autre feature ou changer de tier, on modifie SEULEMENT commands/entitlements.rs::FEATURE_TIERS
  • État notEntitled ajouté au reducer + UI block dans SettingsPage
  • i18n FR/EN complet (settings.updates.notEntitled + error.updateNotEntitled)
  • Bilingual CHANGELOG
  • Aucune chaîne en dur
  • Le check est fail-safe : si le call invoke échoue, on tombe dans le catch ERROR (pas dans notEntitled), donc l'utilisateur voit un vrai message d'erreur, pas un faux paywall

Suggestion non bloquante

  • Le check_entitlement est dupliqué dans useUpdater.ts et ErrorPage.tsx (~3 lignes chacun). Acceptable pour 2 callsites, mais si une 3e arrive, refactor en helper useEntitlement(feature) ou entitlementService.ts.

Aucun problème critique.

## Review (sprint inline) — APPROVE ### Points vérifiés - ✅ Gate dans `useUpdater` ET dans `ErrorPage` — pas de chemin de contournement - ✅ Le nom du feature (`'auto-update'`) match exactement la clé dans `FEATURE_TIERS` (entitlements.rs) - ✅ Modularité respectée : pour gater une autre feature ou changer de tier, on modifie SEULEMENT `commands/entitlements.rs::FEATURE_TIERS` - ✅ État `notEntitled` ajouté au reducer + UI block dans SettingsPage - ✅ i18n FR/EN complet (settings.updates.notEntitled + error.updateNotEntitled) - ✅ Bilingual CHANGELOG - ✅ Aucune chaîne en dur - ✅ Le check est fail-safe : si le call invoke échoue, on tombe dans le catch ERROR (pas dans `notEntitled`), donc l'utilisateur voit un vrai message d'erreur, pas un faux paywall ### Suggestion non bloquante - Le `check_entitlement` est dupliqué dans `useUpdater.ts` et `ErrorPage.tsx` (~3 lignes chacun). Acceptable pour 2 callsites, mais si une 3e arrive, refactor en helper `useEntitlement(feature)` ou `entitlementService.ts`. Aucun problème critique.
maximus force-pushed issue-48-gate-auto-updates from 174c07de51 to 6d67ab8935 2026-04-09 19:53:04 +00:00 Compare
maximus merged commit dd106a1df6 into issue-46-license-commands-entitlements 2026-04-10 13:55:40 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#58
No description provided.