con un clic
bootstrap-phoenix
Bootstrap Phoenix Application
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Bootstrap Phoenix Application
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Add a "non-production" environment banner to a Phoenix 1.8 app — a sticky bar at the top of every page that warns developers the app is not production. Adds a config entry for the production host, a reusable function component + helpers in the web Layouts module, and renders the banner in every root layout. Detection is host-based (or Mix-env based) and asks for configuration like the production host. Checks what already exists and only adds missing pieces. Use when the user says "env banner", "environment banner", "dev banner", "staging banner", "non-production bar", "not in production banner", or wants a warning bar shown everywhere except production.
Bootstrap account user management UI and backend in a Phoenix 1.8 app. Adds LiveView for listing, inviting, and removing account members with role-based access control. Builds on top of bootstrap-accounts. Use when the user says "bootstrap user management", "add user management", "account users", "invite users", "member management", "manage account members", or wants to add user invitation and role management to an account-scoped Phoenix app.
Inspect OpenSpec artifacts for gaps, correctness, consistency, and codebase alignment. Dispatches subcommands via `/inspector [subcommand] [args]`. Use when the user says "/inspector review", "inspect change", "audit the spec", "/inspector review-update", "review and fix", "/inspector sync-linear", "/inspector commits", "check commits against specs", "/inspector reconcile", "reconcile specs", "sync specs to code", "/inspector explain", "explain the change", "/inspector mockups", "generate mockups", "wireframe the change", "/inspector flows", "generate flow diagrams", "workflow diagrams", "/inspector review-work", "verify and review", or asks to sanity-check, critique, find gaps, generate UI mockups, process flow diagrams, or verify implementation.
Set up and configure GoodIssuesReporter in Elixir/Phoenix applications. Dispatches subcommands via `/goodissues-reporter [subcommand]`. Use when the user says '/goodissues-reporter bootstrap', '/goodissues-reporter help', 'add goodissues reporter', 'setup error reporting', 'add goodissues monitoring', or wants to integrate GoodIssuesReporter into a Phoenix app.
Publish a release by running `just publish`. Use when the user says '/publish', 'publish release', 'cut a release', 'release', 'tag and release', or wants to build, tag, and publish a new version.
Create and update Elixir API client packages using CanOpener compile-time OpenAPI code generation. Dispatches subcommands via `/can-opener [subcommand]`. Use when the user says '/can-opener bootstrap', '/can-opener update', '/can-opener help', 'new elixir client', 'api client package', 'can opener', 'update api client', or wants to scaffold or update a CanOpener-based Elixir client library.
| name | bootstrap-phoenix |
| description | Bootstrap Phoenix Application |
Set up a new Phoenix application with comprehensive code quality, testing, and development tooling including:
Before creating a new application, check if a Phoenix app already exists:
mix.exs containing {:phoenix,mix.exs containing {:phoenix,# Check current directory
grep -l "{:phoenix," mix.exs 2>/dev/null
# Check subdirectories (one level deep)
find . -maxdepth 2 -name "mix.exs" -exec grep -l "{:phoenix," {} \; 2>/dev/null
If a Phoenix app is found:
Extract the app name from the mix.exs project configuration:
# Look for: app: :app_name in the project/0 function
Set working directory to the Phoenix app root (where mix.exs is located)
Skip Phase 1 entirely and proceed directly to Phase 2: Update Dependencies
Inform the user: "Detected existing Phoenix app: APP_NAME. Skipping project creation and proceeding with dependency updates."
Proceed with Phase 1: Create Phoenix Application below.
mix phx.new APP_NAME --binary-id --database postgres
cd APP_NAME
Note: Replace APP_NAME with your actual application name (lowercase, underscores for spaces).
File: mix.exs
Replace the deps/0 function with:
defp deps do
[
# Phoenix Core
{:phoenix, "~> 1.8"},
{:phoenix_ecto, "~> 4.5"},
{:ecto_sql, "~> 3.13"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 4.1"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 1.1"},
{:phoenix_live_dashboard, "~> 0.8"},
# Assets
{:esbuild, "~> 0.10", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.3", runtime: Mix.env() == :dev},
{:heroicons,
github: "tailwindlabs/heroicons",
tag: "v2.2.0",
sparse: "optimized",
app: false,
compile: false,
depth: 1},
# HTTP Client (always use Req, never HTTPoison/Tesla)
{:req, "~> 0.5"},
# Email
{:swoosh, "~> 1.16"},
# Background Jobs
{:oban, "~> 2.18"},
# Security
{:bcrypt_elixir, "~> 3.0"},
# Environment & Config
{:dotenvy, "~> 1.1"},
# Error Tracking
{:sentry, "~> 12.0"},
# Utilities
{:telemetry_metrics, "~> 1.0"},
{:telemetry_poller, "~> 1.0"},
{:gettext, "~> 1.0"},
{:jason, "~> 1.2"},
{:dns_cluster, "~> 0.2.0"},
{:bandit, "~> 1.5"},
# Development Tools
{:tidewave, "~> 0.5", only: :dev},
# Code Quality (dev/test only)
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:ex_dna, github: "dannote/ex_dna", branch: "master", only: [:dev, :test], runtime: false},
{:ex_slop, github: "dannote/ex_slop", branch: "master", only: [:dev, :test], runtime: false},
{:doctor, "~> 0.21", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
{:sobelow, "~> 0.13", only: [:dev, :test], runtime: false},
# Testing
{:lazy_html, ">= 0.1.0", only: :test},
{:mimic, "~> 1.10", only: :test}
]
end
File: mix.exs
Update the project/0 function:
def project do
[
app: :APP_NAME,
version: "0.1.0",
elixir: "~> 1.15",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
compilers: [:phoenix_live_view] ++ Mix.compilers(),
listeners: [Phoenix.CodeReloader],
dialyzer: [
plt_file: {:no_warn, "priv/plts/dialyzer.plt"},
plt_add_apps: [:ex_unit]
]
]
end
def cli do
[
preferred_envs: [check: :test, precommit: :test]
]
end
File: mix.exs
Update the aliases/0 function:
defp aliases do
[
setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
"assets.build": ["compile", "tailwind APP_NAME", "esbuild APP_NAME"],
"assets.deploy": [
"tailwind APP_NAME --minify",
"esbuild APP_NAME --minify",
"phx.digest"
],
check: [
"compile --warnings-as-errors",
"deps.unlock --unused",
"format --check-formatted",
"credo --strict",
"doctor",
"sobelow --config",
"dialyzer",
"test"
],
precommit: ["check"]
]
end
File: .credo.exs
%{
configs: [
%{
name: "default",
files: %{
included: [
"lib/",
"src/",
"test/",
"web/",
"apps/*/lib/",
"apps/*/src/",
"apps/*/test/",
"apps/*/web/"
],
excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"]
},
plugins: [],
requires: ["deps/ex_dna/lib/ex_dna/integrations/credo.ex"],
strict: true,
parse_timeout: 5000,
color: true,
checks: %{
enabled: [
# Consistency Checks
{Credo.Check.Consistency.ExceptionNames, []},
{Credo.Check.Consistency.LineEndings, []},
{Credo.Check.Consistency.ParameterPatternMatching, []},
{Credo.Check.Consistency.SpaceAroundOperators, []},
{Credo.Check.Consistency.SpaceInParentheses, []},
{Credo.Check.Consistency.TabsOrSpaces, []},
# Design Checks
{Credo.Check.Design.AliasUsage,
[priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]},
{ExDNA.Credo, []},
{Credo.Check.Design.TagTODO, [exit_status: 2]},
{Credo.Check.Design.TagFIXME, []},
# Readability Checks
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, []},
{Credo.Check.Readability.ModuleNames, []},
{Credo.Check.Readability.ParenthesesInCondition, []},
{Credo.Check.Readability.ParenthesesOnZeroArityDefs, []},
{Credo.Check.Readability.PredicateFunctionNames, []},
{Credo.Check.Readability.PreferImplicitTry, []},
{Credo.Check.Readability.RedundantBlankLines, []},
{Credo.Check.Readability.Semicolons, []},
{Credo.Check.Readability.SpaceAfterCommas, []},
{Credo.Check.Readability.StringSigils, []},
{Credo.Check.Readability.TrailingBlankLine, []},
{Credo.Check.Readability.TrailingWhiteSpace, []},
{Credo.Check.Readability.UnnecessaryAliasExpansion, []},
{Credo.Check.Readability.VariableNames, []},
# ExSlop — Readability Checks (AI slop detection)
{ExSlop.Check.Readability.NarratorDoc, []},
{ExSlop.Check.Readability.NarratorComment, []},
{ExSlop.Check.Readability.ObviousComment, []},
{ExSlop.Check.Readability.StepComment, []},
{ExSlop.Check.Readability.BoilerplateDocParams, []},
{ExSlop.Check.Readability.DocFalseOnPublicFunction, []},
# Refactoring Opportunities
{Credo.Check.Refactor.Apply, []},
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.MapJoin, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.Nesting, [max_nesting: 2]},
{Credo.Check.Refactor.UnlessWithElse, []},
{Credo.Check.Refactor.WithClauses, []},
# ExSlop — Refactoring Checks (AI slop detection)
{ExSlop.Check.Refactor.FilterNil, []},
{ExSlop.Check.Refactor.RejectNil, []},
{ExSlop.Check.Refactor.ReduceAsMap, []},
{ExSlop.Check.Refactor.MapIntoLiteral, []},
{ExSlop.Check.Refactor.IdentityPassthrough, []},
{ExSlop.Check.Refactor.IdentityMap, []},
{ExSlop.Check.Refactor.CaseTrueFalse, []},
{ExSlop.Check.Refactor.TryRescueWithSafeAlternative, []},
{ExSlop.Check.Refactor.WithIdentityElse, []},
{ExSlop.Check.Refactor.WithIdentityDo, []},
{ExSlop.Check.Refactor.SortThenReverse, []},
{ExSlop.Check.Refactor.StringConcatInReduce, []},
# Warnings
{Credo.Check.Warning.ApplicationConfigInModuleAttribute, []},
{Credo.Check.Warning.BoolOperationOnSameValues, []},
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
{Credo.Check.Warning.IExPry, []},
{Credo.Check.Warning.IoInspect, []},
{Credo.Check.Warning.OperationOnSameValues, []},
{Credo.Check.Warning.OperationWithConstantResult, []},
{Credo.Check.Warning.RaiseInsideRescue, []},
{Credo.Check.Warning.SpecWithStruct, []},
{Credo.Check.Warning.WrongTestFileExtension, []},
{Credo.Check.Warning.UnusedEnumOperation, []},
{Credo.Check.Warning.UnusedFileOperation, []},
{Credo.Check.Warning.UnusedKeywordOperation, []},
{Credo.Check.Warning.UnusedListOperation, []},
{Credo.Check.Warning.UnusedPathOperation, []},
{Credo.Check.Warning.UnusedRegexOperation, []},
{Credo.Check.Warning.UnusedStringOperation, []},
{Credo.Check.Warning.UnusedTupleOperation, []},
{Credo.Check.Warning.UnsafeExec, []},
# ExSlop — Warning Checks (AI slop detection)
{ExSlop.Check.Warning.BlanketRescue, []},
{ExSlop.Check.Warning.RescueWithoutReraise, []},
{ExSlop.Check.Warning.RepoAllThenFilter, []},
{ExSlop.Check.Warning.QueryInEnumMap, []},
{ExSlop.Check.Warning.GenserverAsKvStore, []}
],
disabled: [
# Optional checks disabled for Phoenix projects
{Credo.Check.Readability.Specs, []},
{Credo.Check.Refactor.MapInto, []},
{Credo.Check.Warning.LazyLogging, []},
{Credo.Check.Refactor.AppendSingleItem, []},
{Credo.Check.Refactor.DoubleBooleanNegation, []},
{Credo.Check.Refactor.ModuleDependencies, []},
{Credo.Check.Refactor.NegatedIsNil, []},
{Credo.Check.Refactor.PipeChainStart, []},
{Credo.Check.Refactor.VariableRebinding, []},
{Credo.Check.Warning.LeakyEnvironment, []},
{Credo.Check.Warning.MapGetUnsafePass, []},
{Credo.Check.Warning.MixEnv, []},
{Credo.Check.Warning.UnsafeToAtom, []}
]
}
}
]
}
File: .sobelow-conf
[
verbose: false,
private: false,
skip: false,
router: "",
exit: "low",
format: "txt",
ignore: [],
ignore_files: []
]
The --config flag in the check alias tells Sobelow to use this file. The exit: "low" setting ensures all findings (low, medium, high) cause a non-zero exit code.
File: .doctor.exs
%Doctor.Config{
ignore_modules: [
# Exclude test modules from documentation requirements
~r/.*Test$/,
~r/.*Fixtures$/,
# Exclude generated Phoenix modules (update APP_NAME)
~r/^APP_NAMEWeb.Telemetry$/,
~r/^APP_NAMEWeb.Endpoint$/,
~r/^APP_NAME.DataCase$/,
~r/^APP_NAME.ConnCase$/,
~r/^APP_NAMEWeb.ConnCase$/
],
ignore_paths: [
"test/",
"priv/",
"deps/",
"_build/"
],
# Strict documentation coverage thresholds (80%+)
min_module_doc_coverage: 80,
min_module_spec_coverage: 0,
min_overall_doc_coverage: 80,
min_overall_moduledoc_coverage: 100,
min_overall_spec_coverage: 0,
# Don't raise on failures, just report
raise: false,
# Use full reporter for detailed output
reporter: Doctor.Reporters.Full,
# Don't require @type for structs (can be enabled later)
struct_type_spec_required: false,
# Not an umbrella project
umbrella: false
}
File: .formatter.exs
[
import_deps: [:ecto, :ecto_sql, :phoenix, :credo],
subdirectories: ["priv/*/migrations"],
plugins: [Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
]
File: .env.sample
# APP_NAME Environment Variables Template
# Copy this file to .env and fill in your values
# DO NOT commit .env to version control
# Phoenix Server
PHX_SERVER=true
PHX_HOST=localhost
PORT=4000
# Database
DATABASE_URL=ecto://postgres:postgres@localhost/APP_NAME_dev
POOL_SIZE=10
ECTO_IPV6=false
# Security (generate with: mix phx.gen.secret)
SECRET_KEY_BASE=
# DNS Cluster (optional, for production clustering)
DNS_CLUSTER_QUERY=
# Feature Flags
ENABLE_BETA_FEATURES=false
MAINTENANCE_MODE=false
# Monitoring (optional)
SENTRY_DSN=
HONEYBADGER_API_KEY=
# Mailer Configuration (Development)
# For development, emails are logged by default
MAIL_FROM=noreply@example.com
File: .env.dev
DATABASE_URL=ecto://postgres:postgres@localhost/APP_NAME_dev
SECRET_KEY_BASE=your-dev-secret-key-base-generate-with-mix-phx-gen-secret
File: .env.test
DATABASE_URL=ecto://postgres:postgres@localhost/APP_NAME_test
SECRET_KEY_BASE=test-secret-key-base-minimum-64-characters-for-testing-purposes-only
File: config/runtime.exs
Add this at the top (after import Config):
import Config
# Load .env file for development and test environments
# In production, environment variables should be set by the deployment platform
if config_env() in [:dev, :test] do
env_files = [
".env.#{config_env()}.local",
".env.#{config_env()}",
".env.local",
".env"
]
existing_files = Enum.filter(env_files, &File.exists?/1)
env_vars =
existing_files
|> Enum.reverse()
|> Enum.reduce(%{}, fn file, acc ->
case Dotenvy.source(file) do
{:ok, vars} -> Map.merge(acc, vars)
_ -> acc
end
end)
Enum.each(env_vars, fn {key, value} ->
if is_nil(System.get_env(key)) do
System.put_env(key, value)
end
end)
end
# Rest of your runtime config continues below...
File: lib/APP_NAME_web/endpoint.ex
Add the Tidewave plug before the if code_reloading? do block:
if Code.ensure_loaded?(Tidewave) do
plug Tidewave
end
if code_reloading? do
# ... existing code reloading configuration
File: config/dev.exs
Add LiveView debug configuration for better Tidewave integration:
# Tidewave works best with LiveView debug annotations enabled
config :phoenix_live_view,
debug_heex_annotations: true,
debug_attributes: true
File: config/config.exs
Add at the end of the file (before any import_config):
# Sentry error tracking
config :sentry,
enable_source_code_context: true,
root_source_code_paths: [File.cwd!()],
included_environments: [:prod]
# Attach Sentry to Elixir's Logger so crashes/errors are captured automatically
config :APP_NAME, :logger, [
{:handler, :sentry_handler, Sentry.LoggerHandler, %{config: %{metadata: [:request_id]}}}
]
File: config/runtime.exs
Add after the Dotenvy loading block:
# Sentry error tracking
if sentry_dsn = System.get_env("SENTRY_DSN") do
config :sentry,
dsn: sentry_dsn,
environment_name: config_env()
end
File: lib/APP_NAME_web/endpoint.ex
Add plug Sentry.PlugContext before plug Plug.MethodOverride:
plug Sentry.PlugContext
plug Plug.MethodOverride
File: lib/APP_NAME_web.ex
In the live_view/0 macro, add on_mount Sentry.LiveViewHook inside the quote block:
defp live_view do
quote do
use Phoenix.LiveView
on_mount Sentry.LiveViewHook
unquote(html_helpers())
end
end
File: .gitignore
Add these lines:
# Environment files (keep samples)
.env
.env.local
.env.*.local
!.env.sample
# Dialyzer PLT files
/priv/plts/
# Editor and IDE
.idea/
*.swp
*.swo
.vscode/
mkdir -p priv/plts
After creating all files, run:
# Install dependencies
mix deps.get
# Setup database
mix ecto.setup
# Build assets
mix assets.setup
mix assets.build
# Build Dialyzer PLT (takes 5-10 minutes first time)
mix dialyzer --plt
# Run full quality check
mix check
After running this command, you should have:
Search and replace APP_NAME in these files:
mix.exs (multiple locations).doctor.exs (module ignore patterns)lib/APP_NAME_web/endpoint.ex (Tidewave plug).env.sample.env.dev.env.test# Development
mix phx.server # Start server
iex -S mix phx.server # Start with IEx
# Quality Checks
mix check # Run ALL quality checks (use before commits)
mix precommit # Alias for mix check
mix format # Auto-format code
mix credo --strict # Static analysis
mix doctor # Documentation coverage
mix sobelow --config # Security analysis
mix dialyzer # Type checking
# Testing
mix test # Run all tests
mix test --failed # Re-run failed tests
mix test path/to/test.exs:42 # Run specific test at line
# Database
mix ecto.gen.migration name # Generate migration
mix ecto.migrate # Run migrations
mix ecto.reset # Drop and recreate DB
Req, never HTTPoison, Tesla, or :httpcapp.js or app.css<script> tags in templatesmix check before every commit to catch issues earlyNote: This bootstrap creates a production-ready Phoenix application with comprehensive quality tooling. After setup, always run mix check before committing code.