| name | deck-management |
| description | How decks are stored in SQL, how to create/read/update/delete decks. Read before working with deck data. |
Deck Management
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,
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:
pnpm action list-decks
pnpm action get-deck --id=<deckId>
pnpm action get-deck --id=<deckId> --slideId=<slideId> --compact=false
pnpm action view-screen
From actions:
list-decks -- list all decks (returns id, title, slide count, timestamps)
get-deck -- get a single deck; Slides chat calls are compact by default.
Pass slideId for one targeted slide (full HTML by default), or use
compact=false when a full deck read is actually needed
Writing Decks
From scripts:
pnpm action db-exec --sql "INSERT INTO decks (id, title, data) VALUES (?, ?, ?)" --params '["new-id", "Title", "{...}"]'
From actions:
add-deck -- create a new deck
save-deck -- replace an authoritative full deck payload
delete-deck -- 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
data column 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