---
category: spec
tags:
  - design
  - dashboard
  - permissions
  - ux
last_updated: 2026-03-18
confidence: high
---

# Dashboard Visibility Toggle

## Problem

Wiki permissions (READ_ACCESS, WRITE_ACCESS, ATTACHMENT_ACCESS) are managed in the otterwiki admin panel at `/-/admin/permissions_and_registration`. This is buried and unfamiliar to new users. The most common permission change — controlling who can *read* the wiki — should be accessible from the platform dashboard.

The platform previously had an `is_public` flag in the `wikis` table that overlaid the per-wiki permissions, causing confusion when the two disagreed. That flag is now inert. This spec replaces it with a dashboard control that writes directly to the per-wiki DB — single source of truth, no overlay.

## Design

Add a **visibility selector** to the wiki settings card on the platform dashboard (`/app/`). Three states:

| Label | READ_ACCESS value | Meaning |
|---|---|---|
| **Private** | `APPROVED` | Only the owner and explicitly approved users can read |
| **Logged in** | `REGISTERED` | Any authenticated platform user can read |
| **Public** | `ANONYMOUS` | Anyone on the internet can read |

Default for new wikis: **Private** (APPROVED).

The selector controls `READ_ACCESS` only. WRITE_ACCESS and ATTACHMENT_ACCESS remain independent, managed via the otterwiki admin panel. This matches common wiki patterns (e.g., public read + restricted write).

## Mechanism

### Read

Open a raw `sqlite3` connection to `{wiki_dir}/wiki.db`:

```sql
SELECT value FROM preferences WHERE name = 'READ_ACCESS'
```

Map the value to the three-state selector. If the value is missing or unrecognized, default to "Private."

### Write

On selector change:

```sql
INSERT OR REPLACE INTO preferences (name, value) VALUES ('READ_ACCESS', ?)
```

Before writing, call `_init_wiki_db()` to ensure the DB and `preferences` table exist. This is already idempotent.

### Staleness

After a direct write to `wiki.db`, otterwiki workers with that wiki already loaded won't see the change until their next request triggers `_swap_database()``update_app_config()`. This is pre-existing behavior — the same staleness applies to changes made via the otterwiki admin panel. No new issue.

## Implementation

### Files to change

- **`app/api_server.py`**: Add a helper to read `READ_ACCESS` from a wiki's DB. Add a POST handler to update it. The dashboard GET already loads wiki data — extend it to include current visibility state.
- **`app/management/templates/wiki_settings.html`**: Add a visibility selector card (three radio buttons or a segmented control) above the existing MCP section.
- **`app/resolver.py`**: No changes needed. The resolver already reads `READ_ACCESS` from the per-wiki DB on each request.

### UI placement

The visibility selector goes in the wiki settings card on the dashboard, prominently placed (above MCP details). Label: "Visibility" with the three options and a one-line explanation of each.

### What NOT to do

- Do NOT add a column to the platform `wikis` table. The selector reads and writes `wiki.db` directly.
- Do NOT import otterwiki models. Use raw `sqlite3`, same as `_init_wiki_db()`.
- Do NOT change WRITE_ACCESS or ATTACHMENT_ACCESS from this control. Those are independent.

## Edge cases

- **Visibility changed via otterwiki admin panel**: The dashboard will reflect the current DB value on next load. No conflict — single source of truth.
- **wiki.db doesn't exist yet**: Call `_init_wiki_db()` before reading. It's idempotent.
- **Unrecognized READ_ACCESS value**: Display as "Private" (safest default).

## Relationship to otterwiki admin panel

The dashboard toggle and the otterwiki admin panel write the same `preferences` row. They are two UIs for the same field. The dashboard is simpler (one control for the most common operation); the admin panel is comprehensive (all three access controls, all four levels including ADMIN).

The [[Administration]] default wiki page directs users to the admin panel for full permission control. The dashboard toggle is a convenience shortcut.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9