Properties
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.

Panel Status

Already working (no changes needed)

Panel Route Notes
Application Preferences /-/admin SITE_NAME, SITE_DESCRIPTION, SITE_LOGO, etc. All stored in per-wiki preferences. update_app_config() reloads from the right DB. app_renderer sees changes via live reference to app.config.
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 GIT_WEB_SERVER, remote push/pull. Works but git remote push/pull + SSH key storage is a security concern — wiki owners storing arbitrary SSH keys that the platform executes. Consider gating push/pull behind a platform-level flag.

Flag: SERVER_NAME in Application Preferences could break Flask's URL generation in multi-tenant mode. Should be hidden or read-only in PLATFORM_MODE.

Re-enable now: Permissions panel (medium effort)

Route: /-/admin/permissions_and_registration

What it controls:

  • READ_ACCESS — ANONYMOUS / REGISTERED / APPROVED
  • WRITE_ACCESS — same options
  • ATTACHMENT_ACCESS — same options
  • Registration settings (DISABLE_REGISTRATION, AUTO_APPROVAL, etc.) — not applicable to ATProto auth

Current state: ProxyHeaderAuth.has_permission() ignores these entirely — it trusts proxy headers from the resolver.

Proposed integration: The resolver reads these preferences after _swap_database() and intersects them with platform ACL permissions before injecting proxy headers.

  • Platform ACL grants the ceiling (owner/editor/viewer → READ, WRITE, UPLOAD, ADMIN)
  • Per-wiki READ_ACCESS/WRITE_ACCESS restrict further (e.g., if WRITE_ACCESS=APPROVED and user isn't approved, strip WRITE from headers)
  • Wiki owner can restrict but never escalate beyond what the platform ACL grants

Changes needed:

  1. otterwiki fork (wikibot-io branch): Modify the permissions_and_registration template to hide registration-related fields when PLATFORM_MODE is true. Remove @platform_mode_disabled decorator from the route.
  2. robot.wtf resolver: After _swap_database() and update_app_config(), read READ_ACCESS/WRITE_ACCESS/ATTACHMENT_ACCESS from app.config. Apply them when computing the x-otterwiki-permissions header — intersect with ACL-granted permissions.

Phase 2: User Management (high effort)

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

Problem: ProxyHeaderAuth creates transient user objects from headers. Nothing persists to the per-wiki DB. get_all_user() returns only [current_user].

Required changes:

  1. User tracking: Resolver upserts a User record into per-wiki DB on each authenticated request (ATProto handle as email field, display name as name, null password_hash)
  2. get_all_user() override: Query per-wiki user table instead of returning [current_user]
  3. Template changes: Hide password/email fields in PLATFORM_MODE; show ATProto handles
  4. ACL integration: Per-user flags (allow_read, allow_write, is_admin) feed into permission computation alongside READ_ACCESS/WRITE_ACCESS

Keep disabled: Mail Preferences

Per-wiki SMTP config is a security/spam risk. If mail is needed, platform provides a shared service.

Implementation Order

  1. Permissions panel — re-enable with resolver integration (this sprint)
  2. Hide SERVER_NAME — quick template fix (opportunistic)
  3. User Management — user tracking + template customization (Phase 2)