Meetily Database Schema for Meetings, Transcripts, and Summaries Explained

Meetily uses a SQLite database with five core tables—meetings, transcripts, summary_processes, transcript_chunks, and settings—to store meeting metadata, raw transcript segments, AI processing state, and LLM configuration.

The schema is implemented in the Tauri-based Rust backend and managed through sqlx. It provides atomic storage for the entire meeting lifecycle, from initial transcription through chunked LLM processing to final summary generation.

Schema Overview

The database schema for storing meetings, transcripts, and summaries in Meetily is defined in frontend/src-tauri/migrations/20250916100000_initial_schema.sql. All tables use UUID-based TEXT primary keys and declare foreign-key relationships that cascade deletions.

Core Tables

Table Purpose Key Relationship
meetings Meeting container with title and timestamps Root entity
transcripts Individual transcript segments with optional AI highlights meeting_id → meetings.id
summary_processes Lifecycle tracking for summarization jobs meeting_id → meetings.id
transcript_chunks Chunked text fed to LLMs for processing meeting_id → meetings.id
settings / transcript_settings LLM provider and model configuration Standalone

The meetings Table

This table represents a single meeting session.

-- From initial_schema.sql
CREATE TABLE meetings (
    id TEXT PRIMARY KEY,
    title TEXT NOT NULL,
    created_at TEXT NOT NULL,
    updated_at TEXT NOT NULL
);

The id is generated as a UUID. The title is typically derived from the meeting name or timestamp.

The transcripts Table

Stores raw transcript segments produced by the Whisper speech-to-text engine.

CREATE TABLE transcripts (
    id TEXT PRIMARY KEY,
    meeting_id TEXT NOT NULL REFERENCES meetings(id) ON DELETE CASCADE,
    transcript TEXT NOT NULL,
    timestamp TEXT NOT NULL,
    summary TEXT,
    action_items TEXT,
    key_points TEXT
);

Per-segment AI enrichment: The optional columns summary, action_items, and key_points allow Meetily to store AI-generated highlights for individual transcript segments before full-meeting summarization.

Saving Transcripts

In frontend/src-tauri/src/database/repositories/transcript.rs (lines 10-78), the TranscriptsRepository handles persistence:

use crate::database::repositories::TranscriptsRepository;

// `transcripts` is a slice of `TranscriptSegment` from Whisper
let meeting_id = TranscriptsRepository::save_transcript(
    &db_pool,
    "Team Stand-up – 2024-08-01",
    &transcripts,
    Some("/path/to/meeting/folder".into()),
)
.await?;

Fetching transcripts for display uses a parameterized query:

let transcripts = sqlx::query_as::<_, Transcript>(
    "SELECT * FROM transcripts WHERE meeting_id = ?"
)
.bind(&meeting_id)
.fetch_all(&db_pool)
.await?;

The summary_processes Table

Tracks the asynchronous lifecycle of meeting-wide summarization jobs.

CREATE TABLE summary_processes (
    meeting_id TEXT PRIMARY KEY REFERENCES meetings(id) ON DELETE CASCADE,
    status TEXT NOT NULL,  -- pending, processing, finished, error
    created_at TEXT NOT NULL,
    updated_at TEXT NOT NULL,
    error TEXT,
    result TEXT,
    start_time TEXT,
    end_time TEXT,
    chunk_count INTEGER,
    processing_time INTEGER,
    metadata TEXT
);

State machine: The status column drives the UI state, while chunk_count, processing_time, and start_time/end_time provide performance telemetry.

Updating Process Status

The ON CONFLICT clause enables upsert semantics for idempotent status updates:

sqlx::query(
    "INSERT INTO summary_processes (meeting_id, status, created_at, updated_at)
     VALUES (?, ?, ?, ?)
     ON CONFLICT(meeting_id) DO UPDATE SET
        status = excluded.status,
        updated_at = excluded.updated_at"
)
.bind(&meeting_id)
.bind("processing")
.bind(chrono::Utc::now())
.bind(chrono::Utc::now())
.execute(&db_pool)
.await?;

The transcript_chunks Table

Stores the chunked representation of full transcripts prepared for LLM ingestion.

CREATE TABLE transcript_chunks (
    meeting_id TEXT PRIMARY KEY REFERENCES meetings(id) ON DELETE CASCADE,
    meeting_name TEXT,
    transcript_text TEXT NOT NULL,
    model TEXT,
    model_name TEXT,
    chunk_size INTEGER,
    overlap INTEGER,
    created_at TEXT NOT NULL
);

The chunk_size and overlap columns record the tokenization strategy used, enabling reproducibility and A/B testing of different chunking approaches.

Configuration Tables

settings

Global application configuration for LLM providers and Whisper settings.

CREATE TABLE settings (
    id TEXT PRIMARY KEY,
    provider TEXT,
    model TEXT,
    whisperModel TEXT,
    -- API key fields omitted for security
    created_at TEXT,
    updated_at TEXT
);

transcript_settings

Per-user or per-session transcription configuration with provider-specific overrides.

Foreign Key Cascade Behavior

All child tables declare ON DELETE CASCADE:

  • Deleting a meetings row automatically removes associated transcripts, summary_processes, and transcript_chunks
  • This ensures referential integrity without application-level cleanup logic

Key Implementation Files

File Responsibility
frontend/src-tauri/migrations/20250916100000_initial_schema.sql DDL for all tables
frontend/src-tauri/src/database/repositories/transcript.rs Transcript CRUD and meeting creation
frontend/src-tauri/src/database/repositories/meeting.rs Meeting queries with transcript pagination
frontend/src-tauri/src/summary/processor.rs summary_processes and transcript_chunks management

Summary

  • The database schema for storing meetings, transcripts, and summaries in Meetily centers on SQLite with five interconnected tables
  • meetings is the root entity; all other tables cascade on deletion
  • transcripts stores Whisper output with optional per-segment AI metadata
  • summary_processes provides job-state tracking with performance metrics
  • transcript_chunks preserves the chunked input to LLMs for debugging
  • All persistence uses sqlx with compile-time checked queries in the Tauri Rust backend

Frequently Asked Questions

What database does Meetily use for meeting data?

Meetily uses SQLite accessed through the sqlx Rust crate. The database file is managed by the Tauri backend in frontend/src-tauri/.

How does Meetily handle transcript chunking for LLM processing?

The transcript_chunks table stores the preprocessed, chunked transcript text along with parameters (chunk_size, overlap, model_name) used for the splitting strategy. This enables reproducibility and debugging of chunking decisions.

Can transcripts be deleted independently of meetings?

No. The schema declares ON DELETE CASCADE on meeting_id foreign keys. Deleting a meeting automatically removes its transcripts, summary processes, and transcript chunks.

Where is the AI summary status tracked?

The summary_processes table tracks the full lifecycle—pending, processing, finished, or error—with timing metrics and error messages. This table is updated by frontend/src-tauri/src/summary/processor.rs.

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 →