[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EFTKHEKRTTQA6AP8VT2JEY":3,"skill-same:01M6EFTKHEKRTTQA6AP8VT2JEY":46},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":21,"frontMatter":22,"refName":23,"commitSha":24,"skillDirectory":25,"forksCount":26,"repositoryHtmlUrl":27,"repositoryHomepageUrl":28,"ownerHtmlUrl":29,"ownerBlogUrl":6,"ownerDescription":30,"updatedAt":31,"install":32,"resources":45},"01M6EFTKHEKRTTQA6AP8VT2JEY","phoenix",null,"ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fphoenix\u002FSKILL.md",[],[18],"Phoenix","2026-11-10 10:12:30",false,"# Phoenix\n\nPhoenix leverages the Erlang VM (BEAM) for massive concurrency and fault tolerance. LiveView enables rich, real-time UIs with server-rendered HTML — no JavaScript framework needed.\n\n## Installation\n\n```bash\n# Install Phoenix and create project\nmix archive.install hex phx_new\nmix phx.new my_app --database postgres\ncd my_app\nmix setup   # deps.get + ecto.create + assets\n```\n\n## Project Structure\n\n```\n# Phoenix project layout\nlib\u002Fmy_app\u002F\n├── application.ex          # OTP supervision tree\n├── repo.ex                 # Ecto repo\n├── accounts\u002F               # Context module\n│   ├── user.ex             # Ecto schema\n│   └── accounts.ex         # Business logic\nlib\u002Fmy_app_web\u002F\n├── endpoint.ex             # HTTP entry point\n├── router.ex               # Routes\n├── controllers\u002F            # REST controllers\n├── live\u002F                   # LiveView modules\n├── components\u002F             # Function components\n└── templates\u002F              # HEEx templates\n```\n\n## Ecto Schema and Migration\n\n```elixir\n# lib\u002Fmy_app\u002Farticles\u002Farticle.ex — Ecto schema\ndefmodule MyApp.Articles.Article do\n  use Ecto.Schema\n  import Ecto.Changeset\n\n  schema \"articles\" do\n    field :title, :string\n    field :slug, :string\n    field :body, :string\n    field :published, :boolean, default: false\n    belongs_to :author, MyApp.Accounts.User\n    timestamps()\n  end\n\n  def changeset(article, attrs) do\n    article\n    |> cast(attrs, [:title, :body, :published])\n    |> validate_required([:title, :body])\n    |> validate_length(:title, max: 200)\n    |> unique_constraint(:slug)\n    |> generate_slug()\n  end\n\n  defp generate_slug(changeset) do\n    case get_change(changeset, :title) do\n      nil -> changeset\n      title -> put_change(changeset, :slug, Slug.slugify(title))\n    end\n  end\nend\n```\n\n```elixir\n# priv\u002Frepo\u002Fmigrations\u002F20240101000000_create_articles.exs — migration\ndefmodule MyApp.Repo.Migrations.CreateArticles do\n  use Ecto.Migration\n\n  def change do\n    create table(:articles) do\n      add :title, :string, null: false, size: 200\n      add :slug, :string, null: false\n      add :body, :text, null: false\n      add :published, :boolean, default: false\n      add :author_id, references(:users, on_delete: :delete_all), null: false\n      timestamps()\n    end\n\n    create unique_index(:articles, [:slug])\n  end\nend\n```\n\n## Context Module\n\n```elixir\n# lib\u002Fmy_app\u002Farticles\u002Farticles.ex — business logic context\ndefmodule MyApp.Articles do\n  import Ecto.Query\n  alias MyApp.Repo\n  alias MyApp.Articles.Article\n\n  def list_published do\n    Article\n    |> where(published: true)\n    |> order_by(desc: :inserted_at)\n    |> preload(:author)\n    |> Repo.all()\n  end\n\n  def get_article!(id), do: Repo.get!(Article, id) |> Repo.preload(:author)\n\n  def create_article(attrs) do\n    %Article{}\n    |> Article.changeset(attrs)\n    |> Repo.insert()\n  end\n\n  def update_article(%Article{} = article, attrs) do\n    article\n    |> Article.changeset(attrs)\n    |> Repo.update()\n  end\nend\n```\n\n## Router\n\n```elixir\n# lib\u002Fmy_app_web\u002Frouter.ex — routing\ndefmodule MyAppWeb.Router do\n  use MyAppWeb, :router\n\n  pipeline :browser do\n    plug :accepts, [\"html\"]\n    plug :fetch_session\n    plug :fetch_live_flash\n    plug :put_root_layout, html: {MyAppWeb.Layouts, :root}\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n  end\n\n  pipeline :api do\n    plug :accepts, [\"json\"]\n  end\n\n  scope \"\u002F\", MyAppWeb do\n    pipe_through :browser\n    live \"\u002Farticles\", ArticleLive.Index, :index\n    live \"\u002Farticles\u002F:slug\", ArticleLive.Show, :show\n  end\n\n  scope \"\u002Fapi\", MyAppWeb.API do\n    pipe_through :api\n    resources \"\u002Farticles\", ArticleController, only: [:index, :show, :create]\n  end\nend\n```\n\n## LiveView\n\n```elixir\n# lib\u002Fmy_app_web\u002Flive\u002Farticle_live\u002Findex.ex — LiveView for article list\ndefmodule MyAppWeb.ArticleLive.Index do\n  use MyAppWeb, :live_view\n\n  alias MyApp.Articles\n\n  @impl true\n  def mount(_params, _session, socket) do\n    articles = Articles.list_published()\n    {:ok, assign(socket, articles: articles, search: \"\")}\n  end\n\n  @impl true\n  def handle_event(\"search\", %{\"query\" => query}, socket) do\n    articles = Articles.search(query)\n    {:noreply, assign(socket, articles: articles, search: query)}\n  end\nend\n```\n\n```heex\n\u003C!-- lib\u002Fmy_app_web\u002Flive\u002Farticle_live\u002Findex.html.heex — LiveView template -->\n\u003Cdiv>\n  \u003Ch1>Articles\u003C\u002Fh1>\n  \u003Cform phx-change=\"search\" phx-debounce=\"300\">\n    \u003Cinput type=\"text\" name=\"query\" value={@search} placeholder=\"Search...\" \u002F>\n  \u003C\u002Fform>\n  \u003Cdiv :for={article \u003C- @articles}>\n    \u003Ch2>\u003C.link navigate={~p\"\u002Farticles\u002F#{article.slug}\"}>\u003C%= article.title %>\u003C\u002F.link>\u003C\u002Fh2>\n    \u003Cp>By \u003C%= article.author.name %>\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n## JSON Controller\n\n```elixir\n# lib\u002Fmy_app_web\u002Fcontrollers\u002Fapi\u002Farticle_controller.ex — API controller\ndefmodule MyAppWeb.API.ArticleController do\n  use MyAppWeb, :controller\n  alias MyApp.Articles\n\n  def index(conn, _params) do\n    articles = Articles.list_published()\n    json(conn, %{data: Enum.map(articles, &article_json\u002F1)})\n  end\n\n  def create(conn, %{\"article\" => params}) do\n    case Articles.create_article(params) do\n      {:ok, article} -> conn |> put_status(:created) |> json(%{data: article_json(article)})\n      {:error, changeset} -> conn |> put_status(422) |> json(%{errors: format_errors(changeset)})\n    end\n  end\n\n  defp article_json(a), do: %{id: a.id, title: a.title, slug: a.slug}\nend\n```\n\n## Channels (Real-time)\n\n```elixir\n# lib\u002Fmy_app_web\u002Fchannels\u002Froom_channel.ex — WebSocket channel\ndefmodule MyAppWeb.RoomChannel do\n  use MyAppWeb, :channel\n\n  def join(\"room:\" \u003C> room_id, _params, socket) do\n    {:ok, assign(socket, :room_id, room_id)}\n  end\n\n  def handle_in(\"message\", %{\"body\" => body}, socket) do\n    broadcast!(socket, \"message\", %{body: body, user: socket.assigns.user_id})\n    {:noreply, socket}\n  end\nend\n```\n\n## Testing\n\n```elixir\n# test\u002Fmy_app\u002Farticles_test.exs — context test\ndefmodule MyApp.ArticlesTest do\n  use MyApp.DataCase\n  alias MyApp.Articles\n\n  test \"create_article\u002F1 with valid data\" do\n    attrs = %{title: \"Test\", body: \"Content\", author_id: user_fixture().id}\n    assert {:ok, article} = Articles.create_article(attrs)\n    assert article.title == \"Test\"\n  end\nend\n```\n\n## Key Commands\n\n```bash\n# Common Mix commands\nmix phx.gen.live Articles Article articles title:string body:text\nmix ecto.migrate\nmix phx.routes          # Show all routes\nmix test\nmix phx.server          # Start dev server\niex -S mix phx.server   # Start with REPL\n```\n\n## Key Patterns\n\n- Organize business logic in Context modules — controllers\u002FLiveViews delegate to contexts\n- Use changesets for all data validation — they compose and return descriptive errors\n- Use `preload` explicitly — Ecto never lazy-loads to prevent N+1\n- LiveView `handle_event` replaces most JavaScript interactivity\n- Use PubSub (`Phoenix.PubSub.broadcast`) for real-time updates across LiveView processes\n- Use `Ecto.Multi` for transactions spanning multiple operations\n",{},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002FTerminalSkills\u002Fskills\u002Fphoenix",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":7,"skillName":5,"commands":33,"prompt":43,"zipAvailable":44},[34,37,40],{"tool":35,"command":36},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill phoenix",{"tool":38,"command":39},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill phoenix",{"tool":41,"command":42},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill phoenix","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fphoenix\u002FSKILL.md",true,[],[47,61,71,80,86,93],{"skillNo":48,"name":49,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":50,"categories":51,"keywords":57,"publishedAt":19},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[52],{"categoryNo":53,"categoryName":54,"taxonomyType":55,"taxonomyTypeDesc":56},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[58,59,60],"model","model hierarchy","model hierarchy skill",{"skillNo":62,"name":63,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":67,"publishedAt":19},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[66],{"categoryNo":53,"categoryName":54,"taxonomyType":55,"taxonomyTypeDesc":56},[68,69,70],"MCP","zoom","zoom mcp",{"skillNo":72,"name":73,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":76,"publishedAt":19},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[77,78,79,69],"sdk","zoom apps sdk","apps",{"skillNo":81,"name":82,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":19},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[82],{"skillNo":87,"name":88,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":92,"publishedAt":19},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[91],{"categoryNo":53,"categoryName":54,"taxonomyType":55,"taxonomyTypeDesc":56},[88],{"skillNo":94,"name":95,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":98,"publishedAt":19},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[95]]