AI Summary
This page documents Deckly's AI Summary feature as it exists today: how it is triggered from the UI, how the Supabase edge function resolves scope and generates summaries, what models are used, what data is persisted, and what secrets must be configured for the feature to work.
Summary
AI Summary adds two capabilities to Deckly:
- a scoped summary for a deck, data room, or room folder
- follow-up chat that stays anchored to the current summary and retrieved document snippets
The implementation is split between the React app and the ai-summary Supabase edge function. The browser is responsible for opening the summary panel and sending requests; the edge function owns authentication, scope resolution, caching, quota checks, retrieval, generation, and chat persistence.
Current provider/model choices:
- Embeddings:
text-embedding-3-small - Summary generation:
gpt-4o-mini - Follow-up chat:
gpt-4o-mini
Deckly calls OpenAI directly from the edge function today. We are not using Vercel AI Gateway in the current implementation.
User Flow
Entry points
The summary panel can be opened from:
- the
Summarizebutton in the deck viewer - the
Summarizeaction in the content library deck table - the
Summarize with AIaction in saved decks - the
Summarizeaction in data room detail views and folder cards
What happens when a user clicks summarize
- The UI opens the AI Summary sidebar.
- The browser calls the
ai-summaryedge function with the requested scope. - The edge function resolves the scope, checks quota, and looks up any existing cache entry.
- If a fresh summary exists, it is returned from cache.
- If no cached summary exists, the edge function gathers document chunks, generates a summary, writes the cache row, and returns the result.
- Signed-in users can continue with follow-up chat against the current summary.
Guest behavior
Guests can summarize deck scopes only. Guest follow-up chat is locked, and the UI prompts sign-in before continuing the conversation.
Backend Architecture
The supabase/functions/ai-summary/index.ts function is the orchestration layer.
It performs these steps:
- authenticates the caller from the request header when a signed-in summary or chat is requested
- loads the user tier from
profiles - resolves the scope into document records
- builds a stable content hash for cache keys
- checks summary cache state
- enforces guest and signed-in quotas
- generates summary text through OpenAI
- persists summary cache rows and chat session/message rows
- performs lightweight retrieval for follow-up chat
The key service layers behind it are:
src/services/aiSummaryInitialOrchestrator.tsfor cache-aware summary generationsrc/services/aiChatSessionService.tsfor chat session management and message persistencesrc/services/aiRetrievalQueryService.tsfor snippet selectionsrc/services/aiSummaryCacheCore.tsfor cache lookup and cache row lifecyclesrc/services/aiSummaryQuotaPolicy.tsfor guest and signed-in limits
Data Model
The AI feature stores its own tables in Supabase:
ai_summary_cache- one row per scope/content-hash/model combination
- stores summary text, status, metadata, timestamps, and cache freshness
ai_chat_sessions- one row per signed-in chat session
- tracks the scope, content hash, summary cache reference, and session lifecycle
ai_chat_messages- stores user and assistant messages for each chat session
- includes retrieval context and model metadata
ai_guest_usage- tracks guest summary usage by IP address and date
- enforces the daily guest limit
ai_chunk_embeddings- stores chunk text and embeddings used for retrieval
- keyed by scope, content hash, embedding model, and model version
The foundation migration for these tables is:
supabase/migrations/20260502160000_add_ai_summary_foundations.sql
Model Strategy
Why the models are split
Summary generation, chat, and embeddings do different jobs.
- Embeddings should be optimized for retrieval quality and cost.
- Summary generation should be optimized for concise synthesis.
- Chat should be optimized for follow-up conversation grounded in the summary and retrieved snippets.
Current model choices
text-embedding-3-smallis used for document retrieval embeddings.gpt-4o-miniis used for initial summaries.gpt-4o-miniis also used for follow-up chat.
What is not split yet
The current chat and summary generation both use the same chat model. That is intentional for now. If the team later wants to test another chat provider or a gateway, the model boundary already exists in the service layer and edge function.
Cache and Quota Behavior
Cache key
Summary cache entries are keyed by:
- scope type
- scope id
- content hash
- model identifier
- model version
This means a summary is reused only when the underlying content and the model settings match.
Freshness behavior
- cached summaries are reopened without regenerating
- stale or content-changed summaries are regenerated
- no-content scopes are cached separately so repeated requests do not re-run generation
Quotas
Current quota policy is defined in src/constants/tiers.ts and enforced by the AI quota service:
- guest: 1 summary per 24 hours per IP
- FREE: 2 summaries per 24 hours
- PRO: 10 summaries per 24 hours
- PRO_PLUS: 50 summaries per 24 hours
The edge function returns quota-limited responses that the UI maps to sign-in or upgrade prompts.
Supabase function secrets
The ai-summary edge function requires:
OPENAI_API_KEYSUPABASE_SERVICE_ROLE_KEYorPROJECT_SECRET_KEY
The function also expects the Supabase runtime to expose:
SUPABASE_URL
The same Supabase project URL and anon key used by the frontend are reused by the function runtime. The browser app does not need the service-role secret.
What you do not need for AI Summary
These are not required for AI Summary specifically:
CONVERT_API_SECRETCRON_SECRET
Those belong to other edge functions in the repo.
Troubleshooting
503 Service Unavailable from ai-summary
This usually means the edge function failed to boot. Check:
OPENAI_API_KEYexists in Supabase function secretsSUPABASE_SERVICE_ROLE_KEYorPROJECT_SECRET_KEYexists in Supabase function secrets- the
ai-summaryfunction was deployed successfully - the
ai_summary_foundationsmigration has been applied
OPENAI_API_KEY is not configured
The edge function reads OPENAI_API_KEY directly from the function runtime. Adding the key only to the browser .env.local is not enough.
Empty summary or no_content
The current document set may not have extractable text yet. This can happen when:
- the deck has not been indexed into chunk embeddings
- the room/folder contains only unsupported or empty documents
- the content was filtered out during extraction
Chat is locked
Guest chat is intentionally disabled. Sign in to continue the conversation.
Files of Interest
supabase/functions/ai-summary/index.tssrc/services/aiSummaryInitialOrchestrator.tssrc/services/aiChatSessionService.tssrc/services/aiRetrievalQueryService.tssrc/services/aiSummaryCacheCore.tssrc/services/aiSummaryQuotaPolicy.tssrc/components/viewer/AiSummarySidebar.tsxsrc/hooks/useAiSummaryPanel.tssrc/pages/Viewer.tsxsrc/pages/DataRoomViewer.tsxsrc/pages/OwnerDeckPreview.tsxsrc/components/dashboard/DecksTable.tsxsrc/components/saved-decks/DocumentRow.tsxsrc/components/saved-decks/LibraryActionMenu.tsx
Developer Note
The current implementation uses OpenAI directly from the Supabase edge function. If we later move to a gateway or alternate provider, the best place to change that is inside supabase/functions/ai-summary/index.ts, because the rest of the app already treats summaries, retrieval, and chat as separate responsibilities.
