# How Meetily's Onboarding Flow Collects User Preferences: A Technical Deep Dive

> Explore Meetily's onboarding flow technical details. Discover how React context, Tauri commands, and local storage manage user preferences for audio permissions and AI models.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: deep-dive
- Published: 2026-07-11

---

**Meetily's onboarding flow collects user preferences through a React context that manages audio permissions and AI model selections, persisting them via Tauri commands to a local JSON store and SQLite database.**

The open-source meeting assistant Meetily (Zackriya-Solutions/meetily) implements a privacy-first onboarding sequence that captures critical user choices before allowing access to recording features. This flow gathers audio permission grants and AI model preferences through a tightly coupled frontend React context and backend Rust Tauri commands, ensuring preferences survive application restarts while maintaining local data sovereignty.

## React Context State Management

The frontend UI relies on [`frontend/src/contexts/OnboardingContext.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src/contexts/OnboardingContext.tsx) to orchestrate the onboarding sequence. This context maintains the **current step index**, **permission states**, and **model selection** in a centralized state.

The context initializes by invoking the Tauri command `get_onboarding_status` to hydrate any previously saved preferences from [`onboarding-status.json`](https://github.com/Zackriya-Solutions/meetily/blob/main/onboarding-status.json). It validates that required models—the Parakeet speech-to-text model and the selected summary LLM—exist on disk before allowing progression. The state structure tracks:

- `microphone`, `systemAudio`, and `screenRecording` permission states
- `selectedSummaryModel` identifier
- `model_status` objects for both Parakeet and the summary model

When users toggle permissions or change models, the context updates via `setPermissionStatus` and `setSelectedSummaryModel` mutators, which trigger auto-save operations after a debounce period.

## Permission Handling and Audio Setup

Meetily requests platform-specific audio permissions through the Tauri plugin system defined in [`frontend/src-tauri/src/audio/permissions.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/audio/permissions.rs). The React context exposes these permission states to UI components, displaying granular controls for microphone access, system audio capture, and screen recording authorization.

Each permission change flows through the context's `setPermissionStatus` method, which updates the local state and queues a persistence operation. The backend validates these permissions before allowing any recording operations, creating a security boundary that prevents unauthorized audio capture.

## AI Model Selection and Validation

The onboarding flow resolves the preferred summary model by calling the Tauri command `builtin_ai_get_recommended_model`, which returns a default or previously selected LLM configuration. Users may override this recommendation through the UI, triggering validation via `builtin_ai_is_model_ready`.

If the selected model is missing from local storage, the context invokes `builtin_ai_download_model` (wrapped in the `requestSummaryModelDownload` function) to fetch the required files. This ensures that only locally-available models can be selected as the active preference, preventing configuration errors during meeting transcription.

## Persistence Layer: Tauri Store and SQLite

User preferences persist through two mechanisms depending on the onboarding stage. During the active flow, the Rust implementation in [`frontend/src-tauri/src/onboarding.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/onboarding.rs) handles serialization via `save_onboarding_status_cmd`:

```rust
#[tauri::command]
pub async fn save_onboarding_status_cmd<R: Runtime>(
    app: AppHandle<R>,
    status: OnboardingStatus,
) -> Result<(), String> {
    save_onboarding_status(&app, &status)
        .await
        .map_err(|e| format!("Failed to save onboarding status: {}", e))
}

```

The `OnboardingStatus` struct captures:
- `model_status.parakeet`: Availability of the transcription model
- `model_status.summary`: Availability of the LLM
- `selected_summary_model`: The user's chosen AI model identifier

When the user completes the flow by invoking `complete_onboarding`, the Rust backend performs database operations through `SettingsRepository::save_model_config` to persist the LLM configuration in SQLite, records the transcription provider as `parakeet`, and marks the onboarding status as `completed = true` in the JSON store.

## Gatekeeping and Post-Onboarding Enforcement

The system gate-keeps core functionality based on onboarding completion status. The tray implementation in [`frontend/src-tauri/src/tray.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/tray.rs) checks the persisted onboarding flag before allowing recording initiation, ensuring that users cannot bypass the permission and model selection requirements.

This design creates a hard dependency chain: the UI loads persisted preferences on mount, validates model availability, captures new user choices, auto-saves incremental changes, and finalizes the configuration in the database only upon explicit completion.

## Summary

- **Meetily's onboarding flow** uses a React context in [`OnboardingContext.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/OnboardingContext.tsx) to manage the UI state for audio permissions and AI model selection.
- **Permission states** for microphone, system audio, and screen recording are captured through `setPermissionStatus` and validated via Tauri's [`audio/permissions.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/permissions.rs) module.
- **AI model preferences** are resolved using `builtin_ai_get_recommended_model`, validated with `builtin_ai_is_model_ready`, and downloaded via `builtin_ai_download_model` if missing.
- **Preferences persist** to [`onboarding-status.json`](https://github.com/Zackriya-Solutions/meetily/blob/main/onboarding-status.json) through `save_onboarding_status_cmd` and finalize in SQLite via `complete_onboarding`, which saves the LLM config and marks the flow as completed.
- **Recording access** is gated by the completion flag checked in [`tray.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/tray.rs), ensuring models and permissions are configured before use.

## Frequently Asked Questions

### How does Meetily store user preferences during the onboarding flow?

Meetily stores preferences incrementally in a local JSON file ([`onboarding-status.json`](https://github.com/Zackriya-Solutions/meetily/blob/main/onboarding-status.json)) using Tauri's store API via the `save_onboarding_status_cmd` command. When the user completes onboarding, the system migrates the final AI model configuration to an SQLite database through `SettingsRepository::save_model_config`, while maintaining the completion flag in the JSON store for fast startup checks.

### What audio permissions does Meetily request during onboarding?

The onboarding flow requests three specific audio permissions: **microphone access** for voice capture, **system audio** for capturing meeting participants, and **screen recording** for display capture. These are managed through the [`audio/permissions.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/audio/permissions.rs) Tauri plugin and tracked in the React context's `permissions` state object until persisted.

### Can users change their AI model after completing onboarding?

While the onboarding flow sets the initial `selected_summary_model` via `builtin_ai_get_recommended_model`, the architecture supports model changes through the same validation pipeline. The context checks model availability with `builtin_ai_is_model_ready` and triggers downloads via `builtin_ai_download_model`, though the specific post-onboarding UI for model switching would depend on the application's settings implementation.

### What happens if required AI models are missing during onboarding?

If the Parakeet transcription model or selected summary model is missing when the context loads, the `loadOnboardingStatus` function detects this through the model status checks. The UI then prompts the user to download the missing model via `requestSummaryModelDownload`, which invokes `builtin_ai_download_model`. The onboarding cannot proceed to completion until `builtin_ai_is_model_ready` returns true for both required models.