---
category: reference
tags: [architecture, admin, permissions, multi-tenancy]
last_updated: 2026-03-17
confidence: high
---

# Admin Panel Re-enablement

Analysis of which Otterwiki admin panels can be re-enabled in robot.wtf's multi-tenant platform, now that per-wiki SQLite databases are deployed.

## Background

Otterwiki has 8 admin panels. Three are gated by `PLATFORM_MODE` (added in `feat/P2-8-admin-panel-hiding`). Per-wiki databases landed on 2026-03-17, meaning each wiki's `preferences`, `drafts`, `user`, and `cache` tables are now isolated.

## Upstream bug found

`handle_permissions_and_registration` in `otterwiki/preferences.py` is missing the `has_permission("ADMIN")` guard that every other admin handler has. Fix submitted as `fix/permissions-admin-guard` — PR pending to redimp. Red/green verified.

## Panel Status

### Already working (no changes needed)

| Panel | Route | Notes |
|-------|-------|-------|
| Application Preferences | `/-/admin` | SITE_NAME, SITE_DESCRIPTION, SITE_LOGO, etc. SERVER_NAME hidden in PLATFORM_MODE. |
| Sidebar Preferences | `/-/admin/sidebar_preferences` | Pure preferences. Works. |
| Content and Editing | `/-/admin/content_and_editing` | COMMIT_MESSAGE, WIKILINK_STYLE, etc. Works. |
| Repository Management | `/-/admin/repository_management` | ✅ **Gated in PLATFORM_MODE** (2026-03-17). Route, nav link, pull webhook, and auto-push/pull all disabled. SSH key storage and outbound connections blocked. May re-enable with sandboxing if demand emerges. |

### Phase 1: Permissions panel ✅ DEPLOYED (2026-03-17)

`READ_ACCESS` / `WRITE_ACCESS` / `ATTACHMENT_ACCESS` configurable via Otterwiki admin. Resolver enforces by intersecting with platform ACL. Registration fields hidden in PLATFORM_MODE. `READ_ACCESS` replaces `is_public` as sole source of truth for anonymous access.

### Phase 2: User Management (consolidated)

**Key decision (2026-03-17): Remove the "Collaborators" tab from the platform dashboard entirely. All user/access management happens in Otterwiki's User Management panel.** This consolidates three layers (platform ACL, wiki preferences, per-wiki roster) into two places the wiki owner actually sees: the Permissions panel and the User Management panel.

**Routes:** `/-/admin/user_management`, `/-/user/<uid>`

#### Design: Explicit roster, not activity tracking

The per-wiki `user` table is an **explicit roster managed by wiki admins**, not an activity log. Users only exist there because an admin added them.

**Admin workflow:**
1. Admin opens User Management panel in Otterwiki's admin
2. Enters a DID handle (e.g., `@alice.bsky.social`) to add a user
3. Sets per-user flags: role (viewer/editor/admin), `is_approved`
4. User can now access the wiki at whatever level their flags grant

**Wiki admins can create other wiki admins.**

#### Consolidating platform ACL into User Management

Currently, the platform dashboard has a "Collaborators" tab that manages the `acls` table in robot.db (granting owner/editor/viewer roles). Phase 2 moves this into Otterwiki's User Management panel:

- **Remove the Collaborators tab** from the dashboard (`wiki_settings.html`)
- **Remove the Collaborators API endpoints** from the management API (or deprecate)
- **User Management becomes the single place** to manage who can access the wiki and at what level
- **The per-wiki `user` table replaces the platform `acls` table** as the source of truth for per-wiki access
- **The resolver reads from the per-wiki user table** instead of (or in addition to) the platform ACL table
- **The platform ACL ceiling is enforced implicitly:** the wiki owner's own role (from the `wikis` table) is the ceiling. The owner can grant up to their own level but not beyond.

#### Migration path

1. On Phase 2 deploy, migrate existing `acls` entries into per-wiki `user` tables
2. Remove Collaborators tab from dashboard
3. Remove or deprecate ACL management API endpoints
4. Resolver reads permissions from per-wiki user table

#### `email` field decision — deferred

Otterwiki's User model keys on `email`. Two options:
- **Appropriate `email` for DID handles** — quick, minimal schema divergence, but blocks future email notifications
- **Add a `handle` column** — cleaner, but more fork divergence

Decision deferred. Future notification mechanism (email vs. BlueSky DMs) affects this choice.

#### Permission flow with APPROVED level

Once Phase 2 lands, the APPROVED access level becomes fully functional:
1. Wiki owner sets `READ_ACCESS=APPROVED` in Permissions panel
2. Resolver checks per-wiki `user` table for the authenticated user's handle
3. If found and `is_approved=True`: READ permission granted
4. If not found or not approved: READ stripped

#### Required changes

**Otterwiki fork:**
1. Re-enable User Management + User Edit panels in PLATFORM_MODE
2. Customize add-user form: accept DID handle, hide password fields
3. Override `ProxyHeaderAuth.get_all_user()` to query per-wiki user table
4. Map user flags to roles (viewer/editor/admin) for display

**robot.wtf:**
1. Remove Collaborators tab from `wiki_settings.html`
2. Remove or deprecate ACL management endpoints in `management/routes.py`
3. Extend `_apply_wiki_access_restrictions()` to query per-wiki user table for APPROVED level and per-user role
4. Migration script: copy `acls` entries to per-wiki `user` tables
5. Resolver reads per-wiki user table for permission computation

### Keep disabled: Mail Preferences

Per-wiki SMTP config is a security/spam risk. Notification mechanism (email vs. BlueSky DMs) is an open question.

## Implementation Order

1. ~~Permissions panel~~ ✅ Deployed
2. ~~Hide SERVER_NAME~~ ✅ Deployed
3. ~~Remove is_public toggle~~ ✅ Deployed
4. ~~User Management~~ ✅ Deployed (2026-03-17) — platform ACL removed entirely, per-wiki user table is sole permission source, role UI (admin/editor/viewer) deployed, APPROVED access level functional, dashboard collapsed to single-page card
5. ~~Repository Management~~ ✅ Gated in PLATFORM_MODE (2026-03-17) — route, nav, webhook, auto-push/pull all disabled

### Remaining disabled
- **Mail Preferences** — per-wiki SMTP is a security/spam risk. Notification mechanism (email vs. BlueSky DMs) is an open question.
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