---
title: "Server Mode Guide for bettr"
author: "bettr package authors"
date: "`r Sys.Date()`"
output:
  BiocStyle::html_document:
    toc: true
    toc_float: true
    number_sections: true
vignette: >
  %\VignetteIndexEntry{Server Mode Guide for bettr}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
editor_options:
  markdown:
    wrap: 72
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

**Version 1.6.0 and later**

## Overview

Version 1.6.0 introduces **server mode**, a new way to deploy and use
bettr that enables browser-based JSON file uploads, automatic caching,
and programmatic data loading via URLs. This makes bettr suitable for:

-   **Multi-user server deployments** where different users need to
    visualize their own data
-   **Web-based workflows** without requiring R programming knowledge
-   **Data sharing** through portable JSON files and direct links

------------------------------------------------------------------------

## What's New in Version 1.6.0

### Server Mode for JSON Uploads

The `bettr()` function now supports a `serverMode` parameter that
launches the app in a special mode where users upload JSON files through
the browser.

**Benefits:**

-   No R programming required for end users
-   Multiple users can use the same server instance with their own data
-   Data is isolated per user session
-   Automatic browser caching for quick reload

### JSON Serialization

New functions for converting bettr data to/from JSON format:

-   `bettrToJSON()` - Export `SummarizedExperiment` to JSON
-   `bettrFromJSON()` - Import JSON back to `SummarizedExperiment`

**Benefits:**

-   Portable data format (language-agnostic)
-   Easy data sharing between users and systems
-   Preserves all metadata, colors, weights, and transformations
-   Enables web-based workflows

### Browser localStorage Caching

Automatic client-side caching of uploaded JSON data in server mode.

**What gets cached:**

-   Uploaded JSON data

**Benefits:**

-   Page refresh doesn't lose your work
-   Survives browser restarts
-   No manual saving required
-   Automatic caching after upload

### Cache Versioning

Administrators can force cache invalidation when deploying updates.

**Use cases:**

-   Deploy schema changes that require fresh data
-   Force all users to re-upload after breaking changes
-   Manage cache in multi-tenant environments
-   Troubleshooting cache-related issues

### URL Parameters for Programmatic Loading

Load JSON data automatically via URL query parameters.

**Benefits:**

-   Create direct links to specific visualizations
-   Integrate with external tools and pipelines
-   Automate opening visualizations after benchmark runs
-   Share analysis results with a simple URL

------------------------------------------------------------------------

## Server Mode Basics

### Starting a Server

```{r server-start}
#| eval: false

library(bettr)

# Basic server mode
bettr(serverMode = TRUE)

# With cache versioning
bettr(serverMode = TRUE, cacheVersion = "v1.0")

# Custom theme
bettr(serverMode = TRUE, bstheme = "flatly")
```

### What Happens When You Start Server Mode

1.  The app starts listening on a local port (e.g.,
    `http://127.0.0.1:4567`)
2.  Users navigate to this URL in their browser
3.  The upload interface is displayed
4.  Users can:
    -   Upload JSON files manually
    -   Have data loaded automatically via URL parameters (if provided)
5.  Once data is uploaded, the full bettr interface appears
6.  All interactions are automatically cached in the browser

### User Interface

**Upload Mode Interface:**

-   Clean, simple upload area
-   "Choose JSON File" button
-   Information about browser caching
-   No "Close app" button (for multi-user safety)

**After Upload:**

-   Full bettr visualization interface
-   All standard features available
-   "Load Data" panel for uploading new files
-   "Clear Cached Data" button

------------------------------------------------------------------------

## JSON Serialization

### Creating JSON Files

#### From Data Frames

```{r json-from-dataframe}
#| eval: false

library(bettr)

# Create benchmark data
benchmark_data <- data.frame(
    Method = c("AlgorithmA", "AlgorithmB", "AlgorithmC"),
    Accuracy = c(0.95, 0.92, 0.89),
    Speed = c(120, 150, 100),
    Memory = c(256, 512, 128)
)

# Add metric metadata
metric_info <- data.frame(
    Metric = c("Accuracy", "Speed", "Memory"),
    Type = c("Quality", "Performance", "Resource"),
    Unit = c("Proportion", "ms", "MB")
)

# Define initial transformations
transforms <- list(
    Speed = list(flip = TRUE, transform = "[0,1]"),
    Memory = list(flip = TRUE, transform = "[0,1]")
)

# Create SummarizedExperiment
bettrSE <- assembleSE(
    df = benchmark_data,
    idCol = "Method",
    metricInfo = metric_info,
    initialTransforms = transforms
)

# Export to JSON
json_file <- tempfile(fileext = ".json")
bettrToJSON(bettrSE, file = json_file)
```

<details>
<summary>**Click to view example JSON structure**</summary>

The exported JSON file has the following structure:

```json
{
  "idCol": "Method",
  "data": [
    {
      "Method": "AlgorithmA",
      "Accuracy": 0.95,
      "Speed": 120,
      "Memory": 256,
      "_row": "AlgorithmA"
    },
    {
      "Method": "AlgorithmB",
      "Accuracy": 0.92,
      "Speed": 150,
      "Memory": 512,
      "_row": "AlgorithmB"
    },
    {
      "Method": "AlgorithmC",
      "Accuracy": 0.89,
      "Speed": 100,
      "Memory": 128,
      "_row": "AlgorithmC"
    }
  ],
  "metricInfo": [
    {
      "Metric": "Accuracy",
      "Type": "Quality",
      "Unit": "Proportion"
    },
    {
      "Metric": "Speed",
      "Type": "Performance",
      "Unit": "ms"
    },
    {
      "Metric": "Memory",
      "Type": "Resource",
      "Unit": "MB"
    }
  ],
  "idInfo": {},
  "initialWeights": {},
  "initialTransforms": {
    "Speed": {
      "flip": true,
      "transform": "[0,1]"
    },
    "Memory": {
      "flip": true,
      "transform": "[0,1]"
    }
  }
}
```

**Key components:**

- `idCol`: Name of the identifier column
- `data`: Array of objects, one per method with all metric values
- `metricInfo`: Metadata about each metric (optional classifications, units, etc.)
- `idInfo`: Additional metadata about methods (optional)
- `initialWeights`: Default metric weights (optional)
- `initialTransforms`: Transformations to apply to metrics (flip for "lower is better", transform for normalization)

</details>

#### From Existing SummarizedExperiment

```{r json-from-se}
#| eval: false

# If you already have a SummarizedExperiment
json_file <- tempfile(fileext = ".json")
bettrToJSON(my_existing_SE, file = json_file)

# Get JSON as string (for programmatic use)
json_string <- bettrToJSON(my_existing_SE, file = NULL)
```

### Reading JSON Files

```{r json-read}
#| eval: false

# Read from file
bettrSE <- bettrFromJSON(file = "benchmark_results.json")

# Read from JSON string
bettrSE <- bettrFromJSON(json = json_string)

# Use in non-server mode
bettr(bettrSE = bettrSE)
```

------------------------------------------------------------------------

## URL Parameters for Programmatic Loading

### Overview

URL query parameters allow you to automatically load JSON data when
users open the app.

### Two Loading Methods

#### Load from URL (`jsonUrl`)

```         
http://localhost:4567/?jsonUrl=https://example.com/data.json
```

**Use cases:**

-   Data hosted on web servers
-   GitHub raw file URLs
-   Cloud storage (S3, Google Cloud Storage, etc.)
-   Internal company servers

**Example:**

```{r url-jsonurl}
#| eval: false

# Start server
bettr(serverMode = TRUE)

# Construct URL
base_url <- "http://localhost:4567"
data_url <- "https://raw.githubusercontent.com/user/repo/main/results.json"
full_url <- paste0(base_url, "/?jsonUrl=", URLencode(data_url, reserved = TRUE))

# Open in browser
browseURL(full_url)
```

#### Load from File Path (`jsonFile`)

```         
http://localhost:4567/?jsonFile=/absolute/path/to/data.json
```

**Use cases:**

-   Local server deployments
-   Internal network file shares
-   Automated pipelines on same machine
-   Development and testing

**Example:**

```{r url-jsonfile}
#| eval: false

# Start server
bettr(serverMode = TRUE)

# Construct URL
base_url <- "http://localhost:4567"
file_path <- "/Users/username/benchmarks/latest_results.json"
full_url <- paste0(base_url, "/?jsonFile=", URLencode(file_path, reserved = TRUE))

# Open in browser
browseURL(full_url)
```

**Using the included example data:**

The bettr package includes a pre-exported JSON file from the
DuoClustering2018 dataset that can be used for testing and examples.

```{r url-jsonfile-example}
#| eval: false

# Start server
bettr(serverMode = TRUE)

# Get path to included example JSON file
json_path <- system.file("extdata", "duo2018_bettr.json", package = "bettr")

# Construct URL
base_url <- "http://localhost:4567"
full_url <- paste0(base_url, "/?jsonFile=", URLencode(json_path, reserved = TRUE))

# Open in browser
browseURL(full_url)
```

------------------------------------------------------------------------

## Browser Cache Management

### How Caching Works

1.  **Automatic Save:**
    -   When you upload a JSON file, it's saved to browser localStorage
    -   Happens immediately after successful upload
    -   No manual action required
2.  **Automatic Restore:**
    -   When you reload the page, cached data is automatically restored
    -   A notification confirms the restoration
3.  **Cache Storage:**
    -   Stored in browser's localStorage (typically 5-10MB limit)
    -   Specific to your browser and domain
    -   Persists across browser restarts
    -   Not shared across different browsers or devices

### Manual Cache Control

#### Clear Cache Button

Located in the "Load Data" accordion panel:

```         
Load Data
├── Choose JSON File
└── Clear Cached Data (button)
```

Click to:

-   Remove all cached data
-   Start fresh with a new dataset
-   Free up browser storage

### Cache Versioning (Administrators)

#### Setting Up Versioning

```{r cache-versioning}
#| eval: false

# Deploy version 1.0
bettr(serverMode = TRUE, cacheVersion = "v1.0")

# Later, deploy version 1.1 with breaking changes
bettr(serverMode = TRUE, cacheVersion = "v1.1")
```

#### Version String Format

Any string works - choose what makes sense for your workflow:

```{r version-formats}
#| eval: false

# Semantic versioning
cacheVersion = "v1.2.3"

# Date-based
cacheVersion = "2025-10-07"

# Build numbers
cacheVersion = "build-456"

# Custom
cacheVersion = "production-release-oct2025"
```

#### User Experience

When version changes:

1.  User opens the app
2.  Browser detects version mismatch
3.  Cache is automatically cleared
4.  User sees: **"Cache was cleared due to version update. Please upload
    your data."**
5.  User uploads their JSON file again
6.  New cache is created with current version

# Session info {-}

```{r session-info}
sessionInfo()
```

