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
meetingsrow automatically removes associatedtranscripts,summary_processes, andtranscript_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
meetingsis the root entity; all other tables cascade on deletiontranscriptsstores Whisper output with optional per-segment AI metadatasummary_processesprovides job-state tracking with performance metricstranscript_chunkspreserves the chunked input to LLMs for debugging- All persistence uses
sqlxwith 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →