Skip to content

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
  1. SavedDecksView.tsx: The entry point. Handles Local UI State (visual filters, search, modal visibility) but delegates all Server State to the hook.
  2. useLibrary.ts: The brain. Manages fetching, caching, and optimistic mutations using TanStack Query.
  3. 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 userId to 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.setQueryData patches 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

ComponentResponsibility
SavedDecksView.tsxMain layout, breadcrumbs, search, and filtered item orchestration.
FolderCard.tsxVisual representation of a "Collection". Displays deck counts, primary tags, and handle edit/delete actions.
DocumentRow.tsxThe core document entry. Handles navigation, inline note editing, and quick actions.
DeckActionMenu.tsxA unified Radix UI menu for moving documents, managing tags, and removal.
CreateFolderModal.tsxMulti-step form for creating/editing folders. Supports adding/creating tags in one flow.
ManageTagsModal.tsxGlobal tag management (CRUD) for the user's personal organization.
TagChip.tsxReusable 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 selectedFolderId is set to "all", the UI filters for documents where folder_id === null.
  • Folder Identity: Each folder has a color property (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_count on 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.some check 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_note prop from the cache.

5. Developer Cheat Sheet

Adding a new Document action:

  1. Update the DeckActionMenu.tsx with a new DropdownMenuItem.
  2. Add a mutation to useLibrary.ts to handle the backend call.
  3. Implement an onSuccess handler in the mutation to patch the query cache.

Debugging Filter Logic:

  • Check the filteredDecks memoized array in SavedDecksView.tsx.
  • Ensure that the selectedFolderId and selectedTagId dependencies 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".

Built with ❤️ for Founders