Ozone Moderation Admin Interface

repository·main·Indexed 19 days ago

https://github.com/bluesky-social/ozone

A labeling and moderation service for the AT Protocol (atproto) ecosystem, including a backend service and a Next.js web application. Ozone provides tools for administrators to manage content and accounts through moderation reports, labeling, takedowns, and user management. It utilizes the tools.ozone.* Lexicon namespace and supports role-based access control for triage, moderator, and admin roles.

Tokens
8.1K
Snippets
13
Records
37
Agent score
68%

What's inside Ozone

  1. Overview of Ozone labeling service

    main

    Ozone is a labeling service designed for Bluesky and other AT Protocol (atproto) applications. It consists of a backend service and a Next.js web application (Ozone UI) used for moderation tasks. The UI typically requires moderator or administrator privileges.

    Key capabilities include:

    • Moderation Management: Viewing, triaging, escalating, and actioning moderation reports.
    • Content & Account Control: Performing takedowns, suspending content/accounts, and creating or modifying labels.
    • User Management: Viewing invite trees and disabling invite generation.
    • Communication: Sending moderation emails using predefined templates.
    • Investigation: Browsing app.bsky profiles and post threads, including content that has been taken down.
    • Navigation: Quick-action modal accessible via Ctrl-K.
  2. Access control and roles in Ozone moderation

    main

    While general tools.ozone.* lexicons may be accessible to users with an admin token, the tools.ozone.moderation.emitEvent method enforces strict role-based access control. The outcome of an event (and its ability to change a subject's state) depends on the caller's role.

    Defined roles include:

    • triage: Can perform basic functions but cannot take down or label subjects.
    • moderator: Can perform standard moderation actions like labeling or taking down subjects.
    • admin: Has full access to all moderation actions.
  3. Core Concepts in Ozone

    main

    Understanding the relationship between Subjects, Events, Reports, and Queues is essential for using Ozone:

    • Subjects: The target of an action. This can be an entire account or an individual piece of content (e.g., a post). Note that an account profile is a distinct subject from the account itself.
    • Events: A record of something happening. Every event has a subject and a creator. Events include reports, actions (like adding labels), and workflow helpers (like escalation).
    • Reports: A specific type of event, usually created by app users. A special type is an Appeal, where an account reports itself following a moderation intervention.
    • Queues: Dynamic views of subjects based on state:
      • Unreviewed: Reported subjects with no resolution.
      • Escalated: Subjects flagged for additional team consideration.
      • Resolved: Subjects that have been reviewed and either acknowledged or acted upon.
  4. Core concepts of the Ozone moderation system

    main

    Ozone is a labeling and moderation system for the atproto network, utilizing the tools.ozone.* Lexicon namespace. The system is built around four primary abstractions:

    • Subjects: The target of moderation. This can be an entire account (referenced by a DID) or specific content (referenced by an AT-URI and optionally a CID). Note that an account profile record is considered a distinct subject from the account itself.
    • Events: Records of actions taken within the system. Every event includes a subject (the target) and a creator (the account performing the action). Events can update a subject's state. Common events include reports, actions (like adding labels), escalations, and acknowledgements.
    • Reports: A specific type of event, typically created by app users. A special subtype is an Appeal, which occurs when an account reports itself in response to a moderation decision.
    • Queues: Dynamic lists of subjects in specific states, generated by querying the tools.ozone.moderation.querySubjects API endpoint.
  5. Distinguish between account-level and content-level events

    main

    When reviewing data, be aware of the distinction between account-level events and content-level events.

    Specifically, "profile records" are a form of content that applies to an entire account but is distinct from the account itself. In certain interfaces, you can use toggle buttons to switch between:

    • action account vs action account's profile
    • all events for account vs all events for account and account's content
  6. Understand Subject State properties

    main

    A subject's current state is the result of all historical events applied to it. Ozone tracks several independent state properties:

    reviewState

    Tracks the lifecycle of a subject being reviewed. Possible values:

    • reviewOpen: The default state for subjects with incoming reports. Reports are displayed in reverse chronological order.
    • reviewEscalated: The subject has been flagged for review by higher-tier moderators.
    • reviewClosed: The moderator has acknowledged the reports (with or without action). New reports will move the subject back to reviewOpen.
    • reviewNone: Used for subjects with metadata (tags/comments) that do not require human review.

    muted (Boolean)

    Indicates if a subject is temporarily excluded from moderation queues to prevent clutter (e.g., from frequent re-reporting). Muted subjects only reappear after a selected period unless manually unmuted.

    appealed (Boolean)

    Indicates if the author of a subject has appealed a decision. An appeal automatically moves the reviewState to reviewOpen. A moderator must explicitly use the "Resolve Appeal" action to change this.

    takendown (Boolean)

    Indicates if a moderator has temporarily or permanently removed the subject. Temporary suspensions are automatically reversed after a set period.

  7. Quickstart for Ozone Web Interface

    main

    The Ozone web interface is a collaborative tool for moderators to review reports, create labels, and inspect atproto content.

    Logging In

    Users log in using an atproto account with their handle and password. (Note: OAuth support is planned for future updates).

    Basic Navigation

    • Queues: Upon login, you will see a queue of un-reviewed reports. Other queues include escalated and resolved reports.
    • Take Action Panel: Click the "Take Action" link in the upper-right to open a modal for reviewing a single subject. This panel allows you to view historical events, add/remove labels, and add team-private comments.
    • Ctrl Panel: Press Ctrl-K or click the link in the left bar to open a quick search panel. You can paste a handle, bsky.app URL, or other identifier to quickly access reports or profile metadata.
    • Account Profile View: Clicking a handle or username in the Take Action panel opens the Ozone account profile page, showing metadata like public DID PLC history, recent posts, and report history.
  8. Set up local integrated development environment

    main

    To develop Ozone locally, you must connect it to a running PDS (Personal Data Server) instance. The recommended approach is to use the dev-env from the atproto repository.

    1. Start the atproto dev-env: In your atproto repository, run:
      yarn workspace @atproto/dev-env start
    2. **Identify the Ozone service DID**: Look in the `dev-env` startup logs for a line indicating the Ozone service DID:
       `🗼 Ozone service DID did:plc:xxxxx`
    3. **Configure Ozone**: Create a `.env.local` file in the Ozone project root and add the DID:
       ```env
       NEXT_PUBLIC_OZONE_SERVICE_DID=did:plc:xxxxx
    1. Start Ozone: Run the development server:
      yarn dev
    5. **Login**: Navigate to `http://localhost:3000`. Use the "Credentials" tab with the following test accounts:
    
    | Role | Account Handle | Password | Service URL |
    | :--- | :--- | :--- | :--- |
    | Mod | `mod.test` | `mod-pass` | `http://localhost:2583` |
    | Triage | `triage.test` | `triage-pass` | `http://localhost:2583` |
    | Admin | `admin-mod.test` | `admin-mod-pass` | `http://localhost:2583` |
    

    Step 1: Start atproto dev-env

    yarn workspace @atproto/dev-env start

    Step 3: Configure Ozone

    echo "NEXT_PUBLIC_OZONE_SERVICE_DID=did:plc:xxxxx" > .env.local

    Step 4: Start Ozone

    yarn dev

  9. Verify Ozone installation

    main

    After starting the service, verify it is running correctly using the following methods:

    1. Check Service Status: Use systemctl and docker ps to ensure containers (caddy, ozone, postgres, watchtower) are active.
    2. Healthcheck Endpoint: Request the _health endpoint via curl.
    3. WebSocket Stream: Test the label subscription WebSocket using wsdump.
    4. Web UI: Visit https://<your-domain> in a browser.
    # Check health
    curl https://ozone.EXAMPLE.COM/xrpc/_health
    
    # Check WebSocket stream
    wsdump "wss://ozone.EXAMPLE.COM/xrpc/com.atproto.label.subscribeLabels?cursor=0"
  10. Self-host Ozone via Docker

    main

    To run your own moderation service, you can self-host Ozone. The recommended approach is to use a Dockerized setup that hosts both the Ozone UI and the backend service together.

    Detailed instructions for deployment can be found in the HOSTING.md file.

  11. Managing Email and Templates

    main

    The Account View includes an Email tab for communicating with accounts. Emails are sent via request to the account's PDS.

    Email Templates

    Templates are specific to the Ozone backend instance.

    • Variables: Use double-brackets for auto-substitution, e.g., {{handle}}.
    • Placeholders: Use triple-quotes for manual placeholders, e.g., ### DESCRIPTION OF IMAGE ###. The email will not be sent until these placeholders are replaced or an override is toggled.
    • Privacy: The template name and any additional comments are saved in the event log for the team, but the recipient only sees the subject and body of the email.

    Workflow

    1. Navigate to the Email tab in the Account View.
    2. Select a template or write free-form text.
    3. Replace any manual placeholders if necessary.
    4. Send the email (Note: Emails are not sent automatically as a result of other actions; they must be sent manually).
  12. Install Ozone on Ubuntu 22.04/24.04

    main

    Follow these steps to install Ozone using Docker on Ubuntu:

    1. Open Linux Firewall

    If using ufw, allow HTTP and HTTPS traffic:

    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp

    2. Install Docker

    Uninstall old versions, set up the repository, and install Docker Engine and Docker Compose plugin as per the official Docker instructions for Ubuntu.

    3. Set up Directories

    Create the necessary directory structure for Ozone and its dependencies:

    sudo mkdir /ozone
    sudo mkdir /ozone/postgres
    sudo mkdir --parents /ozone/caddy/data
    sudo mkdir --parents /ozone/caddy/etc/caddy

    4. Configure Caddy

    Create a Caddyfile to handle TLS and reverse proxying. Replace ozone.example.com with your domain and ozone@example.com with your email.

    cat <<CADDYFILE | sudo tee /ozone/caddy/etc/caddy/Caddyfile
    ozone.example.com {
      tls ozone@example.com
      reverse_proxy http://localhost:3000
    }
    CADDYFILE

    5. Configure Postgres and Ozone Environment Variables

    Create /ozone/postgres.env with your POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB.

    Then, create /ozone/ozone.env. You must provide values for:

    • OZONE_HOSTNAME
    • OZONE_SERVICE_ACCOUNT_HANDLE
    • OZONE_SERVER_DID (resolved via atproto identity API)
    • OZONE_ADMIN_PASSWORD
    • OZONE_SIGNING_KEY_HEX (a secp256k1 private key in hex format)
    • OZONE_DB_POSTGRES_URL (using the credentials from your postgres.env)

    6. Deploy with Docker Compose and Systemd

    Download the compose.yaml file and create a systemd service to manage the containers.

    # Download compose file
    curl https://raw.githubusercontent.com/bluesky-social/ozone/main/service/compose.yaml | sudo tee /ozone/compose.yaml
    
    # Create systemd service
    cat <<SYSTEMD_UNIT_FILE | sudo tee /etc/systemd/system/ozone.service
    [Unit]
    Description=Bluesky Ozone Service
    Documentation=https://github.com/bluesky-social/ozone
    Requires=docker.service
    After=docker.service
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    WorkingDirectory=/ozone
    ExecStart=/usr/bin/docker compose --file /ozone/compose.yaml --profile daemon up --detach
    ExecStop=/usr/bin/docker compose --file /ozone/compose.yaml --profile daemon down
    
    [Install]
    WantedBy=default.target
    SYSTEMD_UNIT_FILE
    
    # Start service
    sudo systemctl daemon-reload
    sudo systemctl enable ozone
    sudo systemctl start ozone