Database Schema for Meetily: Complete SQLite Table Reference and Migration Guide

Meetily uses a lightweight SQLite database accessed through SQLx, with its schema defined in versioned migration files and type-safe Rust structs in the Tauri backend.

The open-source meeting assistant Meetily, hosted in the Zackriya-Solutions/meetily repository, persists all data locally in a single SQLite file accessed through SQLx. The database schema for Meetily defines tables for meetings, transcripts, summary jobs, and provider settings, using both SQL migrations and Rust structs to maintain a type-safe data layer.

Core Tables in the Meetily Database Schema

The initial schema defines six core tables that handle meetings, transcript segments, summary jobs, audio chunks, and provider configuration. Several columns were added through later migrations to support folder-based organization, audio synchronization, and additional API providers.

meetings

The meetings table stores one row per recorded meeting according to the base migration in frontend/src-tauri/migrations/20250916100000_initial_schema.sql. It includes the following columns:

  • id TEXT PRIMARY KEY – Unique identifier for the meeting
  • title TEXT NOT NULL – Display title
  • created_at TEXT NOT NULL – ISO timestamp of creation
  • updated_at TEXT NOT NULL – ISO timestamp of last update
  • folder_path TEXT – Added later to support folder-based organization

transcripts

The transcripts table stores individual transcript entries, typically representing a paragraph or speaker turn. As implemented in Zackriya-Solutions/meetily, its columns include:

  • id TEXT PRIMARY KEY
  • meeting_id TEXT FOREIGN KEY → meetings(id)
  • transcript TEXT NOT NULL
  • timestamp TEXT NOT NULL
  • summary TEXT, action_items TEXT, key_points TEXT – AI-generated metadata
  • audio_start_time REAL, audio_end_time REAL, duration REAL – Added later for precise playback synchronization with the original audio file

summary_processes

The summary_processes table tracks the status and results of the LLM-driven meeting-summary pipeline. Its columns are:

  • meeting_id TEXT PRIMARY KEY FOREIGN KEY → meetings(id)
  • status TEXT NOT NULL
  • created_at TEXT NOT NULL, updated_at TEXT NOT NULL
  • error TEXT, result TEXT
  • start_time TEXT, end_time TEXT
  • chunk_count INTEGER DEFAULT 0
  • processing_time REAL DEFAULT 0.0
  • metadata TEXT

transcript_chunks

The transcript_chunks table stores the raw chunks sent to the Whisper engine or other STT back-ends. It contains:

  • meeting_id TEXT PRIMARY KEY FOREIGN KEY → meetings(id)
  • meeting_name TEXT
  • transcript_text TEXT NOT NULL
  • model TEXT NOT NULL, model_name TEXT NOT NULL
  • chunk_size INTEGER, overlap INTEGER
  • created_at TEXT NOT NULL

settings and transcript_settings

The settings table holds global configuration for LLM and STT providers:

  • id TEXT PRIMARY KEY
  • provider TEXT NOT NULL, model TEXT NOT NULL, whisperModel TEXT NOT NULL
  • groqApiKey TEXT, openaiApiKey TEXT, anthropicApiKey TEXT, ollamaApiKey TEXT
  • openRouterApiKey TEXT – Added in a later migration to support OpenRouter

The transcript_settings table stores provider-specific credentials for transcription services:

  • id TEXT PRIMARY KEY
  • provider TEXT NOT NULL, model TEXT NOT NULL
  • whisperApiKey TEXT, deepgramApiKey TEXT, elevenLabsApiKey TEXT
  • groqApiKey TEXT, openaiApiKey TEXT

How the Meetily Schema Evolves Through Migrations

Meetily applies schema changes through numbered SQL migration files that run automatically on launch. These migrations reside in frontend/src-tauri/migrations/ and modify the base tables using standard ALTER TABLE statements.

Initial Schema Creation

The file frontend/src-tauri/migrations/20250916100000_initial_schema.sql creates all base tables when the app is first installed. This script defines the meetings, transcripts, summary_processes, transcript_chunks, settings, and transcript_settings tables.

Audio Synchronization and Folders

The migration frontend/src-tauri/migrations/20251006000000_add_audio_sync_fields.sql extends the schema with two feature sets. It adds folder_path to the meetings table and audio_start_time, audio_end_time, and duration to the transcripts table, enabling precise audio playback synchronization and folder-based meeting organization.

Extended API Provider Support

The migration frontend/src-tauri/migrations/20250920155811_add_openrouter_api_key.sql adds the openRouterApiKey column to the settings table. According to the Zackriya-Solutions/meetily source code, additional migrations such as add_summary_backup.sql and add_gemini_api_key.sql continue to extend the schema as the application evolves.

Rust Model Definitions for Type-Safe Access

All database tables are represented as structs in frontend/src-tauri/src/database/models.rs. These structs implement SQLx's FromRow derive macro, mapping rows directly to Rust types for compile-time query validation.

The following excerpt from models.rs shows the MeetingModel and Transcript structs:

#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
pub struct MeetingModel {
    pub id: String,
    pub title: String,
    pub created_at: DateTimeUtc,
    pub updated_at: DateTimeUtc,
    pub folder_path: Option<String>,
}

#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
pub struct Transcript {
    pub id: String,
    pub meeting_id: String,
    pub transcript: String,
    pub timestamp: String,
    pub summary: Option<String>,
    pub action_items: Option<String>,
    pub key_points: Option<String>,
    pub audio_start_time: Option<f64>,
    pub audio_end_time: Option<f64>,
    pub duration: Option<f64>,
}

The Option<T> fields correspond to columns added by later migrations or nullable fields in the SQLite schema.

Working with the Meetily Database

The following examples demonstrate how the Rust backend interacts with the Meetily database schema using SQLx compile-time checked macros.

Inserting a New Meeting

This query inserts a row into the meetings table with a generated UUID and current timestamp:

use sqlx::sqlite::SqlitePool;
use uuid::Uuid;
use chrono::Utc;

async fn create_meeting(pool: &SqlitePool, title: &str) -> sqlx::Result<()> {
    let id = Uuid::new_v4().to_string();
    let now = Utc::now();
    sqlx::query!(
        r#"
        INSERT INTO meetings (id, title, created_at, updated_at, folder_path)
        VALUES (?1, ?2, ?3, ?4, NULL)
        "#,
        id,
        title,
        now.to_rfc3339(),
        now.to_rfc3339()
    )
    .execute(pool)
    .await?;
    Ok(())
}

Querying Transcripts by Meeting

This function retrieves all transcript rows for a specific meeting_id, ordered by timestamp:

use sqlx::sqlite::SqlitePool;

async fn get_transcripts(pool: &SqlitePool, meeting_id: &str) -> sqlx::Result<Vec<Transcript>> {
    let rows = sqlx::query_as!(
        Transcript,
        r#"
        SELECT *
        FROM transcripts
        WHERE meeting_id = ?1
        ORDER BY timestamp ASC
        "#,
        meeting_id
    )
    .fetch_all(pool)
    .await?;
    Ok(rows)
}

Updating Summary Process Status

This update modifies the summary_processes table to reflect the current state of the LLM pipeline:

async fn set_summary_status(
    pool: &SqlitePool,
    meeting_id: &str,
    new_status: &str,
) -> sqlx::Result<()> {
    sqlx::query!(
        r#"
        UPDATE summary_processes
        SET status = ?1, updated_at = ?2
        WHERE meeting_id = ?3
        "#,
        new_status,
        chrono::Utc::now().to_rfc3339(),
        meeting_id
    )
    .execute(pool)
    .await?;
    Ok(())
}

Storing Provider Settings

This insertion persists user configuration to the settings table, including API keys for multiple providers:

async fn insert_setting(pool: &SqlitePool, setting: Setting) -> sqlx::Result<()> {
    sqlx::query!(
        r#"
        INSERT INTO settings (
            id, provider, model, whisperModel,
            groqApiKey, openaiApiKey, anthropicApiKey,
            ollamaApiKey, openRouterApiKey
        )
        VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)
        "#,
        setting.id,
        setting.provider,
        setting.model,
        setting.whisper_model,
        setting.groq_api_key,
        setting.openai_api_key,
        setting.anthropic_api_key,
        setting.ollama_api_key,
        setting.open_router_api_key
    )
    .execute(pool)
    .await?;
    Ok(())
}

Key Files Defining the Database Schema

Understanding the following files is essential for working with Meetily's data layer:

Summary

The Meetily database schema is designed for local-first meeting data storage with SQLite and SQLx.

  • Six core tables handle meetings, transcripts, summary jobs, audio chunks, and provider settings
  • Versioned migrations in frontend/src-tauri/migrations/ apply schema changes incrementally without breaking existing data
  • Rust structs in frontend/src-tauri/src/database/models.rs provide compile-time type safety via SQLx FromRow derives
  • Nullable columns such as folder_path, audio_start_time, and openRouterApiKey allow backward-compatible feature additions

Frequently Asked Questions

What database engine does Meetily use?

Meetily stores all persistent data in a local SQLite database. The Rust backend accesses this database through SQLx, which provides compile-time checked queries and automatic row mapping via the structs in frontend/src-tauri/src/database/models.rs.

Where are the Meetily database migrations stored?

Schema migrations live in frontend/src-tauri/migrations/ inside the repository. Each migration file is timestamped and executed in order by the migration runner defined in frontend/src-tauri/src/database/manager.rs.

How does Meetily handle schema updates?

Meetily applies schema updates through incremental SQL migration files. For example, 20251006000000_add_audio_sync_fields.sql adds playback synchronization columns, and 20250920155811_add_openrouter_api_key.sql extends the settings table. These run automatically when the Tauri application starts.

What is the purpose of the summary_processes table?

The summary_processes table tracks the lifecycle and output of the LLM-driven summarization pipeline. It stores processing status, timing, chunk counts, error messages, and final results for each meeting, enabling the UI to display progress and retrieve generated summaries.

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 →