Decks are stored in the decks SQL table via Drizzle ORM. Each deck row contains the full deck JSON (slides, metadata) in a data TEXT column.
Schema
CREATE TABLE decks (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
data TEXT NOT NULL, -- Full deck JSON (slides array, metadata)
created_at TEXT DEFAULT (current_timestamp),
updated_at TEXT DEFAULT (current_timestamp)
);
Deck JSON Structure
The data column stores a JSON object:
{
"title": "My Presentation",
"slides": [
{
"id": "slide-1",
"content": "<div class=\"fmd-slide\" style=\"...\">...</div>",
"layout": "title"
},
{
"id": "slide-2",
"content": "<div class=\"fmd-slide\" style=\"...\">...</div>",
"layout": "content"
}
]
}
Each slide has an id, HTML content, and optional layout type.
Reading Decks
From scripts:
# List all decks (metadata only)
pnpm action list-decks
# Get a specific deck with all slides
pnpm action get-deck --id=<deckId>
# See what the user is looking at
pnpm action view-screen
From the API:
GET /api/decks-- list all decks (returns id, title, slide count, timestamps)GET /api/decks/:id-- get a single deck with full data
Writing Decks
From scripts:
# Use db-exec to insert/update
pnpm action db-exec --sql "INSERT INTO decks (id, title, data) VALUES (?, ?, ?)" --params '["new-id", "Title", "{...}"]'
From the API:
POST /api/decks-- create a new deckPUT /api/decks/:id-- update an existing deckDELETE /api/decks/:id-- delete a deck
Important Rules
- Always use the API or Drizzle -- never write raw JSON files for deck storage
- Deck IDs are stable -- once created, a deck's ID doesn't change
- Slide IDs within a deck are stable -- used for referencing specific slides
- The
datacolumn is the full source of truth -- title is duplicated at the top level for listing queries - SSE events (
source: "resources") fire when decks change, keeping the UI in sync