feat: release channels (alpha/beta/stable) via PostHog feature flags
- Add `release_channel` to Settings (Rust + TypeScript) - Add channel selector in Settings panel (alpha/beta/stable) - Pass `release_channel` as PostHog person property on identify - Add `isFeatureEnabled()` helper: alpha always true, beta/stable use PostHog flags with hardcoded fallback defaults - Update `useFeatureFlag` to delegate to PostHog-backed evaluation (localStorage overrides still work for dev/QA) - Create ADR-0042 (supersedes ADR-0017) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -826,9 +826,13 @@ flowchart LR
|
||||
- **Canary**: `useUpdater` hook fetches `latest-canary.json` via HTTP, compares versions, and opens the GitHub release page for manual download
|
||||
- Canary versions use semver prerelease: `0.YYYYMMDD.N-canary`
|
||||
|
||||
### Feature Flags (Local V1)
|
||||
### Feature Flags (PostHog + Release Channels)
|
||||
|
||||
Feature flags use a local-only system with no external dependencies:
|
||||
Feature flags are backed by PostHog and evaluated per release channel:
|
||||
|
||||
- **Alpha**: all features always enabled (no PostHog lookup)
|
||||
- **Beta**: sees features where the PostHog flag targets `release_channel = beta`
|
||||
- **Stable** (default): sees features where the flag targets `release_channel = stable`
|
||||
|
||||
```typescript
|
||||
import { useFeatureFlag } from './hooks/useFeatureFlag'
|
||||
@@ -838,18 +842,14 @@ const enabled = useFeatureFlag('example_flag') // boolean
|
||||
|
||||
**Resolution order:**
|
||||
1. `localStorage` override: key `ff_<name>` with value `"true"` or `"false"`
|
||||
2. Compile-time default in `FLAG_DEFAULTS` map
|
||||
2. `isFeatureEnabled(flag)` in `telemetry.ts` → checks release channel, then PostHog, then hardcoded defaults
|
||||
|
||||
**How to add a new flag:**
|
||||
1. Add the flag name to the `FeatureFlagName` union type in `src/hooks/useFeatureFlag.ts`
|
||||
2. Set its default in the `FLAG_DEFAULTS` record
|
||||
2. Create the flag on PostHog dashboard with rollout rules per channel
|
||||
3. Use `useFeatureFlag('your_flag')` in components
|
||||
|
||||
**Design decisions:**
|
||||
- No remote fetching, no PostHog dependency — zero privacy concerns
|
||||
- `localStorage` overrides allow dev/QA testing without rebuilding
|
||||
- Type-safe flag names via TypeScript union type
|
||||
- API surface is compatible with future migration to remote flags
|
||||
Release channel is selectable in Settings (alpha / beta / stable) and passed to PostHog as a person property via `identify()`. See ADR-0042.
|
||||
|
||||
## Platform Support — iOS / iPadOS (Prototype)
|
||||
|
||||
|
||||
37
docs/adr/0042-posthog-release-channels-feature-flags.md
Normal file
37
docs/adr/0042-posthog-release-channels-feature-flags.md
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
type: ADR
|
||||
id: "0042"
|
||||
title: "PostHog-based release channels and feature flags"
|
||||
status: active
|
||||
date: 2026-04-03
|
||||
supersedes: "0017"
|
||||
---
|
||||
## Context
|
||||
|
||||
ADR-0017 introduced canary/stable update channels with localStorage-based feature flags. This worked for local development but lacked remote flag management — promoting a feature from beta to stable required a code change and rebuild.
|
||||
|
||||
## Decision
|
||||
|
||||
**Replace localStorage feature flags with PostHog-based feature flags, evaluated per release channel (alpha/beta/stable). The release channel is a user-selectable setting; PostHog flag rules determine which features are visible for each channel.**
|
||||
|
||||
- **Alpha**: all features always enabled (no PostHog lookup needed, works offline)
|
||||
- **Beta**: sees features where the PostHog flag targets `release_channel = beta`
|
||||
- **Stable** (default): sees features where the PostHog flag targets `release_channel = stable`
|
||||
- Promotion = flipping a PostHog flag on the dashboard. Zero code changes, zero rebuilds.
|
||||
- `isFeatureEnabled(flagKey)` in `telemetry.ts` is the single evaluation point.
|
||||
- localStorage overrides (`ff_<name>`) still work for dev/QA testing (checked first).
|
||||
- Offline: PostHog caches flags in localStorage; alpha always works; first-launch-no-network falls back to hardcoded defaults.
|
||||
|
||||
## Options considered
|
||||
|
||||
* **Option A**: Keep localStorage-only flags (ADR-0017) — no server dependency, but no remote management.
|
||||
* **Option B** (chosen): PostHog feature flags — we already use PostHog for analytics, so no new dependency. Remote flag management, per-channel targeting, gradual rollouts via PostHog dashboard.
|
||||
* **Option C**: Dedicated feature flag service (LaunchDarkly, Unleash) — more powerful but adds a new vendor dependency.
|
||||
|
||||
## Consequences
|
||||
|
||||
* `release_channel` added to Settings (persisted via Tauri backend, not vault).
|
||||
* `useTelemetry` passes `release_channel` as a PostHog person property on identify.
|
||||
* `isFeatureEnabled()` checks channel → PostHog → hardcoded defaults.
|
||||
* `useFeatureFlag` hook updated to delegate to `isFeatureEnabled` (after localStorage override check).
|
||||
* ADR-0017 is superseded — the canary update channel remains, but feature gating moves from localStorage to PostHog.
|
||||
Reference in New Issue
Block a user