Packages

phoenix_kit

1.7.176
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 v101.ex
Raw

lib/phoenix_kit/migrations/postgres/v101.ex

defmodule PhoenixKit.Migrations.Postgres.V101 do
@moduledoc """
V101: Projects module tables.
Creates five tables used by `phoenix_kit_projects`:
- `phoenix_kit_project_tasks` — reusable task library with default
assignees and estimated duration
- `phoenix_kit_project_task_dependencies` — "task A must finish before
task B" links at the template (library) level
- `phoenix_kit_projects` — project containers with start mode
(immediate / scheduled)
- `phoenix_kit_project_assignments` — task instance in a project;
copies duration + description from template (editable independently)
- `phoenix_kit_project_dependencies` — per-project assignment-level
"A must finish before B" links
Each assignment and task template may have **at most one** assignee
(team, department, or person) — enforced by `CHECK (num_nonnulls(...) <= 1)`
on both tables.
Depends on V100 (staff tables) for the polymorphic assignee foreign keys.
"""
use Ecto.Migration
def up(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
execute("""
CREATE TABLE IF NOT EXISTS #{p}phoenix_kit_project_tasks (
uuid UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
title VARCHAR(255) NOT NULL,
description TEXT,
estimated_duration INTEGER,
estimated_duration_unit VARCHAR(20) DEFAULT 'hours',
default_assigned_team_uuid UUID REFERENCES #{p}phoenix_kit_staff_teams(uuid) ON DELETE SET NULL,
default_assigned_department_uuid UUID REFERENCES #{p}phoenix_kit_staff_departments(uuid) ON DELETE SET NULL,
default_assigned_person_uuid UUID REFERENCES #{p}phoenix_kit_staff_people(uuid) ON DELETE SET NULL,
inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT phoenix_kit_project_tasks_single_default_assignee
CHECK (num_nonnulls(default_assigned_team_uuid, default_assigned_department_uuid, default_assigned_person_uuid) <= 1)
)
""")
execute("""
CREATE UNIQUE INDEX IF NOT EXISTS phoenix_kit_project_tasks_title_index
ON #{p}phoenix_kit_project_tasks (lower(title))
""")
execute("""
CREATE TABLE IF NOT EXISTS #{p}phoenix_kit_projects (
uuid UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
name VARCHAR(255) NOT NULL,
description TEXT,
status VARCHAR(20) NOT NULL DEFAULT 'active',
is_template BOOLEAN NOT NULL DEFAULT false,
counts_weekends BOOLEAN NOT NULL DEFAULT false,
start_mode VARCHAR(20) NOT NULL DEFAULT 'immediate',
scheduled_start_date DATE,
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
""")
execute("""
CREATE UNIQUE INDEX IF NOT EXISTS phoenix_kit_projects_name_index
ON #{p}phoenix_kit_projects (lower(name))
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_projects_status_index
ON #{p}phoenix_kit_projects (status)
""")
execute("""
CREATE TABLE IF NOT EXISTS #{p}phoenix_kit_project_assignments (
uuid UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
project_uuid UUID NOT NULL REFERENCES #{p}phoenix_kit_projects(uuid) ON DELETE CASCADE,
task_uuid UUID NOT NULL REFERENCES #{p}phoenix_kit_project_tasks(uuid) ON DELETE CASCADE,
status VARCHAR(20) NOT NULL DEFAULT 'todo',
position INTEGER NOT NULL DEFAULT 0,
description TEXT,
estimated_duration INTEGER,
estimated_duration_unit VARCHAR(20),
assigned_team_uuid UUID REFERENCES #{p}phoenix_kit_staff_teams(uuid) ON DELETE SET NULL,
assigned_department_uuid UUID REFERENCES #{p}phoenix_kit_staff_departments(uuid) ON DELETE SET NULL,
assigned_person_uuid UUID REFERENCES #{p}phoenix_kit_staff_people(uuid) ON DELETE SET NULL,
counts_weekends BOOLEAN,
progress_pct INTEGER NOT NULL DEFAULT 0,
track_progress BOOLEAN NOT NULL DEFAULT false,
completed_by_uuid UUID REFERENCES #{p}phoenix_kit_users(uuid) ON DELETE SET NULL,
completed_at TIMESTAMPTZ,
inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT phoenix_kit_project_assignments_single_assignee
CHECK (num_nonnulls(assigned_team_uuid, assigned_department_uuid, assigned_person_uuid) <= 1)
)
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_assignments_project_index
ON #{p}phoenix_kit_project_assignments (project_uuid)
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_assignments_status_index
ON #{p}phoenix_kit_project_assignments (status)
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_assignments_task_index
ON #{p}phoenix_kit_project_assignments (task_uuid)
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_assignments_team_index
ON #{p}phoenix_kit_project_assignments (assigned_team_uuid)
WHERE assigned_team_uuid IS NOT NULL
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_assignments_department_index
ON #{p}phoenix_kit_project_assignments (assigned_department_uuid)
WHERE assigned_department_uuid IS NOT NULL
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_assignments_person_index
ON #{p}phoenix_kit_project_assignments (assigned_person_uuid)
WHERE assigned_person_uuid IS NOT NULL
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_assignments_completed_by_index
ON #{p}phoenix_kit_project_assignments (completed_by_uuid)
WHERE completed_by_uuid IS NOT NULL
""")
execute("""
CREATE TABLE IF NOT EXISTS #{p}phoenix_kit_project_dependencies (
uuid UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
assignment_uuid UUID NOT NULL REFERENCES #{p}phoenix_kit_project_assignments(uuid) ON DELETE CASCADE,
depends_on_uuid UUID NOT NULL REFERENCES #{p}phoenix_kit_project_assignments(uuid) ON DELETE CASCADE,
inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
""")
execute("""
CREATE UNIQUE INDEX IF NOT EXISTS phoenix_kit_project_dependencies_pair_index
ON #{p}phoenix_kit_project_dependencies (assignment_uuid, depends_on_uuid)
""")
# Reverse lookup: "which assignments depend on X?" (impact analysis when
# marking X done). The pair index above only helps forward lookups.
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_project_dependencies_depends_on_index
ON #{p}phoenix_kit_project_dependencies (depends_on_uuid)
""")
execute("""
CREATE TABLE IF NOT EXISTS #{p}phoenix_kit_project_task_dependencies (
uuid UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
task_uuid UUID NOT NULL REFERENCES #{p}phoenix_kit_project_tasks(uuid) ON DELETE CASCADE,
depends_on_task_uuid UUID NOT NULL REFERENCES #{p}phoenix_kit_project_tasks(uuid) ON DELETE CASCADE,
inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
""")
execute("""
CREATE UNIQUE INDEX IF NOT EXISTS phoenix_kit_project_task_deps_pair_index
ON #{p}phoenix_kit_project_task_dependencies (task_uuid, depends_on_task_uuid)
""")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '101'")
end
def down(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
execute("DROP TABLE IF EXISTS #{p}phoenix_kit_project_task_dependencies")
execute("DROP TABLE IF EXISTS #{p}phoenix_kit_project_dependencies")
execute("DROP TABLE IF EXISTS #{p}phoenix_kit_project_assignments")
execute("DROP TABLE IF EXISTS #{p}phoenix_kit_projects")
execute("DROP TABLE IF EXISTS #{p}phoenix_kit_project_tasks")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '100'")
end
defp prefix_str("public"), do: "public."
defp prefix_str(prefix), do: "#{prefix}."
end