Packages
phoenix_kit
1.7.44
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
Current section
Files
lib/phoenix_kit/migrations/postgres/v55.ex
defmodule PhoenixKit.Migrations.Postgres.V55 do
@moduledoc """
V55: Standalone Comments Module
Creates polymorphic comments tables decoupled from the Posts module.
Comments can be attached to any resource type via `resource_type` + `resource_id`.
## Tables
- `phoenix_kit_comments` — threaded comments with polymorphic resource association
- `phoenix_kit_comments_likes` — comment like tracking
- `phoenix_kit_comments_dislikes` — comment dislike tracking
## Design
- Polymorphic: `resource_type` (varchar) + `resource_id` (uuid), no FK constraints
- Self-referencing `parent_id` for unlimited threading depth
- Counter caches for `like_count` and `dislike_count`
- Status-based moderation (published/hidden/deleted/pending)
- Old `phoenix_kit_post_comments` tables remain untouched
"""
use Ecto.Migration
def up(%{prefix: prefix} = _opts) do
prefix_str = if prefix && prefix != "public", do: "#{prefix}.", else: ""
schema_name = if prefix && prefix != "public", do: prefix, else: "public"
# Step 1: Create phoenix_kit_comments table
execute """
CREATE TABLE IF NOT EXISTS #{prefix_str}phoenix_kit_comments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
resource_type VARCHAR(50) NOT NULL,
resource_id UUID NOT NULL,
user_id BIGINT,
parent_id UUID,
content TEXT NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'published',
depth INTEGER NOT NULL DEFAULT 0,
like_count INTEGER NOT NULL DEFAULT 0,
dislike_count INTEGER NOT NULL DEFAULT 0,
inserted_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT fk_comments_user
FOREIGN KEY (user_id) REFERENCES #{prefix_str}phoenix_kit_users(id) ON DELETE SET NULL,
CONSTRAINT fk_comments_parent
FOREIGN KEY (parent_id) REFERENCES #{prefix_str}phoenix_kit_comments(id) ON DELETE CASCADE
)
"""
# Step 2: Create indexes for comments
execute """
CREATE INDEX IF NOT EXISTS idx_comments_resource
ON #{prefix_str}phoenix_kit_comments (resource_type, resource_id)
"""
execute """
CREATE INDEX IF NOT EXISTS idx_comments_resource_status
ON #{prefix_str}phoenix_kit_comments (resource_type, resource_id, status)
"""
execute """
CREATE INDEX IF NOT EXISTS idx_comments_user_id
ON #{prefix_str}phoenix_kit_comments (user_id)
"""
execute """
CREATE INDEX IF NOT EXISTS idx_comments_parent_id
ON #{prefix_str}phoenix_kit_comments (parent_id)
"""
execute """
CREATE INDEX IF NOT EXISTS idx_comments_status
ON #{prefix_str}phoenix_kit_comments (status)
"""
execute """
CREATE INDEX IF NOT EXISTS idx_comments_inserted_at
ON #{prefix_str}phoenix_kit_comments (inserted_at)
"""
# Step 3: Create phoenix_kit_comments_likes table
execute """
CREATE TABLE IF NOT EXISTS #{prefix_str}phoenix_kit_comments_likes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
comment_id UUID NOT NULL,
user_id BIGINT NOT NULL,
inserted_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT fk_comments_likes_comment
FOREIGN KEY (comment_id) REFERENCES #{prefix_str}phoenix_kit_comments(id) ON DELETE CASCADE,
CONSTRAINT fk_comments_likes_user
FOREIGN KEY (user_id) REFERENCES #{prefix_str}phoenix_kit_users(id) ON DELETE CASCADE,
CONSTRAINT uq_comments_likes_comment_user
UNIQUE (comment_id, user_id)
)
"""
# Step 4: Create phoenix_kit_comments_dislikes table
execute """
CREATE TABLE IF NOT EXISTS #{prefix_str}phoenix_kit_comments_dislikes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
comment_id UUID NOT NULL,
user_id BIGINT NOT NULL,
inserted_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
CONSTRAINT fk_comments_dislikes_comment
FOREIGN KEY (comment_id) REFERENCES #{prefix_str}phoenix_kit_comments(id) ON DELETE CASCADE,
CONSTRAINT fk_comments_dislikes_user
FOREIGN KEY (user_id) REFERENCES #{prefix_str}phoenix_kit_users(id) ON DELETE CASCADE,
CONSTRAINT uq_comments_dislikes_comment_user
UNIQUE (comment_id, user_id)
)
"""
# Step 5: Seed default settings
execute """
INSERT INTO #{prefix_str}phoenix_kit_settings (key, value, date_added, date_updated)
VALUES
('comments_enabled', 'false', NOW(), NOW()),
('comments_moderation', 'false', NOW(), NOW()),
('comments_max_depth', '10', NOW(), NOW()),
('comments_max_length', '10000', NOW(), NOW())
ON CONFLICT (key) DO NOTHING
"""
# Step 6: Seed "comments" permission for Admin role
seed_admin_comments_permission(prefix_str, schema_name)
# Record migration version
execute "COMMENT ON TABLE #{prefix_str}phoenix_kit IS '55'"
end
def down(%{prefix: prefix} = _opts) do
prefix_str = if prefix && prefix != "public", do: "#{prefix}.", else: ""
execute "DROP TABLE IF EXISTS #{prefix_str}phoenix_kit_comments_dislikes CASCADE"
execute "DROP TABLE IF EXISTS #{prefix_str}phoenix_kit_comments_likes CASCADE"
execute "DROP TABLE IF EXISTS #{prefix_str}phoenix_kit_comments CASCADE"
# Remove settings
execute """
DELETE FROM #{prefix_str}phoenix_kit_settings
WHERE key IN ('comments_enabled', 'comments_moderation', 'comments_max_depth', 'comments_max_length')
"""
# Remove permission
execute """
DELETE FROM #{prefix_str}phoenix_kit_role_permissions WHERE module_key = 'comments'
"""
# Record migration version
execute "COMMENT ON TABLE #{prefix_str}phoenix_kit IS '54'"
end
defp seed_admin_comments_permission(prefix_str, schema_name) do
execute """
DO $$
DECLARE
admin_role_id BIGINT;
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = '#{schema_name}' AND table_name = 'phoenix_kit_user_roles') THEN
SELECT id INTO admin_role_id FROM #{prefix_str}phoenix_kit_user_roles WHERE name = 'Admin' LIMIT 1;
IF admin_role_id IS NOT NULL THEN
INSERT INTO #{prefix_str}phoenix_kit_role_permissions (role_id, module_key, inserted_at)
VALUES (admin_role_id, 'comments', NOW())
ON CONFLICT (role_id, module_key) DO NOTHING;
END IF;
END IF;
END $$;
"""
end
end