# Dashgrid LLM Docs
Auto-generated reference from the Dashgrid documentation pages.

# Intro

## What is Dashgrid
**Dashgrid** is a multi-purpose tracking platform providing tools to create, run, combine, and share tracking tools like dashboards, widgets, data buckets, and more.
  - **Dashgrid principles**:  Keep it simple, user-friendly, focused, up-to-date, and flexible.
  - **Multi-purpose**: Dashgrid is designed and developed for application in diverse use cases.
  - **Reactive**: Dashgrid is engineered for responsiveness, fast usage, and user-experience.
  - **Actionable**: Dashgrid helps to clearly define and present relevant data, signals, and insights.
  - **Lean integration**: By design, Dashgrid requires no access to your systems. You submit only the relevant metrics through a simple, secure API.

## Dashgrid is for
 - **Data providers**: Developers, data scientists, technical teams, and other data providers who need to track, share, or expose metrics, indicators, and insights to stakeholders.
 - **Stakeholders**: Teams, clients, public who need to track and consume actionable indicators and insights efficiently, without technical knowledge and without time-consuming data exploration.

---

# Dashboards

A dashboard is a top-level container that
- provides a **Grid** system for **Widgets**
- provides a unique **URL Path** for access e.g. `/workspace-name/dashboard-name`
- sets global style preferences for grid and widgets

### Key Features
- **Flexible Grid Layout** - Customizable columns and rows with automatic responsive behavior
- **Custom URL Paths** - User-friendly, shareable URLs for each dashboard
- **Style Presets** - Optimized rendering for low-frequency and high-frequency data updates
- **Widget Management** - Add, position, and configure multiple widgets on a single dashboard
- **Sharing Controls** - Manage access permissions for users and teams
- **Real-Time Updates** - Widgets automatically update as new data arrives

## Grid System

### The grid automatically
- controls how widgets can be placed on a dashboard
- controls how widgets behave under certain dynamic conditions
- handles responsive sizing on different screen sizes, resizing a window, rotating a device
- handles widget overflow and scrolling
- handles empty cells

### The grid is defined by
- **Columns** - Number of columns
- **Rows** - Number of rows

The **grid size** results from the numbers of columns and rows, and determines the maximum number of widgets can be placed on a dashboard.

### Widgets positioning
- **Cell Index** - Starting position in the grid
- **Column Span** - How many columns the widget occupies
- **Row Span** - How many rows the widget occupies

## Style Presets
Styles are optimized to enhance dashboard user-experience based on your data update patterns.
For dashboards with high-frequency data updates (shorter than a minute), specialized styles ensure 
stable positioning of tooltips, numbers, and chart labels, while maintaining smooth rendering performance.

Currently Dashgrid provides two style presets:
- Default LF: for dashboards updated in low-frequency (update cycles longer than a minute)
- Default HF: for dashboards updated in high-frequency (update cycles shorter than a minute)

## URL Path
Each dashboard has a unique **URL Path** within its workspace. The canonical
address combines the workspace path and dashboard path.

  e.g. `https://dashgrid.com/workspace-path/dashboard-path`

When creating a dashboard, its title automatically provides a readable path.
In title mode, the Full URL preview always follows the title; no separate slug
input is shown. Admins and Owners can instead enable a server-generated random
path in Dashboard Settings.
Editors cannot make a title change that would change a title-derived path.

Title-derived paths use 3–50 lowercase letters, numbers, and hyphens. The form
checks availability within the workspace. Changing the path immediately
changes the dashboard and widget addresses; existing links using the previous
path stop working and do not redirect.

## Access Control

### Data Buckets and API Keys
Data Buckets and API Keys
- can be only accessed and managed by users with roles Owner or Admin
- are only accessible within the dashboard where those are defined

For more see the Sharing section.

## Deleting a Dashboard

Deleting a dashboard **permanently deletes everything it contains**:
- all **Widgets**
- all **Data Buckets**, including all stored records
- all **API Keys** — they are revoked immediately, and clients using them stop working
- all sharings and pending invites — every user loses access to the dashboard immediately

Deletion is restricted to the dashboard **Owner** and must be confirmed by
typing the dashboard title. It cannot be undone.

Deletion is all-or-nothing: if the dashboard's buckets and keys cannot be
removed from the data service, nothing is deleted and you can retry.

Before deleting, stop all clients that still submit data to the dashboard's
buckets.

---

# Widgets

Widgets are interactive data visualizations placed on dashboards. Dashgrid provides widgets optimized for
great user-experience, readability, and preformance.

### Key Features
- **Multiple Chart Types** - Line, area, column, bar, scatter, and number visualizations, more coming soon
- **Multi-Series Support** - Display up to 10 variables in a single widget
- **Flexible Positioning** - Span multiple columns and rows on the dashboard grid
- **Customizable Formatting** - Configure axis labels, tooltips, colors, and display formats
- **Real-Time Data** - Automatic updates via WebSocket connections to data buckets
- **Performance Optimized** - Configurable data point limits for optimal rendering

### Widget Types
Dashgrid provides currently six widget types to visualize your data:
- **Line Chart** - Connected data points with lines
- **Area Chart** - Lines with filled areas below
- **Column Chart** - Vertical bars
- **Bar Chart** - Horizontal bars
- **Scatter Chart** - Individual data points without connecting lines
- **Number** - Single numeric values (up to 4 values)
- More widget types will be added in the future

## Position & Size
Widgets are positioned on the dashboard grid using three properties:
- **Cell Index** - The starting position in the grid
- **Column Span** - Number of columns the widget occupies (max. 3)
- **Row Span** - Number of rows the widget occupies (max. 2)

## Axis
Configure axis display for chart widgets:
- **X-Axis** - Label format and visibility
- **Y-Axis** - Domain range (min/max), label format, and visibility
- **Grid Lines** - Horizontal and vertical grid visibility

### Format Options
Available formats for axis labels:
- **str** - Plain string
- **int** - Integer number
- **dec1**, **dec2**, **dec3** - Decimal numbers with 1, 2, or 3 decimal places
- **dateshort**, **datelong** - Short and long date formats
- **datetime** - Full date and time
- **monthyear** - Month and year only
- **timeshort12**, **timeshort24** - 12-hour or 24-hour short time
- **timelong12**, **timelong24** - 12-hour or 24-hour long time

## Tooltip
Configure how tooltips display data:
- **Label Format** - How labels appear (string, date formats, time formats)
- **Value Format** - How values appear (string, integer, decimal places)
- **Unit** - Optional unit displayed for values (e.g., "°C", "%", "USD")

Format options are the same as listed in the Axis section above.

## Series
In Dashgrid widgets, series allow you to display multiple variables within a single widget. For example, a line chart can show temperature, humidity, and pressure as three separate series, each with its own line and color, label and value in tooltip.

### Series Configuration
Each series in a widget has the following properties:
- **Series Key** - Numeric identifier (1-10) that maps to the data field in your data bucket
- **Label** - Human-readable name displayed in legends and tooltips
- **Color** - Visual color for distinguishing the series
- **Shape Type** - Interpolation method for line/area charts (monotone, linear, basis, step)

Most widget types support up to 10 series.\
The Number widget supports up to 4 series.

### Additional Options
- **Show Records** - Number of data points displayed (default: 200, range: 1-10,000). The amount of data points heavily affects user-experience, readability, and performance.
- **Stacked** - For multi-series charts, stack series on top of each other (available for area, bar, column charts)

## Data & API
Each widget connects to a **Data Bucket** to receive data:
- Create a data bucket first
- Edit your widget and select a data bucket to connect to
- Configure which data series to display (identified by series keys)

Widgets automatically update in real-time when new data arrives in their connected data bucket.

---

# Data Buckets

A **Data Bucket** is a container for storing data that is visualized dashboard widgets.

### Key Features
- **Three Bucket Types** - Timestamp Key, String Key, or Integer Key with series values
- **Multi-Series Support** - Multiple data series per record
- **Real-Time Updates** - WebSocket connections for instant widget updates
- **High Performance** - Optimized for high-throughput data ingestion
- **Minified Format** - Bandwidth-efficient data transmission

## Bucket Types

### Timestamp Key + Series Values (TSV)
Records are indexed by timestamp. Each record contains a timestamp key and multiple series values.

**Use cases:** Metrics over time, sensor readings, monitoring data

**TSV keys:** You can use unix timestamps in milliseconds or ISO 8601 timestamp strings. The examples on this page use unix millisecond timestamps.

**Data structure:**
```json
{
  "k": 1760954400000,
  "d": [
    {"sk": 1, "v": 25.5},
    {"sk": 2, "v": 23.1}
  ]
}
```

- `k` - Timestamp key (unix timestamp in milliseconds)
- `d` - Array of series values
- `sk` - Series key (integer identifier)
- `v` - Numeric value (float)

### String Key + Series Values (KV)
Records are indexed by string. Each record contains a string key and multiple series values.

**Use cases:** Configuration data, state storage, categorical metrics

**Data structure:**
```json
{
  "k": "2025",
  "d": [
    {"sk": 1, "v": 45.2},
    {"sk": 2, "v": 52.1}
  ]
}
```

- `k` - String key
- `d` - Array of series values
- `sk` - Series key (integer identifier)
- `v` - Numeric value (float)

### Integer Key + Series Values (IV)
Records are indexed by integer key. Each record contains an integer key and multiple series values.

**Use cases:** Ordered categorical ranges, histogram buckets, ranked data, numeric lookup tables

**Data structure:**
```json
{
  "k": 42,
  "d": [
    {"sk": 1, "v": 45.2},
    {"sk": 2, "v": 52.1}
  ]
}
```

- `k` - Integer key
- `d` - Array of series values
- `sk` - Series key (integer identifier)
- `v` - Numeric value (float)

## Bucket Scope
Data buckets are scoped to a specific dashboard. When you create a bucket, it belongs to one dashboard and can only be accessed by widgets on that dashboard.

## Data Retention
Configure how many records are retained in your buckets:
- **Default retention** - Records are kept indefinitely
- **Custom retention** - Set maximum number of records to retain (e.g., keep latest 1,000 records)
- **Automatic purge** - When the record limit is exceeded, oldest records are automatically removed

Retention settings are configured per dashboard and apply to all buckets within that dashboard.

## API Write Data

### Example 1: Write Single Record (Timestamp Key)
Creating one record with a timestamp key:
```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -d '[
    {
      "key": 1760954400000,
      "data": [
        {"series_key": 1, "value": 25.5},
        {"series_key": 2, "value": 23.1}
      ]
    }
  ]'
```

Examples below use unix millisecond timestamps. ISO 8601 timestamp strings are also accepted for TSV writes.

### Example 2: Write Single Record (Timestamp Key as ISO 8601 String)
Using an ISO 8601 timestamp string for the same TSV write:
```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -d '[
    {
      "key": "2025-10-20T10:00:00Z",
      "data": [
        {"series_key": 1, "value": 25.5},
        {"series_key": 2, "value": 23.1}
      ]
    }
  ]'
```

### Write Multiple Records (Timestamp Keys)
Creating multiple records with timestamp keys in one request:
```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -d '[
    {
      "key": 1760954400000,
      "data": [
        {"series_key": 1, "value": 25.5},
        {"series_key": 2, "value": 23.1}
      ]
    },
    {
      "key": 1760954460000,
      "data": [
        {"series_key": 1, "value": 25.7},
        {"series_key": 2, "value": 23.3}
      ]
    }
  ]'
```

### Write Single Record (String Key)
Creating one record with a string key:
```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -d '[
    {
      "key": "2024",
      "data": [
        {"series_key": 1, "value": 45.2},
        {"series_key": 2, "value": 52.1}
      ]
    }
  ]'
```

### Write Multiple Records (String Keys)
Creating multiple records in one request:
```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -d '[
    {
      "key": "2024",
      "data": [
        {"series_key": 1, "value": 45.2},
        {"series_key": 2, "value": 52.1}
      ]
    },
    {
      "key": "2025",
      "data": [
        {"series_key": 1, "value": 78.5}
      ]
    }
  ]'
```

### Write Multiple Records (Integer Keys)
Creating multiple records with integer keys in one request:
```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -d '[
    {
      "key": 1,
      "data": [
        {"series_key": 1, "value": 45.2},
        {"series_key": 2, "value": 52.1}
      ]
    },
    {
      "key": 2,
      "data": [
        {"series_key": 1, "value": 78.5}
      ]
    }
  ]'
```

### How Data Records Insertion Works

#### Timestamp Key + Series Values (TSV) Buckets
When you insert records into TSV buckets:
- **Automatic sorting**: Records are merged into chart data in continuous descending order (newest first)
- **Upsert behavior**: Writing to an existing timestamp replaces all series values for that timestamp
- **Historical data**: Adding records with timestamps in the past is computationally heavy at scale
- **Best practice**: Send unix millisecond timestamps in chronological order and avoid backdating records when possible

#### String Key + Series Values (KV) Buckets
When you insert records into KV buckets:
- **Preserved order**: Records are appended in the exact order you submit them
- **No automatic sorting**: Dashgrid intentionally preserves your submission order
- **Upsert behavior**: Writing to an existing key replaces all series values for that key
- **Best practice**: Submit records in the order you want them displayed

#### Integer Key + Series Values (IV) Buckets
When you insert records into IV buckets:
- **Integer keys**: Each record key must be an integer
- **Upsert behavior**: Writing to an existing integer key replaces all series values for that key
- **Range queries supported**: You can query integer key ranges with `from` and `to`
- **Best practice**: Use integer keys for ordered numeric buckets or ranked ranges

**Important**: For all bucket types, Dashgrid does NOT merge or append series values - it performs a complete replacement of the record.

### Example:
**Existing record:**
```json
{
  "k": 1737280800000,
  "d": [
    {"sk": 1, "v": 100},
    {"sk": 2, "v": 200}
  ]
}
```

**Writing new data:**
```json
[
  {
    "k": 1737280800000,
    "d": [
      {"sk": 1, "v": 150}
    ]
  }
]
```

**Result:** The record is completely replaced. Series 2 is gone, and series 1 now has value 150.

### Empty Data Arrays:
You can send an empty data array to clear all series for a specific key:
```json
[
  {
    "k": 1737280800000,
    "d": []
  }
]
```

This will create or update the record with no data points, effectively clearing all series data for that key while keeping the record itself.

### API Reference
**Endpoint:** `POST https://data.dashgrid.com/api/buckets/{BUCKET_ID}`

**Authentication:** `X-API-Key: {YOUR_API_KEY}` header

**Field Specifications:**
- **key**: For TSV buckets, use either a unix timestamp in milliseconds or an ISO 8601 timestamp string. KV buckets use strings, and IV buckets use integers.
- **data**: Array of series values (0-10 items per record)
- **series_key**: Integer between 1 and 10, must be unique within the record
- **value**: Number (integer or float), **cannot be null**

**Minified Format:** You can use shortened field names (`k`, `d`, `sk`, `v`) instead of full names for bandwidth efficiency. Both formats are accepted.

## API Read Data

### Get Multiple Records
```bash
curl https://data.dashgrid.com/api/buckets/{bid}/records?limit=10&offset=0 \
  -H "X-API-Key: {YOUR_API_KEY}"
```

Response (flattened format with `k` key, `ca` created_at, and the series keys as string numbers):
```json
{
  "records": [
    {
      "k": 1760954460000,
      "ca": "2025-10-20T10:01:05Z",
      "1": 25.7,
      "2": 23.3
    },
    {
      "k": 1760954400000,
      "ca": "2025-10-20T10:00:05Z",
      "1": 25.5,
      "2": 23.1
    }
  ]
}
```

Query parameters:
- `limit` (integer, optional): Number of records to return (default: 100, max: 1000)
- `offset` (integer, optional): Number of records to skip (default: 0)
- `from` / `to`: Supported for TSV timestamp ranges and IV integer-key ranges. For TSV, you can use unix milliseconds or ISO 8601 timestamp strings.

### Get One Record
Response (flattened format with `k` key, `ca` created_at, and the series keys as string numbers):
```bash
curl https://data.dashgrid.com/api/buckets/{bid}/records/{record_key} \
  -H "X-API-Key: {YOUR_API_KEY}"
```

Response:
```json
{
  "records": [
    {
      "k": 1760954400000,
      "ca": "2025-10-20T10:00:05Z",
      "1": 25.5,
      "2": 23.1
    }
  ]
}
```

## API Delete Data

### Delete Individual Record in KV or IV Bucket
Deletes an individual record from a **KV (String Key)** or **IV (Integer Key)** bucket:

```bash
curl -X DELETE https://data.dashgrid.com/api/buckets/{BUCKET_ID}/records/{KEY} \
  -H "X-API-Key: {YOUR_API_KEY}"
```

**⚠️ Important:** 
- This works for KV buckets (string keys) and IV buckets (integer keys).
- For buckets with timestamp keys (TSV, timestamp), individual deletion is not supported because it creates gaps in the time-series and prevents proper data retention window management.

### Clear Individual Record Values in TSV Bucket (Timestamp Keys)
Writes an empty data array to clear values while preserving the timestamp:

```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "Content-Type: application/json" \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -d '[
    {
      "key": 1737280800000,
      "data": []
    }
  ]'
```

## API Purge Data
Deletes all records in a bucket. This can be triggered via API when you need to clear a bucket and start fresh.
```bash
curl -X DELETE https://data.dashgrid.com/api/buckets/{BUCKET_ID}/purge \
  -H "X-API-Key: {YOUR_API_KEY}"
```

⚠️ **Important:**
- all records in the bucket will be permanently deleted
- data counter will be reset for this bucket
- deleting a bucket in the Dashgrid app, also deteletes all data records

## API Error Responses

### 401 Unauthorized
```json
{"error": "API key required"}
```
Missing or invalid `X-API-Key` header.

### 403 Forbidden
```json
{"error": "permission denied"}
```
API key doesn't have access to this bucket's dashboard.

### 404 Not Found
```json
{"error": "bucket not found"}
```
Bucket ID doesn't exist.

### 400 Bad Request
```json
{"error": "validation error: d.sk must be integer between 1 and 10"}
```
Invalid request data. Common validation errors:
- Key format invalid for bucket type
- Data array has more than 10 items
- Series key not between 1-10
- Duplicate series keys in same record
- Null values in data points

---

# API Keys

API Keys provide programmatic access to write, update, and delete data in your Data Buckets.

### Key Features
- **Dashboard-Scoped Access** - Each key grants access to all buckets within a specific dashboard
- **Write Operations** - Create, update, and delete records via API
- **Secure Authentication** - Keys use the `X-API-Key` header for authentication
- **Owner/Admin Management** - Only users with Owner or Admin roles can create and manage keys

## Scope and Permissions

API Keys are scoped per dashboard:
- A key grants full access to write, update, and delete operations for all buckets within that dashboard
- Keys cannot access buckets from other dashboards
- Only users with Owner or Admin roles can create, view, or revoke API keys

## Creating API Keys

To create an API key:
1. Navigate to your dashboard
2. Go to the **API Keys** tab
3. Click **Create**
4. Give your key a clear name
5. Select the **Key Type**: Production or Development (for easier management and organization)
6. Copy the key immediately - it will only be shown once

**Important:** Store your API key securely. You cannot retrieve it again after creation.

## Using API Keys

Include your API key in the `X-API-Key` header for all API requests:

```bash
curl -X POST https://data.dashgrid.com/api/buckets/{BUCKET_ID} \
  -H "X-API-Key: {YOUR_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '[{"key": "2025-01-20T10:00:00Z", "data": [{"series_key": 1, "value": 42}]}]'
```

For complete API docs, see Data Buckets API.

## Security Best Practices

- **Never expose keys** in public repositories, frontend code, or client-side applications
- **Use environment variables** to store API keys in your backend services
- **Rotate keys regularly** for production environments
- **Create separate keys** for different services or environments (development, staging, testing, production)
- **Revoke compromised keys** immediately and generate new ones
- **Use clear, descriptive key names** to track which service or device uses each key

## Revoking API Keys

If a key is compromised or no longer needed:
1. Go to the **Keys** tab in your dashboard
2. Select the key in the list, and switch to the Danger tab
3. Follow the instructions to permanently disable the key

---

# Sharing

Dashboards support two separate forms of sharing:

- **Member access** requires a Dashgrid account, authentication, and an
  authorized workspace or dashboard role.
- **Public access** publishes a read-only presentation at the dashboard's
  existing URL. Anyone can open it without signing in.

## Roles and permissions

### Viewer

View the dashboard and its widgets. Viewers cannot edit the dashboard, manage
data or keys, change sharing, or publish it.

### Editor

Includes Viewer access and can edit widgets, layout, dashboard settings, data
buckets, and API keys. Editors cannot manage members or publish the dashboard.

### Admin

Includes Editor access, can manage the workspace and assign Viewer, Editor, or
Admin roles, and can publish or unpublish dashboards. Admins cannot grant Owner
or delete the dashboard/workspace.

### Owner

Has complete administrative access, including assigning Owner, publishing or
unpublishing, and deleting dashboards or workspaces.

A direct dashboard role overrides the workspace role for that dashboard, except
that a workspace Owner always remains Owner. A person outside the workspace can
only receive a direct dashboard Viewer role.

## Share with members

Admins and Owners can open the dashboard's **Access** tab and select **Invite**
to invite someone by email. Pending invitations expire after 14 days. Existing
members and invitations appear in the Sharing list, where authorized managers
can inspect or change their access.

The overview places **State** directly after User and reports each access item
as **Enabled**, **Disabled**, or **Invalid** when its stored state does not match
the expected contract. **Created** records when the access item was created;
**Joined** records when membership became effective. Pending invitations have
no Joined date. Invitation expiry remains enforced and visible in invitation
details, but is not a separate overview column.

Member access remains private: every page and data request requires both a
signed-in account and current authorization.

## Publish a dashboard

The Sharing list always contains one **Public** item. It represents the
dashboard's publication state and is not another member or a separately managed
link. Its editor uses the same modal structure and controls as the other Access
editors. An invalid publication state is shown explicitly and cannot be changed
as though it were Disabled or Enabled.

Admins and Owners can:

1. Open **Public** in the Access tab.
2. In **Public Access**, copy the dashboard title from its read-only field as
   needed and switch **State** from **Disabled** to **Enabled**.
3. Review the canonical URL preview and exposure warning. URL help points to
   Dashboard settings for URL management. The preview does not publish the
   dashboard.
4. Type the dashboard title exactly.
5. Enter their current account password.
6. Select **Make dashboard public**.

The dashboard becomes public only after the server rechecks the current role,
title, password, canonical path, and dashboard state. Switching the draft alone
does not publish anything.

Published pages use the same canonical paths as the private application:

```text
Dashboard: /{workspace}/{dashboard}
Widget:    /{workspace}/{dashboard}/{widget_ref}
```

There is no extra `/widgets/` segment. Authorized members still receive the
full private application at these URLs. Anonymous visitors and signed-in
non-members receive only the sanitized public presentation.

## Public data boundary

A published dashboard exposes its configured charts and the complete permitted
history available to those widgets, with a maximum of 1000 records per request.
Public widget details can show the chart, status, update indicator, and enabled
history controls.

The public presentation excludes records tables, bucket names, bucket IDs,
bucket-information panels, API keys, editing controls, presence, and private
application/user state. Public charts poll through Dashgrid and never receive a
BucketStore credential or open a public WebSocket.

Published pages may be indexed, shared, copied, cached, or retained by others.
Only publish data that is appropriate for unrestricted public access.

## Make a dashboard private

Open the **Public** item, switch **State** to **Disabled**, and select **Make
dashboard private**. This exposure-reducing action requires confirmation but no
password or title re-entry.

New public page and data requests stop immediately after the server confirms
the change. Making a dashboard private cannot retract information that someone
already viewed, copied, indexed, or cached. Authorized members continue to use
the private dashboard at its canonical URL.
