Skip to content

State Management

Kassie manages state across three layers: server-side state, TUI client state, and Web client state. Each layer uses different strategies optimized for its context.

Server-Side State

All server state is held in-memory. There is no external database or cache for state storage.

Session Store

Maps session_id to session data:

FieldTypeDescription
session_idstringUUID, unique per login
profileProfileInfoActive database profile
connection*gocql.SessionDatabase connection handle
created_attime.TimeSession creation timestamp

Lifecycle:

  1. Created on successful Login
  2. Used for every authenticated request
  3. Destroyed on Logout or token expiry
  4. Connection pool returned on cleanup

Cursor Store

Maps cursor_id to Scylla paging state for pagination:

FieldTypeDescription
cursor_idstringUUID, unique per query
paging_state[]byteScylla paging state token
keyspacestringQuery keyspace
tablestringQuery table
where_clausestringActive filter (if any)
last_accessedtime.TimeFor expiration tracking

Lifecycle:

  1. Created on initial QueryRows or FilterRows
  2. Updated on each GetNextPage call
  3. Expires after 30 minutes of inactivity
  4. Manually cleared on new query to same table

Connection Pool

Per-profile database connection management:

Profile "local"  ──> Connection Pool (5 connections)
Profile "staging" ──> Connection Pool (5 connections)
Profile "prod"   ──> Connection Pool (5 connections)
  • Pools are created lazily on first login
  • Shared across sessions using the same profile
  • Health-checked and auto-reconnected
  • Closed when all sessions for a profile end

TUI State (Bubbletea)

The TUI uses Bubbletea's Elm Architecture: Model → Update → View.

Global State

go
type AppState struct {
    CurrentView    View          // connection, explorer, help
    Profile        *ProfileInfo  // active profile after login
    SessionToken   string        // JWT access token
    RefreshToken   string        // JWT refresh token
    Error          string        // current error message
}

Explorer State

go
type ExplorerState struct {
    Keyspaces      []Keyspace    // loaded keyspaces
    Tables         []Table       // tables for selected keyspace
    SelectedKS     string        // active keyspace name
    SelectedTable  string        // active table name
    Schema         *TableSchema  // column definitions
    Rows           []Row         // current page of data
    CursorID       string        // pagination cursor
    HasMore        bool          // more pages available
    Filter         string        // active WHERE clause
    FocusedPane    Pane          // sidebar, grid, or inspector
}

Component State

Each component manages its own local state:

ComponentLocal State
SidebarScroll position, expanded keyspaces, search text
DataGridColumn widths, horizontal scroll offset, selected row index
InspectorScroll position, expanded JSON nodes
FilterBarInput text, cursor position, validation error
StatusBarDerived from global + explorer state (no own state)

State Flow

User Input ──> Bubbletea Update() ──> New Model ──> View() ──> Terminal

                    ├── Local state change (navigation, UI toggle)

                    └── gRPC call ──> Server ──> Response ──> Update Model

Web State

The Web client uses a three-layer state model following React best practices.

Server State (TanStack Query)

All data fetched from the API lives in the TanStack Query cache:

Query KeyDataStale Time
['profiles']Profile list5 minutes
['keyspaces']Keyspace list5 minutes
['tables', keyspace]Tables for a keyspace5 minutes
['schema', keyspace, table]Table schema/columns5 minutes
['rows', keyspace, table]Initial row queryOn navigation
['rows', keyspace, table, 'filter', where]Filtered rowsOn navigation
['rows', 'page', cursorId]Next page of dataOn navigation

Benefits:

  • Automatic background refetching
  • Cache invalidation
  • Request deduplication
  • Loading and error states built-in

UI State (Zustand)

Ephemeral client-side state stored in lightweight Zustand stores:

Auth Store:

FieldTypePersisted
accessTokenstringlocalStorage
refreshTokenstringlocalStorage
expiresAtnumberlocalStorage
profileProfileInfolocalStorage
isAuthenticatedbooleanDerived

UI Store:

FieldTypePersisted
sidebarCollapsedbooleanlocalStorage
inspectorOpenbooleanlocalStorage
selectedRowIndexnumberNo
theme'light' | 'dark' | 'system'localStorage

URL State (React Router)

Navigation state encoded in URL search parameters for shareability:

/?keyspace=app_data&table=users&filter=id%3D'abc'&page=2
ParameterTypeDescription
keyspacestringSelected keyspace
tablestringSelected table
filterstringWHERE clause (URL-encoded)
pagenumberCurrent page number

Benefits:

  • Shareable links
  • Browser back/forward navigation
  • Bookmark support
  • State survives page refresh

Web State Flow

User Action

    ├── UI change ──> Zustand store ──> React re-render

    ├── Navigation ──> URL params ──> TanStack Query fetch ──> Re-render

    └── Data fetch ──> TanStack Query ──> API call ──> Cache update ──> Re-render

State Persistence Summary

StateTUIWeb
JWT tokensIn-memorylocalStorage
UI preferencesNot persistedlocalStorage
Navigation stateIn-memoryURL params
Query cacheNot applicableTanStack Query (memory)
Server sessionsIn-memory (server)In-memory (server)
Pagination cursorsIn-memory (server)In-memory (server)

Released under the MIT License.