defmodule Mv.Repo.Migrations.AddJoinRequests do @moduledoc """ Creates join_requests table for the public join flow (onboarding, double opt-in). Stores join form submissions with status pending_confirmation → submitted (after email confirm). Token stored as hash only; 24h retention for unconfirmed records (cleanup via scheduled job). """ use Ecto.Migration def up do create table(:join_requests, primary_key: false) do add :id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true add :status, :text, null: false, default: "pending_confirmation" add :email, :text, null: false add :first_name, :text add :last_name, :text add :form_data, :map add :schema_version, :integer add :confirmation_token_hash, :text add :confirmation_token_expires_at, :utc_datetime_usec add :confirmation_sent_at, :utc_datetime_usec add :submitted_at, :utc_datetime_usec add :approved_at, :utc_datetime_usec add :rejected_at, :utc_datetime_usec add :reviewed_by_user_id, :uuid add :source, :text add :inserted_at, :utc_datetime_usec, null: false, default: fragment("(now() AT TIME ZONE 'utc')") add :updated_at, :utc_datetime_usec, null: false, default: fragment("(now() AT TIME ZONE 'utc')") end create unique_index(:join_requests, [:confirmation_token_hash], name: "join_requests_confirmation_token_hash_unique", where: "confirmation_token_hash IS NOT NULL" ) create index(:join_requests, [:email]) create index(:join_requests, [:status]) end def down do drop table(:join_requests) end end