Skip to content

Desktop trial silently auto-starts at signup with no opt-in #7672

@mdmohsin7

Description

@mdmohsin7

Summary

The desktop app's 3-day premium trial begins silently the moment a user signs in for the first time. There is no in-app "your trial just started" surface, and users routinely discover the trial only when the Trial Ended toast fires three days later.

Root cause

The trial is purely derived from Firebase Auth's account creation timestamp:

# backend/utils/subscription.py:202-214
user_record = firebase_auth.get_user(uid)
creation_ms = user_record.user_metadata.creation_timestamp
creation_seconds = int(creation_ms / 1000)
trial_ends_at = creation_seconds + TRIAL_LENGTH_SECONDS  # 3 * 24 * 60 * 60

No trial_started_at field is persisted; there's no opt-in endpoint; the client never asks the user. The 3-day clock starts whenever Firebase created the account, which is the OAuth sign-in moment.

On the desktop side, AuthService.swift:336-340 and :458-462 kick off state.startTrialMetadataRefresh() + TrialBannerService.shared.start() immediately after sign-in. The banner service only fires at <24h, <1h, and expired thresholds, so the user's first signal that a trial existed is the warning at the 2-day mark — or the expiration toast on day 3 if they were inactive in that window.

Proposed fix

Make the trial opt-in:

  1. Backend — persist subscription.trial_started_at: int | None. get_trial_metadata reads the stored value when present; reports available: true, started_at: null when not. New POST /v1/users/me/trial/start writes now(), idempotent (returns the existing metadata if already started). Backward-compat: existing users currently mid-trial (Firebase creation + 3d > now) get a lazy backfill so we don't yank active access; users whose derived trial already expired silently get a fresh opt-in (the original auto-start was the bug, not the intent).

  2. Desktop — first-sign-in modal showing the trial offer (feature bullets + Start / Maybe later). Settings → Plan & Usage card adds a "Start your 3-day premium trial" button when available && started_at == null. The existing countdown / expired UI is unchanged once the trial is actually started.

Acceptance criteria

  • New desktop signup → no trial clock starts until the user clicks Start.
  • Skipping the modal leaves the trial available; the user can start it later from Settings.
  • Users currently mid-trial at deploy time continue uninterrupted.
  • Trial Ended toast never fires for a user who never opted in.

Out of scope

  • Mobile / web (trial is desktop-only today and stays that way).
  • Reworking the post-trial paywall or pricing surfaces.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingp3Priority: Backlog (score <14)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions