Skip to content

Licensing: Alpha/Beta Tier Access

Licensing: Alpha/Beta Tier Access

Status: Delivered
CAS: CAS-1100
Delivered: 2026-04-29
PRs: #318, #319, #321

What’s new

Casaconomy now has a built-in licensing system that gates premium features by tier. You can grant alpha access to a user by email, and their copy of the app activates against a license key that lives in their OS keychain — no account, no password. Premium features (provider sync, advanced rules, OCR, multi-device vault) are hidden behind a PremiumGate component that shows an upgrade prompt to unlicensed users and renders normally for activated ones.

How to use it

For the board (granting alpha access):

  1. A user sends their email to request alpha access via the in-app form or directly.
  2. The Worker issues a license key in the format CASA-XXXX-XXXX-XXXX-XXXX and emails it to them via Resend.
  3. The user opens Settings → License, types the key and a device name, and clicks Activate. The app contacts the licensing Worker, records the activation, and stores the token in their OS keychain.
  4. Premium features unlock immediately. The status badge on the Settings page shows “Active (Alpha)”.

For the board (revoking a license):

Terminal window
curl -X POST https://licenses.casaconomy.com/v1/licenses/revoke \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-d '{"license_key": "CASA-..."}'

This marks the license revoked, removes all device activations, and sends the user a revocation email.

First-run experience:

Unactivated users see a dismissible banner at the top of the app pointing them to Settings → License. Attempting to use a gated feature from an unactivated device shows an upgrade modal with a “Get Casaconomy Plus” CTA (currently links to https://casaconomy.com/upgrade — placeholder until Phase 5 checkout is wired).

What changed under the hood

  • Cloudflare Worker (workers/licensing/) — TypeScript HTTP API on Cloudflare Workers with four endpoints: access-request, activate, validate, revoke. License keys are SHA-256 hashed before storage; the raw key is only ever sent once by email.
  • D1 schema (workers/licensing/migrations/) — five tables: tiers, customers, licenses, activations, audit. Alpha tier seeded with unlimited devices and all features enabled.
  • Rust license service (src-tauri/src/services/license_service.rs) — manages local state, calls the Worker on activate/validate/deactivate, derives LicenseState from the cached token, runs a 24-hour background revalidation loop. Tokens stored in OS keychain on release builds; in-memory on debug builds to avoid macOS “Always Allow” prompts during development.
  • Tauri commands (src-tauri/src/commands/license_commands.rs) — get_license_state, is_premium_enabled, activate_license, deactivate_device, get_device_info.
  • FrontendLicenseActivationBanner, LicenseSettingsPage, PremiumGate, UpgradePromptModal, useLicenseState hook.

Why we built it

The app was approaching a state where it could be shared with a small circle of alpha users, but had no way to distinguish them from anyone who downloaded it. Rather than bolt on auth later, we built a lightweight keychain-based licensing layer now — self-contained, no accounts required, easy to revoke — that can be extended with Stripe payments in Phase 5 without redesigning the activation UX.

Known limitations / follow-on work

  • No payment processing yet. Alpha and beta tiers are free. Phase 5 will add Stripe (or Lemon Squeezy) checkout and map subscriptions to license issuance.
  • Trial tier is reserved but not wired. The schema has a trial tier; the LicenseState::Trial variant exists in Rust. No flow issues a trial license today.
  • macOS keychain on Sequoia. Background-launched app builds may hit the WKWebView throttling issue tracked in CAS-698 — unrelated to licensing but affects the smoke walk that validates the activation flow end-to-end.
  • Single upgrade CTA link. All upgrade CTAs point to a placeholder URL. This will be replaced when the Phase 5 checkout page is live.
  • Admin API is a raw curl workflow. No UI for the board to issue or revoke licenses. A lightweight admin panel is a natural Phase 5 follow-on.