priv/repo/migrations/20260822132511_create_forum_tables.exs

main at 58e6347eeb72 · 3 KB

defmodule OpenAgents.Repo.Migrations.CreateForumTables do
  use Ecto.Migration

  def change do
    create table(:forum_forums, primary_key: false) do
      add :id, :uuid, primary_key: true

      add :slug, :string, null: false
      add :title, :string, null: false
      add :description, :text
      add :visibility, :string, null: false, default: "public"
      add :discoverability, :string, null: false, default: "listed"
      add :locked, :boolean, null: false, default: false
      add :topic_count, :bigint, null: false, default: 0
      add :post_count, :bigint, null: false, default: 0

      timestamps(type: :utc_datetime_usec)
    end

    create unique_index(:forum_forums, [:slug])

    create constraint(:forum_forums, :forum_forums_visibility_check,
             check: "visibility IN ('public', 'unlisted', 'private')"
           )

    create table(:forum_topics, primary_key: false) do
      add :id, :uuid, primary_key: true
      add :forum_id, references(:forum_forums, type: :uuid, on_delete: :restrict), null: false

      add :idempotency_key, :string, null: false
      add :slug, :string, null: false
      add :title, :string, null: false

      # Legacy actor identity. Posts keep the identity they were written
      # under; a linked account is resolved through forum_actor_links.
      add :actor_ref, :string, null: false
      add :actor_display_name, :string, null: false
      add :actor_slug, :string
      add :actor_is_agent, :boolean, null: false, default: true

      add :state, :string, null: false, default: "open"
      add :pin_state, :string, null: false, default: "normal"
      add :post_count, :bigint, null: false, default: 1
      add :first_post_id, :uuid
      add :latest_post_id, :uuid
      add :archived_at, :utc_datetime_usec

      timestamps(type: :utc_datetime_usec, inserted_at: :created_at)
    end

    create unique_index(:forum_topics, [:idempotency_key])
    create unique_index(:forum_topics, [:forum_id, :slug])

    create index(:forum_topics, [:forum_id, :pin_state, :created_at],
             where: "archived_at IS NULL"
           )

    create index(:forum_topics, [:actor_ref])

    create constraint(:forum_topics, :forum_topics_state_check,
             check: "state IN ('open', 'closed')"
           )

    create constraint(:forum_topics, :forum_topics_pin_state_check,
             check: "pin_state IN ('normal', 'pinned')"
           )

    create table(:forum_posts, primary_key: false) do
      add :id, :uuid, primary_key: true
      add :topic_id, references(:forum_topics, type: :uuid, on_delete: :restrict), null: false

      add :idempotency_key, :string, null: false
      add :post_number, :bigint, null: false
      add :body_text, :text, null: false
      add :content_kind, :string, null: false, default: "markdown"

      add :actor_ref, :string, null: false
      add :actor_display_name, :string, null: false
      add :actor_slug, :string
      add :actor_is_agent, :boolean, null: false, default: true

      add :parent_post_id,
          references(:forum_posts, type: :uuid, on_delete: :nilify_all)

      add :quote_post_id, :uuid

      add :state, :string, null: false, default: "visible"
      add :archived_at, :utc_datetime_usec

      timestamps(type: :utc_datetime_usec, inserted_at: :created_at)
    end

    create unique_index(:forum_posts, [:idempotency_key])
    create unique_index(:forum_posts, [:topic_id, :post_number])

    create index(:forum_posts, [:topic_id, :post_number],
             where: "archived_at IS NULL",
             name: :forum_posts_topic_number_visible_index
           )

    create index(:forum_posts, [:actor_ref])

    create constraint(:forum_posts, :forum_posts_state_check,
             check: "state IN ('visible', 'hidden', 'deleted')"
           )

    execute("SELECT 1", "SELECT 1")
  end
end