Packages

phoenix_kit

1.7.98
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit migrations postgres v92.ex
Raw

lib/phoenix_kit/migrations/postgres/v92.ex

defmodule PhoenixKit.Migrations.Postgres.V92 do
@moduledoc """
V92: Add organization accounts support and organization invitations.
## User schema changes
Adds three new columns to `phoenix_kit_users`:
- `account_type` (VARCHAR(20), NOT NULL, DEFAULT 'person') with CHECK constraint
- `organization_name` (VARCHAR(255)) for organization display names
- `organization_uuid` (UUID) self-referencing FK to link persons to organizations
## Organization invitations table
Creates `phoenix_kit_organization_invitations`:
- BYTEA token (SHA-256 hash of raw 32-byte token, unique)
- Status CHECK constraint: pending | accepted | declined | cancelled
- FK to phoenix_kit_users: organization_uuid (CASCADE), invited_by_uuid (SET NULL)
- Partial unique index on (organization_uuid, email) WHERE status = 'pending'
All operations are idempotent.
"""
use Ecto.Migration
def up(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
schema = if prefix == "public", do: "public", else: prefix
# 1. Add account_type column
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = '#{schema}'
AND table_name = 'phoenix_kit_users'
AND column_name = 'account_type'
) THEN
ALTER TABLE #{p}phoenix_kit_users
ADD COLUMN account_type VARCHAR(20) NOT NULL DEFAULT 'person'
CONSTRAINT phoenix_kit_users_account_type_check CHECK (account_type IN ('person', 'organization'));
END IF;
END $$;
""")
# 2. Add organization_name column
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = '#{schema}'
AND table_name = 'phoenix_kit_users'
AND column_name = 'organization_name'
) THEN
ALTER TABLE #{p}phoenix_kit_users
ADD COLUMN organization_name VARCHAR(255);
END IF;
END $$;
""")
# 3. Add organization_uuid column with FK
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = '#{schema}'
AND table_name = 'phoenix_kit_users'
AND column_name = 'organization_uuid'
) THEN
ALTER TABLE #{p}phoenix_kit_users
ADD COLUMN organization_uuid UUID
REFERENCES #{p}phoenix_kit_users(uuid) ON DELETE SET NULL;
END IF;
END $$;
""")
create_if_not_exists index(:phoenix_kit_users, [:account_type], prefix: prefix)
create_if_not_exists index(:phoenix_kit_users, [:organization_uuid], prefix: prefix)
# 4. Create organization invitations table
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = '#{schema}'
AND table_name = 'phoenix_kit_organization_invitations'
) THEN
CREATE TABLE #{p}phoenix_kit_organization_invitations (
uuid UUID NOT NULL DEFAULT uuid_generate_v7() PRIMARY KEY,
organization_uuid UUID NOT NULL
REFERENCES #{p}phoenix_kit_users(uuid) ON DELETE CASCADE,
email VARCHAR(160) NOT NULL,
invited_by_uuid UUID
REFERENCES #{p}phoenix_kit_users(uuid) ON DELETE SET NULL,
token BYTEA NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CONSTRAINT phoenix_kit_org_invitations_status_check
CHECK (status IN ('pending', 'accepted', 'declined', 'cancelled')),
expires_at TIMESTAMPTZ NOT NULL,
accepted_at TIMESTAMPTZ,
inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
END IF;
END $$;
""")
create_if_not_exists(
unique_index(:phoenix_kit_organization_invitations, [:token], prefix: prefix)
)
create_if_not_exists(
index(:phoenix_kit_organization_invitations, [:organization_uuid], prefix: prefix)
)
create_if_not_exists(index(:phoenix_kit_organization_invitations, [:email], prefix: prefix))
create_if_not_exists(index(:phoenix_kit_organization_invitations, [:status], prefix: prefix))
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM pg_indexes
WHERE schemaname = '#{schema}'
AND tablename = 'phoenix_kit_organization_invitations'
AND indexname = 'phoenix_kit_org_invitations_pending_unique_idx'
) THEN
CREATE UNIQUE INDEX phoenix_kit_org_invitations_pending_unique_idx
ON #{p}phoenix_kit_organization_invitations (organization_uuid, email)
WHERE status = 'pending';
END IF;
END $$;
""")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '92'")
end
def down(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
# Drop invitations table first (FK depends on phoenix_kit_users)
drop_if_exists(index(:phoenix_kit_organization_invitations, [:status], prefix: prefix))
drop_if_exists(index(:phoenix_kit_organization_invitations, [:email], prefix: prefix))
drop_if_exists(
index(:phoenix_kit_organization_invitations, [:organization_uuid], prefix: prefix)
)
drop_if_exists(unique_index(:phoenix_kit_organization_invitations, [:token], prefix: prefix))
execute("DROP TABLE IF EXISTS #{p}phoenix_kit_organization_invitations")
drop_if_exists index(:phoenix_kit_users, [:organization_uuid], prefix: prefix)
drop_if_exists index(:phoenix_kit_users, [:account_type], prefix: prefix)
execute("""
ALTER TABLE #{p}phoenix_kit_users
DROP COLUMN IF EXISTS organization_uuid,
DROP COLUMN IF EXISTS organization_name,
DROP COLUMN IF EXISTS account_type;
""")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '91'")
end
defp prefix_str("public"), do: "public."
defp prefix_str(prefix), do: "#{prefix}."
end