App Contexts (Picker vs Shell)
Relevant source files
The following files were used as context for generating this wiki page:
Vata is designed as a single-tree-at-a-time desktop project editor, mirroring the workflow of professional applications like VS Code or Logic Pro. The application is bifurcated into two primary contexts: the Outside Picker (Home) and the Inside Shell (Tree View). This distinction is fundamental to the app's architecture, resource management, and routing.
The boundary between these contexts is strictly enforced by the routing layer. The Outside Picker operates at the root URL (/), while the Inside Shell is activated for any route under /tree/$treeId/.... This separation ensures that tree-specific resources, particularly database connections, are only active when a specific project is being edited.
Sources: CLAUDE.md:19-25, README.md:10-15
Architectural Overview
The application utilizes a two-database design to support these distinct contexts. A persistent "System DB" handles app-level metadata, while individual "Tree DBs" store genealogical data for specific projects.
| Context | URL Pattern | Primary Database | Purpose |
|---|---|---|---|
| Outside Picker | / | system.db | Tree management (create, open, rename, delete), app settings, and global metadata. |
| Inside Shell | /tree/$treeId/... | <tree-name>.db | Genealogical data manipulation, individual/family management, and event tracking. |
Sources: CLAUDE.md:31-40, src/db/connection.ts:316-350
The following diagram illustrates the transition and structural difference between these two application states:
Visual representation of the application lifecycle moving from the global picker to a specific tree project.
Sources: CLAUDE.md:21-25, src/pages/Home.tsx:88-97
The Outside Picker (Home)
The Outside Picker, implemented primarily in src/pages/Home.tsx, serves as the application's entry point. It provides the user interface for managing the lifecycle of family trees without loading the heavy genealogical data associated with them.
Key Responsibilities
- Tree Discovery: Lists all available trees stored in the System DB.
- Tree Lifecycle: Handles creation of new trees, importing GEDCOM files, renaming/editing tree metadata, and deleting tree files.
- Global Preferences: Provides access to application-wide settings like theme and language via the
PreferencesPopover. - Context Transition: Orchestrates the opening of a tree through
TreeManager.open(treeId)followed by navigation to the shell route.
Sources: src/pages/Home.tsx:49-140, CLAUDE.md:120-125
Database Operations in Picker Context
While in the Picker context, the app exclusively uses getSystemDb() to access system.db. This database contains the trees table, which stores the following fields:
id: Primary key.name: Display name of the tree.path: Filesystem path to the specific SQLite tree database.individual_count/family_count: Cached statistics for display on the Home cards.last_opened_at: Timestamp for sorting "Recent" projects.
Sources: src/db/connection.ts:290-305, src/pages/Home.tsx:150-180
The Inside Shell (Tree View)
The Inside Shell is defined by the layout route in src/routes/tree/$treeId.tsx. This context represents a "loaded project" state where the application focus is locked to a single genealogical database.
The Boundary Lifecycle
The shell is responsible for the critical transition of the active database connection. When a user enters a tree route:
- Mount: The
openTreeDb(path)function is called. This initializes the connection to the tree-specific SQLite file and applies essential PRAGMAs (WAL mode, foreign keys, etc.). - Active State: Child routes (e.g., Individuals, Families) can now call
getTreeDb(). This function throws an error if called outside of the Shell context. - Unmount: When navigating back to the Home page or closing the tree,
closeTreeDb()is invoked to safely release the file lock.
Sources: CLAUDE.md:21-24, src/db/connection.ts:352-378
Navigation and Sub-pages
Once inside the shell, the application provides a dedicated navigation structure for tree entities. Common routes include:
/tree/$treeId/: Main tree visualization./tree/$treeId/individuals: Table view of persons./tree/$treeId/families: Management of relationships./tree/$treeId/places: Hierarchical location data.
Sources: CLAUDE.md:105-115, src/pages/PlacesPage.tsx:15-30
The sequence of entering a tree context is shown below:
Sequence of operations triggered when transitioning from the Picker to the Shell context.
Sources: src/db/connection.ts:352-370, src/pages/Home.tsx:88-95
Connection Management
Technical enforcement of the context boundary relies on the state maintained in src/db/connection.ts.
| Function | Context | Behavior |
|---|---|---|
getSystemDb() | Both | Opens/initializes system.db on first call; remains open for app duration. |
openTreeDb(path) | Shell (Entry) | Closes any existing tree connection and opens the database at the provided path. |
getTreeDb() | Shell (Internal) | Returns the active tree connection. Throws if no tree is open. |
closeTreeDb() | Shell (Exit) | Nullifies the active treeDb reference and closes the SQLite connection. |
Sources: src/db/connection.ts:321-378, CLAUDE.md:31-40
Debugging Contexts
The DebugDrawer component provides a visual way to verify which context is currently active by exposing raw data from both the System DB and the Tree DB. In the Picker context, the "Tree DB" tab displays a "No active tree" state, whereas in the Shell context, it displays entity counts (individuals, names, events) from the project database.
Sources: src/components/debug-drawer.tsx:110-145
Conclusion
The separation between the Outside Picker and the Inside Shell allows Vata to maintain a lightweight global state while enabling complex, isolated data management for individual family trees. By grounding the database connection lifecycle in the routing system, the application ensures data integrity and efficient resource usage across different project databases.