Agent Skillsoperately/operately › ecto-migrations

ecto-migrations

GitHub

定义 Ecto 数据库迁移规范,涵盖 Schema 与 Data 迁移的创建、命名及数据回填规则。指导使用 make gen.migration 生成文件以避免版本冲突,禁止在数据迁移中依赖应用模块,确保迁移安全与一致性。

.agents/skills/ecto-migrations/SKILL.md operately/operately

Trigger Scenarios

添加或重命名数据库字段 执行数据回填或修复 生成 Ecto 迁移文件 解决迁移版本冲突

Install

npx skills add operately/operately --skill ecto-migrations -g -y
More Options

Non-standard path

npx skills add https://github.com/operately/operately/tree/main/.agents/skills/ecto-migrations -g -y

Use without installing

npx skills use operately/operately@ecto-migrations

指定 Agent (Claude Code)

npx skills add operately/operately --skill ecto-migrations -a claude-code -g -y

安装 repo 全部 skill

npx skills add operately/operately --all -g -y

预览 repo 内 skill

npx skills add operately/operately --list

SKILL.md

Frontmatter
{
    "name": "ecto-migrations",
    "description": "Rules for Operately schema migrations (app\/priv\/repo\/migrations\/) and data migrations (app\/lib\/operately\/data\/change_*.ex). Use when adding, renaming, reviewing, or generating database migrations, ecto.gen.migration, Operately.Data.Change* modules, backfills, schema_migrations version collisions, mix ecto.migrate, or make gen.migration."
}

Ecto Migrations

Two layers work together:

Layer Location Role
Schema migration app/priv/repo/migrations/*.exs DDL and/or calls a data change; tracked in schema_migrations
Data migration app/lib/operately/data/change_NNN_*.ex Backfills and data fixes; invoked from a thin schema migration

Creating schema migration files

Always create files in app/priv/repo/migrations/ with:

make gen.migration NAME=add_foo_to_bars

That runs mix ecto.gen.migration inside devenv (see root Makefile gen.migration target) and assigns a unique timestamp version.

Never create or copy migration files by hand (including inventing a YYYYMMDDHHMMSS_*.exs name). Manual timestamps collide across PRs that land close together. Ecto keys migrations by the numeric prefix only, so duplicates cause skipped migrations, re-runs, and production failures (e.g. duplicate_column or missing columns after a rename).

After generating, edit only the body of the generated file. Do not rename the file to “fix” a conflict with another branch — coordinate timestamps via make gen.migration on an up-to-date main instead.

Data migrations

Backfills and one-off data fixes live under app/lib/operately/data/ as Operately.Data.ChangeNNN… modules. A thin schema migration (created with make gen.migration) calls them:

defmodule Operately.Repo.Migrations.BaselineDocumentVersions do
  use Ecto.Migration

  def up do
    Operately.Data.Change110BaselineDocumentVersions.run()
  end

  def down do
    :ok
  end
end

Examples: change_110_baseline_document_versions.ex20260720190200_baseline_document_versions.exs; change_106_backfill_document_names_from_nodes.ex20260720120100_backfill_document_names_from_nodes.exs.

Naming

  • Next unused number: look at the highest change_NNN_*.ex under app/lib/operately/data/ (currently in the 110s).
  • Module: Operately.Data.ChangeNNNDescriptiveName
  • File: change_NNN_descriptive_name.ex
  • Prefer a run/0 entry point (some older modules use up/0).

Do not depend on application modules

Data migrations must not alias live app schemas such as Operately.Goals.Goal or Operately.Activities.Activity. Those modules change over time; a migration that imports them can break on fresh installs months later.

Define minimal inline structs/modules inside the change module with only the fields and helpers the migration needs.

# ❌ DON'T: referencing application modules directly inside migrations
defmodule Operately.Data.Change155MyMigration do
  alias Operately.Repo
  alias Operately.Activities.Activity

  def run do
    from(a in Activity, where: a.action == "task_description_change")
    |> Repo.update_all(set: [content: %{}])
  end
end

# ✅ DO: declare minimal inline structs/modules needed by the migration
defmodule Operately.Data.Change155MyMigration do
  alias Operately.Repo
  alias __MODULE__.Activity

  def run do
    from(a in Activity, where: a.action == "task_description_change")
    |> Repo.update_all(set: [content: %{}])
  end

  defmodule Activity do
    use Operately.Schema

    schema "activities" do
      field :action, :string
      field :content, :map
    end
  end
end

References: change_082_populate_goal_description_changed_activity_goal_name.ex, change_080_create_subscriptions_list_for_tasks.ex, change_110_baseline_document_versions.ex.

(Same rule is summarized in root AGENTS.md under Data Migration Guidelines.)

Idempotency and tests

  • Prefer idempotent run/0 (safe if re-run or if some rows already match the target state).
  • Add tests under app/test/operately/data/change_NNN_*_test.exs (see change_110_baseline_document_versions_test.exs).

Checklist

  • Schema migration created via make gen.migration NAME=...
  • No hand-written or hand-copied app/priv/repo/migrations/*.exs filenames
  • Version prefix is unique among existing migrations before opening the PR
  • Data backfill lives in Operately.Data.ChangeNNN… with inline schemas only
  • Schema migration’s up/0 only delegates to ChangeNNN.run() (plus any DDL)
  • Data change is idempotent where practical and covered by a unit test

Version History

  • 379b061 Current 2026-08-20 12:01

Same Skill Collection

.agents/skills/components-architecture/SKILL.md
.agents/skills/help-docs/SKILL.md
.agents/skills/mcp-tools/SKILL.md
.agents/skills/ui-copy/SKILL.md
.agents/skills/writing-tests/SKILL.md
.agents/skills/clean-code/SKILL.md

Metadata

Files
0
Version
379b061
Hash
8122f13e
Indexed
2026-08-20 12:01

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-25 00:34
浙ICP备14020137号-1 $방문자$