Files
pluriwave/openspec/changes/iap-freemium-unlock/specs/freemium-gating/spec.md
T
FreeTLab aa0b242374 feat(iap): add freemium unlock via one-time in-app purchase
Adds a permanent, non-consumable premium unlock (EstadoEntitlement +
PuertoCompras/ServicioComprasPlayBilling) that removes ads and unlocks
alarm vacations, alarms past a 5-alarm free cap, recording start, and
full Android Auto browsing. The phone equalizer stays free for everyone.

- Entitlement is prefs-backed (compra_premium_v1), fail-open, and
  resolvable headlessly via esPremiumPersistido() for the Android Auto
  audio handler, which registers before runApp.
- Android Auto reduced mode keeps the real root folder labels for free
  users; browsing into any of them (and playFromMediaId/playFromSearch/
  skipToNext/skipToPrevious) is blocked at the getChildren/servicio_audio
  choke points, with a locked "Función Premium" item as the backstop.
  Current-station play/pause/stop stays untouched. A free -> premium
  transition actively invalidates the head unit's cached browse tree.
- Ads (top banner + capped interstitial before adding a station or an
  alarm) are gated behind entitlement via ServicioAnuncios, using
  official Google test ad unit IDs pending AdMob provisioning.
- Alarm cap UX shows an explanatory message with a secondary unlock
  action rather than a bare paywall jump; existing data is grandfathered.
- 4 new localization keys translated across all 13 supported locales.

Co-located tests use strict TDD (RED test before implementation) for
every new pure-logic unit; full existing suite passes unchanged.
2026-08-10 20:37:07 +02:00

4.2 KiB

Freemium Gating Specification

Purpose

Define which features require premium entitlement, the free-tier alarm cap, grandfathering of existing content, and the non-punitive UX for hitting a limit. The equalizer on the phone is explicitly out of scope — it MUST stay free.

Requirements

Requirement: Gated Feature Set (Exactly 4)

The system MUST require premium entitlement for exactly: (1) creating alarm vacations, (2) starting a new station recording, (3) creating an alarm beyond the 5-alarm cap, and (4) full Android Auto browsing (see android-auto-media). The phone equalizer MUST NOT be gated under any circumstance.

Scenario: Free user uses the phone equalizer

  • GIVEN a free-tier user
  • WHEN they open and use the equalizer screen on the phone
  • THEN it works fully, with no entitlement check and no upsell

Scenario: Free user attempts a gated action

  • GIVEN a free-tier user
  • WHEN they tap "add vacation range" or "start recording"
  • THEN they see the paywall/upsell instead of the action completing

Requirement: Alarm Count Cap At 5 (Free Tier)

EstadoAlarmas.guardarAlarma MUST count all alarms, enabled or not, and MUST reject creating a 6th alarm for a free-tier user via a distinct "limit reached" signal, separate from the existing _error field used for native scheduling failures.

Scenario: 6th alarm creation is blocked

  • GIVEN a free-tier user already has 5 alarms (any enabled state)
  • WHEN they attempt to create a 6th
  • THEN guardarAlarma rejects it via the distinct limit signal, and no native scheduling is attempted

Scenario: Editing an existing alarm is unaffected

  • GIVEN a free-tier user has exactly 5 alarms
  • WHEN they edit one of those 5 (not create a new one)
  • THEN the edit succeeds normally

Scenario: Premium user has no cap

  • GIVEN a premium user
  • WHEN they create a 6th or later alarm
  • THEN it succeeds with no limit check

Requirement: Alarm Cap UX Never Bare-Jumps To Paywall

Hitting the alarm cap MUST show an explanatory message with a secondary "unlock" action; it MUST NOT navigate directly to the paywall as the sole response to the attempt.

Scenario: Cap message with secondary action

  • GIVEN a free-tier user hits the 5-alarm cap
  • WHEN the limit signal is raised
  • THEN the UI shows an explanatory message (e.g. "Has alcanzado el límite de 5 alarmas gratuitas") with a secondary button (e.g. "Desbloquear Premium")
  • AND only tapping that secondary button navigates to the paywall

Requirement: Grandfathering Of Existing Content

Alarms, vacations, and recordings created before the gate existed, or already exceeding the cap, MUST remain visible, usable, and editable-in-place. Only NEW creation past a limit or gate is blocked. (Previously: no cap or gate existed, so this distinction did not apply.)

Scenario: Pre-existing alarms above the cap keep working

  • GIVEN a device already has 7 alarms before this change ships
  • WHEN the free-tier gate is active
  • THEN all 7 alarms keep ringing and can be toggled/edited, and only a new 8th creation is blocked

Requirement: Recording Start Gated, Management Stays Free

EstadoGrabacion.iniciar MUST require premium entitlement. Screens that view, play, or delete already-existing recordings MUST remain accessible regardless of entitlement.

Scenario: Free user starts a new recording

  • GIVEN a free-tier user
  • WHEN they tap the record action
  • THEN they see the paywall instead of recording starting

Scenario: Free user manages existing recordings

  • GIVEN a free-tier user with previously recorded files
  • WHEN they open the recordings list
  • THEN they can view, play, and delete those recordings normally

Requirement: Purchase Entry Points At Every Gate Plus Settings

Every gated entry point MUST show a contextual upsell. Settings MUST additionally expose a persistent purchase/restore row.

Scenario: Contextual upsell at a gate

  • GIVEN a free-tier user reaches any of the 4 gated entry points
  • WHEN the gate blocks the action
  • THEN a contextual purchase CTA is shown at that point

Scenario: Settings always shows a premium row

  • GIVEN any user opens Settings
  • WHEN the screen renders
  • THEN it shows either a "buy premium" row (free tier) or a "premium active" state with restore access (premium tier)