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:
Test
2026-04-03 21:22:28 +02:00
parent 3172425a16
commit a0fc97e5cf
13 changed files with 137 additions and 28 deletions

View File

@@ -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)

View 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.