How Meetily's Onboarding Flow Initializes and Stores User Preferences

Meetily's onboarding flow initializes user preferences by loading defaults from a JSON store, persists model selections to SQLite, and updates the Tauri store to mark completion, ensuring preferences survive app restarts.

The onboarding system in Zackriya-Solutions/meetily guides first-time users through initial configuration while maintaining state across sessions. This Rust-powered Tauri application uses a dual-storage approach—JSON for quick UI state checks and SQLite for durable configuration—to ensure that LLM and transcription model selections remain available after reinstalls.

Loading Default Onboarding State from JSON

When the application starts, the Rust backend invokes load_onboarding_status to retrieve the current onboarding progress. This function attempts to read onboarding-status.json via the Tauri Store plugin. If the file is missing or malformed, it falls back to a hard-coded OnboardingStatus::default() struct containing the app version, a "not completed" flag, step index 0, and a ModelStatus with both parakeet and summary fields set to "not_downloaded".

The implementation in frontend/src-tauri/src/onboarding.rs (lines 45–74) handles this initialization:

let status = load_onboarding_status(&app).await?;
println!("Onboarding step: {}, completed: {}", status.current_step, status.completed);

This default state provides the frontend with immediate knowledge of which models require downloading and which onboarding steps remain incomplete.

Persisting Model Choices to SQLite Database

When a user completes onboarding by selecting a summarization model, the complete_onboarding command executes. This critical function, defined in frontend/src-tauri/src/onboarding.rs (lines 78–104), performs durable persistence by writing to the embedded SQLite database through two repository methods:

  1. SettingsRepository::save_model_config – Stores the LLM configuration (builtin-ai model)
  2. SettingsRepository::save_transcript_config – Persists the transcription provider (parakeet)

These database writes ensure that preferences survive full application reinstalls, as the SQLite file remains in the user's data directory. The method signatures include provider names, model identifiers, and optional configuration parameters:

#[tauri::command]
async fn complete_onboarding(app: AppHandle, state: State<'_, AppState>, model: String) {
    // Persist chosen LLM & transcription provider in SQLite
    SettingsRepository::save_model_config(pool, "builtin-ai", &model, "large-v3", None).await?;
    SettingsRepository::save_transcript_config(pool, "parakeet", DEFAULT_PARAKEET_MODEL).await?;
    // ... status updates follow
}

The actual SQL operations live in frontend/src-tauri/src/database/repositories/setting.rs, which handles the complex logic of inserting or updating configuration rows while maintaining data integrity.

Marking Onboarding Complete in the Tauri Store

After successfully writing to SQLite, the flow updates the transient JSON store to reflect completion. The code reloads the onboarding status, updates specific fields (completed = true, current_step = 4), marks both models as "downloaded", and stores the selected summary model identifier.

This final persistence step in frontend/src-tauri/src/onboarding.rs (lines 106–122) uses save_onboarding_status to write the updated struct back to onboarding-status.json:

let mut status = load_onboarding_status(&app).await?;
status.completed = true;
status.current_step = 4;
status.model_status.parakeet = "downloaded".into();
status.model_status.summary = "downloaded".into();
status.model_status.selected_summary_model = Some(model);
save_onboarding_status(&app, &status).await?;

This JSON file serves as the source of truth for UI components checking onboarding completion without querying the database.

Frontend Helper Utilities for Model Status

The TypeScript layer retrieves onboarding state via the get_onboarding_status command and processes it using utilities in frontend/src/lib/onboarding-summary-model.ts (lines 19–55). The resolveOnboardingSummaryModelStatus function determines which summary model to display based on the stored configuration:

import { resolveOnboardingSummaryModelStatus } from '@/lib/onboarding-summary-model';

const result = resolveOnboardingSummaryModelStatus({
  selectedModel: '',
  recommendedModel: 'qwen3.5:2b',
  selectedModelReady: false,
});

console.log(result.selectedSummaryModel); // → "qwen3.5:2b"
console.log(result.summaryModelDownloaded); // → false

Additional helper getSummaryModelSizeLabel provides human-readable size formatting for the onboarding UI, ensuring users understand model storage requirements before downloading.

Summary

  • Dual-storage architecture: Meetily uses JSON for fast UI state checks (onboarding-status.json) and SQLite for permanent configuration storage
  • Rust command handlers: load_onboarding_status, complete_onboarding, and save_onboarding_status manage the flow in frontend/src-tauri/src/onboarding.rs
  • Database persistence: SettingsRepository methods save model selections to survive app reinstalls
  • Frontend integration: TypeScript helpers interpret ModelStatus to render appropriate UI states and download indicators

Frequently Asked Questions

Where does Meetily store onboarding completion status?

Meetily stores onboarding completion in two locations: a JSON file (onboarding-status.json) accessed via the Tauri Store plugin for quick UI checks, and an SQLite database for permanent model configuration. The JSON file tracks whether onboarding is complete and which step the user reached, while the database stores the actual LLM and transcription provider selections in frontend/src-tauri/src/database/repositories/setting.rs.

What happens if the onboarding status file is corrupted?

If onboarding-status.json is missing or malformed, the load_onboarding_status function in frontend/src-tauri/src/onboarding.rs automatically returns OnboardingStatus::default(). This default initializes the app version, sets completed to false, resets the step counter to 0, and marks both parakeet and summary models as "not_downloaded", effectively restarting the onboarding flow.

Which Rust functions handle the onboarding completion process?

The complete_onboarding command handles the entire completion process. It first calls SettingsRepository::save_model_config and SettingsRepository::save_transcript_config to persist selections to SQLite, then updates the JSON store via save_onboarding_status with completion flags and model download status. This ensures both transient UI state and permanent user preferences are synchronized.

How does the frontend determine which summary model to display?

The frontend uses the resolveOnboardingSummaryModelStatus helper from frontend/src/lib/onboarding-summary-model.ts to parse the ModelStatus returned by the Rust backend. This utility compares the user's selected model against the recommended default and checks download readiness, returning the appropriate display name and boolean flags for the UI components.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →