一键导入
tpl-backend-elixir-phoenix
Template do pack (backend/10-elixir-phoenix.md). Orienta o agente em APIs, servicos e arquitetura backend alinhado a esse contexto.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Template do pack (backend/10-elixir-phoenix.md). Orienta o agente em APIs, servicos e arquitetura backend alinhado a esse contexto.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Generate custom favicons from logos, text, or brand colours. Produces favicon.svg, favicon.ico, apple-touch-icon.png, icon-192/512.png, and web manifest. Use whenever the user wants a favicon, mentions replacing a CMS default favicon, converting a logo into a favicon, creating branded initials icons, or troubleshooting favicon not displaying / iOS black square / missing manifest.
"Get a second opinion from leading AI models on code, architecture, strategy, prompting, or anything. Queries models via OpenRouter, Gemini, or OpenAI APIs. Supports single opinion, multi-model consensus, and devil's advocate patterns. Use whenever the user says 'brains trust', 'second opinion', 'ask gemini', 'ask gpt', 'peer review', 'consult another model', 'challenge this', or 'devil's advocate'."
Run an independent code review using the OpenAI Codex CLI in headless mode. Gets a second opinion from a different model family (GPT-5/o3) on recent changes, a PR, a commit, or the whole app — covering bugs, regressions, security, data consistency, UX/state bugs, performance risks, and testing gaps. Saves a severity-prioritised report to .jez/reviews/. Triggers: 'codex review', 'review with codex', 'second opinion on this code', 'independent code review', 'what does codex think', 'get codex to review'.
Deep research and discovery before building something new. Explores local projects for reusable code, researches competitors, reads forums and reviews, analyses plugin ecosystems, investigates technical options, and produces a comprehensive research brief. Three depths: focused (30 min), wide (1-2 hours), deep (3-6 hours). Triggers: 'research this', 'deep research', 'discovery', 'explore the space', 'what should I build', 'competitive analysis', 'before I start building', 'research before coding'.
Plan and execute entire application builds. Generates phased delivery roadmaps, then executes them autonomously — phase by phase, committing at milestones, deploying, testing, and continuing until done or stuck. Modes: plan (generate roadmap), start (begin executing), resume (continue from where you left off), status (show progress). Triggers: 'roadmap', 'plan the build', 'start building', 'resume the build', 'keep going', 'build the whole thing', 'execute the roadmap', 'what phase are we on'.
Walk through a live web app AS a real user to find usability + behavioural bugs that static reviews miss. REQUIRES proof of interaction (typing, clicking, sending, observing) before any verdict — a sweep that didn't interact terminates with verdict 'Incomplete'. Walks threads, exercises every element, runs the multi-pane stress matrix, visual polish sweep, component perfection checklist, automated a11y (axe-core), pragmatic performance budget (LCP/CLS/INP), scenario battery (11 scenarios), and stress recipes including the real-flavour data battery. Hard gates: console errors/warnings = 0, network 5xx = 0, layout collapse = 0, axe Critical/Serious = 0, perf budget green. Audit-the-audit meta-check rejects rushed reports. Each finding has reproduction steps, evidence path, and suspected code location. Trigger with 'ux audit', 'walkthrough', 'qa sweep', 'audit the app', 'dogfood this', 'check all pages', 'find what's broken', 'stress the UI'.
基于 SOC 职业分类
| name | tpl-backend-elixir-phoenix |
| description | Template do pack (backend/10-elixir-phoenix.md). Orienta o agente em APIs, servicos e arquitetura backend alinhado a esse contexto. |
| metadata | {"version":"1.0.0","source_template":"backend/10-elixir-phoenix.md","generated_by":"install_pack_templates_as_claude_skills"} |
Skill gerado a partir do pack templates-claude-code. Arquivo de origem: backend/10-elixir-phoenix.md. Use como baseline e adapte ao projeto antes de mudancas grandes.
lib/
├── my_app/ # Core business logic (Contexts)
│ ├── accounts/
│ │ ├── accounts.ex # Public context API
│ │ ├── user.ex # Ecto schema
│ │ └── user_token.ex
│ ├── blog/
│ │ ├── blog.ex
│ │ └── post.ex
│ └── workers/
│ └── email_worker.ex # GenServer / Oban job
├── my_app_web/ # Web layer
│ ├── router.ex
│ ├── endpoint.ex
│ ├── controllers/
│ │ ├── user_controller.ex
│ │ └── fallback_controller.ex
│ ├── live/
│ │ ├── post_live/
│ │ │ ├── index.ex
│ │ │ └── index.html.heex
│ │ └── post_live/
│ │ ├── show.ex
│ │ └── show.html.heex
│ ├── channels/
│ │ └── room_channel.ex
│ └── views/
│ └── error_view.ex
priv/
└── repo/
└── migrations/
test/
├── my_app/
│ └── accounts_test.exs
└── my_app_web/
├── controllers/
└── live/
MyApp.Accounts.get_user/1, never Repo.get(User, id) from controllers.changeset/2 only; no business logic.with patterns and fall through to {:error, ...}.handle_params/3 to load page-specific data lazily.mix credo --strict and mix dialyzer are CI blockers.# lib/my_app/accounts/user.ex
defmodule MyApp.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
@derive {Jason.Encoder, only: [:id, :email, :name, :inserted_at]}
schema "users" do
field :email, :string
field :name, :string
field :hashed_password, :string, redact: true
timestamps()
end
@required [:email, :name, :password]
def registration_changeset(user \\ %__MODULE__{}, attrs) do
user
|> cast(attrs, @required)
|> validate_required(@required)
|> validate_format(:email, ~r/@/, message: "must have @")
|> validate_length(:name, min: 2, max: 100)
|> validate_length(:password, min: 8, max: 72)
|> unique_constraint(:email)
|> put_password_hash()
end
defp put_password_hash(%Ecto.Changeset{valid?: true, changes: %{password: pw}} = cs),
do: change(cs, hashed_password: Bcrypt.hash_pwd_salt(pw))
defp put_password_hash(cs), do: cs
end
# lib/my_app/accounts/accounts.ex
defmodule MyApp.Accounts do
alias MyApp.Repo
alias MyApp.Accounts.User
def get_user(id), do: Repo.get(User, id)
def get_user!(id), do: Repo.get!(User, id)
def create_user(attrs) do
%User{}
|> User.registration_changeset(attrs)
|> Repo.insert()
end
def list_users(opts \\ []) do
limit = Keyword.get(opts, :limit, 20)
offset = Keyword.get(opts, :offset, 0)
Repo.all(from u in User, limit: ^limit, offset: ^offset, order_by: [asc: u.inserted_at])
end
end
# lib/my_app_web/controllers/user_controller.ex
defmodule MyAppWeb.UserController do
use MyAppWeb, :controller
alias MyApp.Accounts
action_fallback MyAppWeb.FallbackController
def index(conn, _params) do
users = Accounts.list_users()
render(conn, :index, users: users)
end
def create(conn, %{"user" => user_params}) do
with {:ok, user} <- Accounts.create_user(user_params) do
conn |> put_status(:created) |> render(:show, user: user)
end
end
def show(conn, %{"id" => id}) do
with user when not is_nil(user) <- Accounts.get_user(id) do
render(conn, :show, user: user)
else
nil -> {:error, :not_found}
end
end
end
# lib/my_app_web/controllers/fallback_controller.ex
defmodule MyAppWeb.FallbackController do
use MyAppWeb, :controller
def call(conn, {:error, %Ecto.Changeset{} = cs}) do
conn |> put_status(:unprocessable_entity)
|> render(:error, changeset: cs)
end
def call(conn, {:error, :not_found}) do
conn |> put_status(:not_found) |> render(:error, message: "Not found")
end
def call(conn, {:error, :unauthorized}) do
conn |> put_status(:unauthorized) |> render(:error, message: "Unauthorized")
end
end
# lib/my_app_web/channels/room_channel.ex
defmodule MyAppWeb.RoomChannel do
use Phoenix.Channel
alias MyApp.Blog
def join("room:" <> room_id, _payload, socket) do
send(self(), {:after_join, room_id})
{:ok, assign(socket, :room_id, room_id)}
end
def handle_info({:after_join, room_id}, socket) do
messages = Blog.list_messages(room_id, limit: 50)
push(socket, "history", %{messages: messages})
{:noreply, socket}
end
def handle_in("new_message", %{"body" => body}, socket) do
case Blog.create_message(socket.assigns.room_id, body, socket.assigns.current_user) do
{:ok, msg} ->
broadcast!(socket, "new_message", %{id: msg.id, body: msg.body})
{:noreply, socket}
{:error, _cs} ->
{:reply, {:error, %{reason: "invalid"}}, socket}
end
end
end
defmodule MyApp.StatCounter do
use GenServer
# Client API
def start_link(opts), do: GenServer.start_link(__MODULE__, %{}, opts)
def increment(key), do: GenServer.cast(__MODULE__, {:inc, key})
def get(key), do: GenServer.call(__MODULE__, {:get, key})
# Server callbacks
@impl true
def init(state), do: {:ok, state}
@impl true
def handle_cast({:inc, key}, state) do
{:noreply, Map.update(state, key, 1, &(&1 + 1))}
end
@impl true
def handle_call({:get, key}, _from, state) do
{:reply, Map.get(state, key, 0), state}
end
end
| Verb | Path | Controller/LiveView | Action |
|---|---|---|---|
| GET | /api/users | UserController | :index |
| POST | /api/users | UserController | :create |
| GET | /api/users/:id | UserController | :show |
| PUT | /api/users/:id | UserController | :update |
| DELETE | /api/users/:id | UserController | :delete |
| POST | /api/sessions | SessionController | :create (login) |
| DELETE | /api/sessions | SessionController | :delete (logout) |
| GET | /posts | PostLive.Index | (LiveView) |
| GET | /posts/:id | PostLive.Show | (LiveView) |
| WS | /socket | UserSocket + RoomChannel | real-time |
mix compile --warnings-as-errors — zero warningsmix credo --strict — cleanmix dialyzer — no type errorsmix test — all pass; no skipped without reasonmix coveralls ≥ 80% coverageRepo.* calls inside controllers, views, or LiveViews — use ContextsGenServer for things a simple function call handlessend/2 to unknown PIDs — always use Registry or named processesString.to_atom/1) — use String.to_existing_atom/1IO.inspect/puts in production code — use Logger:ets without supervisionrender/1