Curated library of 38 atomic skills, 7 personas, and 1 orchestrator for Elixir and Phoenix development. Organized by category: fundamentals, phoenix, database, testing, auth, infrastructure, quality, security, integrations, tooling, frameworks, personas, and orchestration. Covers core Elixir patterns, Phoenix LiveView, Ecto, OTP, Oban, testing, security, deployment, real-time, and modern tooling (Req, Swoosh, Cachex, Broadway, Ash).
73
91%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
Orchestrates safe Ecto migrations with idempotent cycles, rollback planning, and production deployment safety.
Steps:
down/0.HARD GATE — Plan Approved:
If gate fails: Clarify the schema change plan before implementing.
Steps:
mix ecto.gen.migration <descriptive_name>.up/0 (or change/0 for reversible migrations).down/0 for explicit rollback.ecto-essentials companion skill).ecto-changeset-patterns companion skill).Idempotent cycle test:
mix ecto.rollback
mix ecto.migrate
mix ecto.rollback
mix ecto.migrateAll four steps must succeed without errors.
HARD GATE — Idempotent Cycle Verified:
mix ecto.rollback succeedsmix ecto.migrate succeedsIf gate fails: Fix the migration's up/down before proceeding.
Add nullable column (safe):
defmodule MyApp.Repo.Migrations.AddPublishedAtToPosts do
use Ecto.Migration
def up do
alter table(:posts) do
add :published_at, :utc_datetime
end
end
def down do
alter table(:posts) do
remove :published_at
end
end
endAdd NOT NULL column with expand-contract (risky — three separate migrations per Phase 1 strategy):
# Migration 1 of 3: add nullable column
defmodule MyApp.Repo.Migrations.AddStatusToPosts do
use Ecto.Migration
def up do
alter table(:posts) do
add :status, :string, default: "draft"
end
end
def down do
alter table(:posts) do
remove :status
end
end
end
# Migration 2 of 3: backfill existing rows
defmodule MyApp.Repo.Migrations.BackfillPostStatus do
use Ecto.Migration
def up do
execute("UPDATE posts SET status = 'draft' WHERE status IS NULL")
end
def down do
# No-op — backfill is irreversible
end
end
# Migration 3 of 3: enforce NOT NULL constraint
defmodule MyApp.Repo.Migrations.EnforcePostStatusNotNull do
use Ecto.Migration
def up do
alter table(:posts) do
modify :status, :string, null: false, default: "draft"
end
end
def down do
alter table(:posts) do
modify :status, :string, null: true, default: "draft"
end
end
endAdd index concurrently (safe for large tables):
defmodule MyApp.Repo.Migrations.AddPostAuthorIndex do
use Ecto.Migration
@disable_ddl_transaction true
def up do
create index(:posts, [:author_id], concurrently: true)
end
def down do
drop index(:posts, [:author_id])
end
endSteps:
mix test.MIX_ENV=test mix ecto.migrate.HARD GATE — Test Suite Passes:
mix test
MIX_ENV=test mix ecto.migrateIf gate fails: Fix tests or migration logic.
Steps:
HARD GATE — Rollback Ready:
When completing a migration, output MUST include:
# Migration Report — [Migration Name]
## Plan
- Change: <description>
- Classification: safe / risky / dangerous
- Lock behavior: <assessment>
- Expand-contract: yes / no (steps: <list>)
## Implementation
- File: <migration file path>
- up: <brief description>
- down: <brief description>
- Idempotent cycle: migrate→rollback→migrate→rollback→migrate ✓
## Verification
- mix test: ✓ (<n> tests, 0 failures)
- MIX_ENV=test mix ecto.migrate: ✓
## Deployment Plan
- [ ] Code deployed (handles old + new schema)
- [ ] Migration applied
- [ ] Backfill run (if needed)
- [ ] Cleanup code deployed
- [ ] Rollback command documented: mix ecto.rollbackMigration fails in production:
mix ecto.rollback if reversible; otherwise plan a forward-only fix migration.Rollback fails:
down/0 reverses every operation in up/0 in the correct order.change/0 migrations, Ecto auto-generates the reverse; manual up/down must stay in sync.Lock timeout on large table:
concurrently: true and @disable_ddl_transaction true for index creation.concurrently on large tablesdown/0 defined