Saved Decks & Document Management (Deep-Dive)
This document provides an exhaustive technical breakdown of the Saved Decks (Library) infrastructure. It is designed for developers to understand the data flow, component hierarchy, and state management patterns.
1. Architecture Overview
The feature follows a strict Hook-driven pattern:
mermaid
graph TD
A[SavedDecksView.tsx] --> B[useLibrary.ts]
B --> C[TanStack Query Cache]
B --> D[organizerService.ts]
D --> E[Supabase / Postgres]
subgraph UI Components
A --> F[FolderCard]
A --> G[DocumentRow]
A --> H[Modals / Actions]
end
subgraph Mutations
B --> I[Optimistic Updates]
I --> C
end- SavedDecksView.tsx: The entry point. Handles Local UI State (visual filters, search, modal visibility) but delegates all Server State to the hook.
- useLibrary.ts: The brain. Manages fetching, caching, and optimistic mutations using TanStack Query.
- organizerService.ts: The data layer. Pure functions for Supabase queries and RPCs.
2. State Management (TanStack Query)
We use TanStack Query to ensure the library feels like a local desktop application:
- Query Keys: All keys are namespaced by the
userIdto prevent data leakage during multi-user sessions. - Stale Time: Set to 30 seconds. Navigation back to the library is instant because it's served from cache immediately.
- Invalidation: We explicitly invalidate related queries on mutations (e.g., creating a folder invalidates both folders and tags since tags might be created in-line).
- Optimistic UI: When a user moves a deck or updates a tag,
queryClient.setQueryDatapatches the cache before the network request resolves. - Layered Prefetching: We use intent-based prefetching to overcome loading delays. When a user hovers over the Saved Decks link or lands on the dashboard, we background-fetch the entire library (decks, folders, tags). Document rows also pre-load the Viewer module code on hover for instant entry.
3. Component Map
| Component | Responsibility |
|---|---|
SavedDecksView.tsx | Main layout, breadcrumbs, search, and filtered item orchestration. |
FolderCard.tsx | Visual representation of a "Collection". Displays deck counts, primary tags, and handle edit/delete actions. |
DocumentRow.tsx | The core document entry. Handles navigation, inline note editing, and quick actions. |
DeckActionMenu.tsx | A unified Radix UI menu for moving documents, managing tags, and removal. |
CreateFolderModal.tsx | Multi-step form for creating/editing folders. Supports adding/creating tags in one flow. |
ManageTagsModal.tsx | Global tag management (CRUD) for the user's personal organization. |
TagChip.tsx | Reusable atomic component for displaying tag labels with consistent coloring. |
4. Feature Implementation Details
A. Folder Organization (Collections)
Folders are represented in the library_folders table.
- The "Uncategorized" Logic: When
selectedFolderIdis set to"all", the UI filters for documents wherefolder_id === null. - Folder Identity: Each folder has a
colorproperty (e.g.,#666666,#54e98a) used for visual categorization. - Default Color: New folders default to
#666666(Grey) to maintain a grounded design aesthetic. - Instant Counts: Moving a document decrements the
deck_counton the source folder and increments it on the destination folder optimistically in the cache.
B. Multi-Tag System
Tags are managed via junction tables: library_folder_tags and library_deck_tags.
- Inheritance: Folders can have tags, and Decks can have tags.
- Filtering: Selecting a tag filter in the header performs an
array.somecheck against the tags attached to each deck in the local cache.
C. Inline Note Editing
Inside DocumentRow.tsx, we transition from a <p> to a <textarea> when the note text is clicked.
- Persistence: Targeted save via
noteService.saveNote(deck_id, content). - Reversion: If the user skips or hits Escape, the state reverts to the value from the
dexk.investor_noteprop from the cache.
5. Developer Cheat Sheet
Adding a new Document action:
- Update the
DeckActionMenu.tsxwith a newDropdownMenuItem. - Add a mutation to
useLibrary.tsto handle the backend call. - Implement an
onSuccesshandler in the mutation to patch the query cache.
Debugging Filter Logic:
- Check the
filteredDecksmemoized array inSavedDecksView.tsx. - Ensure that the
selectedFolderIdandselectedTagIddependencies are correctly clearing/setting.
Terms to Note:
- Artifacts vs Documents: We strictly use "Documents" in the user interface.
- Saves: The internal representation of "Saved Decks".
