{"owner":"phoenixframework","repo":"phoenix","hasSkills":true,"totalSkillsCount":2,"totalTokensCount":7176,"categories":["root-instruction","cursor-rule"],"hasMcp":false,"mcpConfig":null,"found":["guides/routing.md",".cursorrules (elixir-phoenix-docker-setup-cursorrules-prompt-fil.mdc)"],"skills":{"guides/routing.md":"# Routing\n\n> ### Requirement {: .tip}\n>\n> This guide expects that you have:\n>\n> * Gone through the [introductory guides](installation.html)\n> * Got a Phoenix application [up and running](up_and_running.html)\n> * Gone through the [request life-cycle guide](request_lifecycle.html)\n\nRouters are the main hubs of Phoenix applications. They match HTTP requests to controller actions, wire up real-time channel handlers, and define a series of pipeline transformations scoped to a set of routes.\n\nThe router file that Phoenix generates, `lib/hello_web/router.ex`, will look something like this one:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  # scope \"/api\", HelloWeb do\n  #   pipe_through :api\n  # end\n\n  # ...\nend\n```\n\nBoth the router and controller module names will be prefixed with the name you gave your application suffixed with `Web`.\n\nThe first line of this module, `use HelloWeb, :router`, simply makes Phoenix router functions available in our particular router.\n\nScopes have their own section in this guide, so we won't spend time on the `scope \"/\", HelloWeb do` block here. The `pipe_through :browser` line will get a full treatment in the \"Pipelines\" section of this guide. For now, you only need to know that pipelines allow a set of plugs to be applied to different sets of routes.\n\nInside the scope block, however, we have our first actual route:\n\n```elixir\nget \"/\", PageController, :home\n```\n\n`get` is a Phoenix macro that corresponds to the HTTP verb GET. Similar macros exist for other HTTP verbs, including POST, PUT, PATCH, DELETE, OPTIONS, CONNECT, TRACE, and HEAD.\n\n> #### Why the macros? {: .info}\n>\n> Phoenix does its best to keep the usage of macros low. You may have noticed, however, that the `Phoenix.Router` relies heavily on macros. Why is that?\n>\n> We use `get`, `post`, `put`, and `delete` to define your routes. We use macros for two purposes:\n>\n>   * They define the routing engine, used on every request, to choose which controller to dispatch the request to. Thanks to macros, Phoenix compiles all of your routes to a huge case-statement with pattern matching rules, which is heavily optimized by the Erlang VM\n>\n>   * For each route you define, we also define metadata to implement `Phoenix.VerifiedRoutes`. As we will soon learn, verified routes allow us to reference any route as if it were a plain looking string, except that it is verified by the compiler to be valid (making it much harder to ship broken links, forms, mails, etc to production)\n>\n> In other words, the router relies on macros to build applications that are faster and safer. Also remember that macros in Elixir are compile-time only, which gives plenty of stability after the code is compiled. As we will learn next, Phoenix also provides introspection for all defined routes via `mix phx.routes`.\n\n## Examining routes\n\nPhoenix provides an excellent tool for investigating routes in an application: `mix phx.routes`.\n\nLet's see how this works. Go to the root of a newly-generated Phoenix application and run `mix phx.routes`. You should see something like the following, generated with all routes you currently have:\n\n```console\n$ mix phx.routes\nGET  /  HelloWeb.PageController :home\n...\n```\n\nThe route above tells us that any HTTP GET request for the root of the application will be handled by the `home` action of the `HelloWeb.PageController`.\n\n## Resources\n\nThe router supports other macros besides those for HTTP verbs like [`get`](`Phoenix.Router.get/3`), [`post`](`Phoenix.Router.post/3`), and [`put`](`Phoenix.Router.put/3`). The most important among them is [`resources`](`Phoenix.Router.resources/4`). Let's add a resource to our `lib/hello_web/router.ex` file like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  get \"/\", PageController, :home\n  resources \"/users\", UserController\n  ...\nend\n```\n\nFor now it doesn't matter that we don't actually have a `HelloWeb.UserController`.\n\nRun `mix phx.routes` once again at the root of your project. You should see something like the following:\n\n```console\n...\nGET     /users           HelloWeb.UserController :index\nGET     /users/:id/edit  HelloWeb.UserController :edit\nGET     /users/new       HelloWeb.UserController :new\nGET     /users/:id       HelloWeb.UserController :show\nPOST    /users           HelloWeb.UserController :create\nPATCH   /users/:id       HelloWeb.UserController :update\nPUT     /users/:id       HelloWeb.UserController :update\nDELETE  /users/:id       HelloWeb.UserController :delete\n...\n```\n\nThis is the standard matrix of HTTP verbs, paths, and controller actions. For a while, this was known as RESTful routes, but most consider this a misnomer nowadays. Let's look at them individually.\n\n- A GET request to `/users` will invoke the `index` action to show all the users.\n- A GET request to `/users/:id/edit` will invoke the `edit` action with an ID to retrieve an individual user from the data store and present the information in a form for editing.\n- A GET request to `/users/new` will invoke the `new` action to present a form for creating a new user.\n- A GET request to `/users/:id` will invoke the `show` action with an id to show an individual user identified by that ID.\n- A POST request to `/users` will invoke the `create` action to save a new user to the data store.\n- A PATCH request to `/users/:id` will invoke the `update` action with an ID to save the updated user to the data store.\n- A PUT request to `/users/:id` will also invoke the `update` action with an ID to save the updated user to the data store.\n- A DELETE request to `/users/:id` will invoke the `delete` action with an ID to remove the individual user from the data store.\n\nIf we don't need all these routes, we can be selective using the `:only` and `:except` options to filter specific actions.\n\nLet's say we have a read-only posts resource. We could define it like this:\n\n```elixir\nresources \"/posts\", PostController, only: [:index, :show]\n```\n\nRunning `mix phx.routes` shows that we now only have the routes to the index and show actions defined.\n\n```console\nGET     /posts      HelloWeb.PostController :index\nGET     /posts/:id  HelloWeb.PostController :show\n```\n\nSimilarly, if we have a comments resource, and we don't want to provide a route to delete one, we could define a route like this.\n\n```elixir\nresources \"/comments\", CommentController, except: [:delete]\n```\n\nRunning `mix phx.routes` now shows that we have all the routes except the DELETE request to the delete action.\n\n```console\nGET    /comments           HelloWeb.CommentController :index\nGET    /comments/:id/edit  HelloWeb.CommentController :edit\nGET    /comments/new       HelloWeb.CommentController :new\nGET    /comments/:id       HelloWeb.CommentController :show\nPOST   /comments           HelloWeb.CommentController :create\nPATCH  /comments/:id       HelloWeb.CommentController :update\nPUT    /comments/:id       HelloWeb.CommentController :update\n```\n\nThe `Phoenix.Router.resources/4` macro describes additional options for customizing resource routes.\n\n## Verified Routes\n\nPhoenix includes `Phoenix.VerifiedRoutes` module which provides compile-time checks of router paths against your router by using the `~p` sigil. For example, you can write paths in controllers, tests, and templates and the compiler will make sure those actually match routes defined in your router.\n\nLet's see it in action. Run `iex -S mix` at the root of the project. We'll define a throwaway example module that builds a couple `~p` route paths.\n\n```elixir\niex> defmodule RouteExample do\n...>   use HelloWeb, :verified_routes\n...>\n...>   def example do\n...>     ~p\"/comments\"\n...>     ~p\"/unknown/123\"\n...>   end\n...> end\nwarning: no route path for HelloWeb.Router matches \"/unknown/123\"\n  iex:5: RouteExample.example/0\n\n{:module, RouteExample, ...}\niex>\n```\n\nNotice how the first call to an existing route, `~p\"/comments\"` gave no warning, but a bad route path `~p\"/unknown/123\"` produced a compiler warning, just as it should. This is significant because it allows us to write otherwise hard-coded paths in our application and the compiler will let us know whenever we write a bad route or change our routing structure.\n\nPhoenix projects are set up out of the box to allow use of verified routes throughout your web layer, including tests. For example in your templates you can render `~p` links:\n\n```heex\n<a href={~p\"/\"}>Welcome Page!</a>\n<a href={~p\"/comments\"}>View Comments</a>\n```\n\nOr in a controller, issue a redirect:\n\n```elixir\nredirect(conn, to: ~p\"/comments/#{comment}\")\n```\n\nUsing `~p` for route paths ensures our application paths and URLs stay up to date with the router definitions. The compiler will catch bugs for us, and let us know when we change routes that are referenced elsewhere in our application.\n\n### More on verified routes\n\nWhat about paths with query strings? You can add query string key values directly, as a keyword list or map of values, for example:\n\n```elixir\n~p\"/users/17?admin=true&active=false\"\n\"/users/17?admin=true&active=false\"\n\n~p\"/users/17?#{[admin: true]}\"\n\"/users/17?admin=true\"\n\n~p\"/users/17?#{%{admin: true}}\"\n\"/users/17?admin=true\"\n```\n\nWhat if we need a full URL instead of a path? Just wrap your path with a call to `Phoenix.VerifiedRoutes.url/1`, which is imported everywhere that `~p` is available:\n\n```elixir\nurl(~p\"/users\")\n\"http://localhost:4000/users\"\n```\n\nThe `url` calls will get the host, port, proxy port, and SSL information needed to construct the full URL from the configuration parameters set for each environment. We'll talk about configuration in more detail in its own guide. For now, you can take a look at `config/dev.exs` file in your own project to see those values.\n\n## Nested resources\n\nIt is also possible to nest resources in a Phoenix router. Let's say we also have a `posts` resource that has a many-to-one relationship with `users`. That is to say, a user can create many posts, and an individual post belongs to only one user. We can represent that by adding a nested route in `lib/hello_web/router.ex` like this:\n\n```elixir\nresources \"/users\", UserController do\n  resources \"/posts\", PostController\nend\n```\n\nWhen we run `mix phx.routes` now, in addition to the routes we saw for `users` above, we get the following set of routes:\n\n```console\n...\nGET     /users/:user_id/posts           HelloWeb.PostController :index\nGET     /users/:user_id/posts/:id/edit  HelloWeb.PostController :edit\nGET     /users/:user_id/posts/new       HelloWeb.PostController :new\nGET     /users/:user_id/posts/:id       HelloWeb.PostController :show\nPOST    /users/:user_id/posts           HelloWeb.PostController :create\nPATCH   /users/:user_id/posts/:id       HelloWeb.PostController :update\nPUT     /users/:user_id/posts/:id       HelloWeb.PostController :update\nDELETE  /users/:user_id/posts/:id       HelloWeb.PostController :delete\n...\n```\n\nWe see that each of these routes scopes the posts to a user ID. For the first one, we will invoke `PostController`'s `index` action, but we will pass in a `user_id`. This implies that we would display all the posts for that individual user only. The same scoping applies for all these routes.\n\nWhen building paths for nested routes, we will need to interpolate the IDs where they belong in route definition. For the following `show` route, `42` is the `user_id`, and `17` is the `post_id`.\n\n```elixir\nuser_id = 42\npost_id = 17\n~p\"/users/#{user_id}/posts/#{post_id}\"\n\"/users/42/posts/17\"\n```\n\nVerified routes also support the `Phoenix.Param` protocol, but we don't need to concern ourselves with Elixir protocols just yet. Just know that once we start building our application with structs like `%User{}` and `%Post{}`, we'll be able to interpolate those data structures directly into our `~p` paths and Phoenix will pluck out the correct fields to use in the route.\n\n```elixir\n~p\"/users/#{user}/posts/#{post}\"\n\"/users/42/posts/17\"\n```\n\nNotice how we didn't need to interpolate `user.id` or `post.id`? This is particularly nice if we decide later we want to make our URLs a little nicer and start using slugs instead. We don't need to change any of our `~p`'s!\n\n## Scoped routes\n\nScopes are a way to group routes under a common path prefix and scoped set of plugs. We might want to do this for admin functionality, APIs, and especially for versioned APIs. Let's say we have user-generated reviews on a site, and that those reviews first need to be approved by an administrator. The semantics of these resources are quite different, and they might not share the same controller. Scopes enable us to segregate these routes.\n\nThe paths to the user-facing reviews would look like a standard resource.\n\n```console\n/reviews\n/reviews/1234\n/reviews/1234/edit\n...\n```\n\nThe administration review paths can be prefixed with `/admin`.\n\n```console\n/admin/reviews\n/admin/reviews/1234\n/admin/reviews/1234/edit\n...\n```\n\nWe accomplish this with a scoped route that sets a path option to `/admin` like this one. We can nest this scope inside another scope, but instead, let's set it by itself at the root, by adding to `lib/hello_web/router.ex` the following:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nWe define a new scope where all routes are prefixed with `/admin` and all controllers are under the `HelloWeb.Admin` namespace.\n\nRunning `mix phx.routes` again, in addition to the previous set of routes we get the following:\n\n```console\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n...\n```\n\nRemember that we wanted both user-facing review routes `/reviews` and the admin ones `/admin/reviews`. If we now include the user-facing reviews in our router under the root scope like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  ...\n  resources \"/reviews\", ReviewController\nend\n\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nand we run `mix phx.routes`, we get output for each scoped route:\n\n```console\n...\nGET     /reviews                 HelloWeb.ReviewController :index\nGET     /reviews/:id/edit        HelloWeb.ReviewController :edit\nGET     /reviews/new             HelloWeb.ReviewController :new\nGET     /reviews/:id             HelloWeb.ReviewController :show\nPOST    /reviews                 HelloWeb.ReviewController :create\nPATCH   /reviews/:id             HelloWeb.ReviewController :update\nPUT     /reviews/:id             HelloWeb.ReviewController :update\nDELETE  /reviews/:id             HelloWeb.ReviewController :delete\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n```\n\nWhat if we had a number of resources that were all handled by admins? We could put all of them inside the same scope like this:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/images\",  ImageController\n  resources \"/reviews\", ReviewController\n  resources \"/users\",   UserController\nend\n```\n\nHere's what `mix phx.routes` tells us:\n\n```console\n...\nGET     /admin/images            HelloWeb.Admin.ImageController :index\nGET     /admin/images/:id/edit   HelloWeb.Admin.ImageController :edit\nGET     /admin/images/new        HelloWeb.Admin.ImageController :new\nGET     /admin/images/:id        HelloWeb.Admin.ImageController :show\nPOST    /admin/images            HelloWeb.Admin.ImageController :create\nPATCH   /admin/images/:id        HelloWeb.Admin.ImageController :update\nPUT     /admin/images/:id        HelloWeb.Admin.ImageController :update\nDELETE  /admin/images/:id        HelloWeb.Admin.ImageController :delete\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\nGET     /admin/users             HelloWeb.Admin.UserController :index\nGET     /admin/users/:id/edit    HelloWeb.Admin.UserController :edit\nGET     /admin/users/new         HelloWeb.Admin.UserController :new\nGET     /admin/users/:id         HelloWeb.Admin.UserController :show\nPOST    /admin/users             HelloWeb.Admin.UserController :create\nPATCH   /admin/users/:id         HelloWeb.Admin.UserController :update\nPUT     /admin/users/:id         HelloWeb.Admin.UserController :update\nDELETE  /admin/users/:id         HelloWeb.Admin.UserController :delete\n```\n\nThis is great, exactly what we want. Note how every route and controller is properly namespaced.\n\nScopes can also be arbitrarily nested, but you should do it carefully as nesting can sometimes make our code confusing and less clear. With that said, suppose that we had a versioned API with resources defined for images, reviews, and users. Then technically, we could set up routes for the versioned API like this:\n\n```elixir\nscope \"/api\", HelloWeb.Api do\n  pipe_through :api\n\n  scope \"/v1\", V1 do\n    resources \"/images\",  ImageController\n    resources \"/reviews\", ReviewController\n    resources \"/users\",   UserController\n  end\nend\n```\n\nYou can run `mix phx.routes` to see how these definitions will look like.\n\nInterestingly, we can use multiple scopes with the same path as long as we are careful not to duplicate routes. The following router is perfectly fine with two scopes defined for the same path:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use Phoenix.Router\n  ...\n  scope \"/\", HelloWeb do\n    pipe_through :browser\n\n    resources \"/users\", UserController\n  end\n\n  scope \"/\", AnotherAppWeb do\n    pipe_through :browser\n\n    resources \"/posts\", PostController\n  end\n  ...\nend\n```\n\nIf we do duplicate a route — which means two routes having the same path — we'll get this familiar warning:\n\n```console\nwarning: this clause cannot match because a previous clause at line 16 always matches\n```\n\n## Pipelines\n\nWe have come quite a long way in this guide without talking about one of the first lines we saw in the router: `pipe_through :browser`. It's time to fix that.\n\nPipelines are a series of plugs that can be attached to specific scopes. If you are not familiar with plugs, we have an [in-depth guide about them](plug.html).\n\nRoutes are defined inside scopes and scopes may pipe through multiple pipelines. Once a route matches, Phoenix invokes all plugs defined in all pipelines associated to that route. For example, accessing `/` will pipe through the `:browser` pipeline, consequently invoking all of its plugs.\n\nPhoenix defines two pipelines by default, `:browser` and `:api`, which can be used for a number of common tasks. In turn we can customize them as well as create new pipelines to meet our needs.\n\n### The `:browser` and `:api` pipelines\n\nAs their names suggest, the `:browser` pipeline prepares for routes which render requests for a browser, and the `:api` pipeline prepares for routes which produce data for an API.\n\nThe `:browser` pipeline has six plugs: The `plug :accepts, [\"html\"]` defines the accepted request format or formats. `:fetch_session`, which, naturally, fetches the session data and makes it available in the connection. `:fetch_live_flash`, which fetches any flash messages from LiveView and merges them with the controller flash messages. Then, the plug `:put_root_layout` will store the root layout for rendering purposes. Later `:protect_from_forgery` and `:put_secure_browser_headers`, protects form posts from cross-site forgery.\n\nCurrently, the `:api` pipeline only defines `plug :accepts, [\"json\"]`.\n\nThe router invokes a pipeline on a route defined within a scope. Routes outside of a scope have no pipelines. Although the use of nested scopes is discouraged (see above the versioned API example), if we call `pipe_through` within a nested scope, the router will invoke all `pipe_through`'s from parent scopes, followed by the nested one.\n\nThose are a lot of words bunched up together. Let's take a look at some examples to untangle their meaning.\n\nHere's another look at the router from a newly generated Phoenix application, this time with the `/api` scope uncommented back in and a route added.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  scope \"/api\", HelloWeb do\n    pipe_through :api\n\n    resources \"/reviews\", ReviewController\n  end\n  # ...\nend\n```\n\nWhen the server accepts a request, the request will always first pass through the plugs in our endpoint, after which it will attempt to match on the path and HTTP verb.\n\nLet's say that the request matches our first route: a GET to `/`. The router will first pipe that request through the `:browser` pipeline - which will fetch the session data, fetch the flash, and execute forgery protection - before it dispatches the request to `PageController`'s `home` action.\n\nConversely, suppose the request matches any of the routes defined by the [`resources/2`](`Phoenix.Router.resources/2`) macro. In that case, the router will pipe it through the `:api` pipeline — which currently only performs content negotiation — before it dispatches further to the correct action of the `HelloWeb.ReviewController`.\n\nIf no route matches, no pipeline is invoked and a 404 error is raised.\n\n### Creating new pipelines\n\nPhoenix allows us to create our own custom pipelines anywhere in the router. To do so, we call the [`pipeline/2`](`Phoenix.Router.pipeline/2`) macro with these arguments: an atom for the name of our new pipeline and a block with all the plugs we want in it.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.Layouts, :root}\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n  end\n\n  pipeline :auth do\n    plug HelloWeb.Authentication\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through [:browser, :auth]\n\n    resources \"/\", ReviewController\n  end\nend\n```\n\nThe above assumes there is a plug called `HelloWeb.Authentication` that performs authentication and is now part of the `:auth` pipeline.\n\nNote that pipelines themselves are plugs, so we can plug a pipeline inside another pipeline. For example, we could rewrite the `auth` pipeline above to automatically invoke `browser`, simplifying the downstream pipeline call:\n\n```elixir\n  pipeline :auth do\n    plug :browser\n    plug :ensure_authenticated_user\n    plug :ensure_user_owns_review\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through :auth\n\n    resources \"/\", ReviewController\n  end\n```\n\n## How to organize my routes?\n\nIn Phoenix, we tend to define several pipelines, that provide specific functionality. For example, the `:browser` and `:api` pipelines are meant to be accessed by specific clients, browsers and http clients respectively.\n\nPerhaps more importantly, it is also very common to define pipelines specific to authentication and authorization. For example, you might have a pipeline that requires all users are authenticated. Another pipeline may enforce only admin users can access certain routes.\n\nOnce your pipelines are defined, you reuse the pipelines in the desired scopes, grouping your routes around their pipelines. For example, going back to our reviews example. Let's say anyone can read a review, but only authenticated users can create them. Your routes could look like this:\n\n```elixir\npipeline :browser do\n  ...\nend\n\npipeline :auth do\n  plug HelloWeb.Authentication\nend\n\nscope \"/\" do\n  pipe_through [:browser]\n\n  get \"/reviews\", PostController, :index\n  get \"/reviews/:id\", PostController, :show\nend\n\nscope \"/\" do\n  pipe_through [:browser, :auth]\n\n  get \"/reviews/new\", PostController, :new\n  post \"/reviews\", PostController, :create\nend\n```\n\nNote in the above how the routes are split across different scopes. While the separation can be confusing at first, it has one big upside: it is very easy to inspect your routes and see all routes that, for example, require authentication and which ones do not. This helps with auditing and making sure your routes have the proper scope.\n\nYou can create as few or as many scopes as you want. Because pipelines are reusable across scopes, they help encapsulate common functionality and you can compose them as necessary on each scope you define.\n\n## Forward\n\nThe `Phoenix.Router.forward/4` macro can be used to send all requests that start with a particular path to a particular plug. Let's say we have a part of our system that is responsible (it could even be a separate application or library) for running jobs in the background, it could have its own web interface for checking the status of the jobs. We can forward to this admin interface using:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\", HelloWeb do\n    ...\n  end\n\n  forward \"/jobs\", BackgroundJob.Plug\nend\n```\n\nThis means that all routes starting with `/jobs` will be sent to the `BackgroundJob.Plug` module. Inside the plug, you can match on subroutes, such as `/pending` and `/active` that shows the status of certain jobs.\n\nWe can even mix the [`forward/4`](`Phoenix.Router.forward/4`) macro with pipelines. If we wanted to ensure that the user was authenticated and was an administrator in order to see the jobs page, we could use the following in our router.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\" do\n    pipe_through [:authenticate_user, :ensure_admin]\n    forward \"/jobs\", BackgroundJob.Plug\n  end\nend\n```\n\nThis means the plugs in the `authenticate_user` and `ensure_admin` pipelines will be called before the `BackgroundJob.Plug` allowing them to send an appropriate response and halt the request accordingly.\n\n`BackgroundJob.Plug` can be implemented as any \"Module Plug\" discussed in the [Plug guide](plug.html). Note though it is not advised to forward to another Phoenix endpoint. This is because plugs defined by your app and the forwarded endpoint would be invoked twice, which may lead to errors.\n\n## Summary\n\nRouting is a big topic, and we have covered a lot of ground here. The important points to take away from this guide are:\n\n- Routes which begin with an HTTP verb name expand to a single clause of the match function.\n- Routes declared with `resources` expand to 8 clauses of the match function.\n- Resources may restrict the number of match function clauses by using the `only:` or `except:` options.\n- Any of these routes may be nested.\n- Any of these routes may be scoped to a given path.\n- Using verified routes with `~p` for compile-time route checks\n",".cursorrules (elixir-phoenix-docker-setup-cursorrules-prompt-fil.mdc)":"---\ndescription: \"Cursor rules for Elixir development with Phoenix and Docker integration.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: Elixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n- When writing code, you will think through any considerations or requirements to make sure we've thought of everything. Only after that do you write the code.\n\n- After a response, provide three follow-up questions worded as if I'm asking you. Format in bold as Q1, Q2, Q3. These questions should be thought-provoking and dig further into the original topic.\n\n- If my response starts with \"VV\", give the most succinct, concise, shortest answer possible.\n\n## Commit Message Guidelines:\n\n- Always suggest a conventional commit message with an optional scope in lowercase. Follow this structure:\n  [optional scope]: [optional body][optional footer(s)]\n\nWhere:\n\n- **type:** One of the following:\n  - `build`: Changes that affect the build system or external dependencies (e.g., Maven, npm)\n  - `chore`: Other changes that don't modify src or test files\n  - `ci`: Changes to our CI configuration files and scripts (e.g., Circle, BrowserStack, SauceLabs)\n  - `docs`: Documentation only changes\n  - `feat`: A new feature\n  - `fix`: A bug fix\n  - `perf`: A code change that improves performance\n  - `refactor`: A code change that neither fixes a bug nor adds a feature\n  - `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n  - `test`: Adding missing tests or correcting existing tests\n\n- **scope (optional):** A noun describing a section of the codebase (e.g., `fluxcd`, `deployment`).\n\n- **description:** A brief summary of the change in present tense.\n\n- **body (optional):** A more detailed explanation of the change.\n\n- **footer (optional):** One or more footers in the following format:\n  - `BREAKING CHANGE: ` (for breaking changes)\n  - `<issue_tracker_id>: ` (e.g., `Jira-123: Fixed bug in authentication`)\n"},"files":{"guides/routing.md":"# Routing\n\n> ### Requirement {: .tip}\n>\n> This guide expects that you have:\n>\n> * Gone through the [introductory guides](installation.html)\n> * Got a Phoenix application [up and running](up_and_running.html)\n> * Gone through the [request life-cycle guide](request_lifecycle.html)\n\nRouters are the main hubs of Phoenix applications. They match HTTP requests to controller actions, wire up real-time channel handlers, and define a series of pipeline transformations scoped to a set of routes.\n\nThe router file that Phoenix generates, `lib/hello_web/router.ex`, will look something like this one:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  # scope \"/api\", HelloWeb do\n  #   pipe_through :api\n  # end\n\n  # ...\nend\n```\n\nBoth the router and controller module names will be prefixed with the name you gave your application suffixed with `Web`.\n\nThe first line of this module, `use HelloWeb, :router`, simply makes Phoenix router functions available in our particular router.\n\nScopes have their own section in this guide, so we won't spend time on the `scope \"/\", HelloWeb do` block here. The `pipe_through :browser` line will get a full treatment in the \"Pipelines\" section of this guide. For now, you only need to know that pipelines allow a set of plugs to be applied to different sets of routes.\n\nInside the scope block, however, we have our first actual route:\n\n```elixir\nget \"/\", PageController, :home\n```\n\n`get` is a Phoenix macro that corresponds to the HTTP verb GET. Similar macros exist for other HTTP verbs, including POST, PUT, PATCH, DELETE, OPTIONS, CONNECT, TRACE, and HEAD.\n\n> #### Why the macros? {: .info}\n>\n> Phoenix does its best to keep the usage of macros low. You may have noticed, however, that the `Phoenix.Router` relies heavily on macros. Why is that?\n>\n> We use `get`, `post`, `put`, and `delete` to define your routes. We use macros for two purposes:\n>\n>   * They define the routing engine, used on every request, to choose which controller to dispatch the request to. Thanks to macros, Phoenix compiles all of your routes to a huge case-statement with pattern matching rules, which is heavily optimized by the Erlang VM\n>\n>   * For each route you define, we also define metadata to implement `Phoenix.VerifiedRoutes`. As we will soon learn, verified routes allow us to reference any route as if it were a plain looking string, except that it is verified by the compiler to be valid (making it much harder to ship broken links, forms, mails, etc to production)\n>\n> In other words, the router relies on macros to build applications that are faster and safer. Also remember that macros in Elixir are compile-time only, which gives plenty of stability after the code is compiled. As we will learn next, Phoenix also provides introspection for all defined routes via `mix phx.routes`.\n\n## Examining routes\n\nPhoenix provides an excellent tool for investigating routes in an application: `mix phx.routes`.\n\nLet's see how this works. Go to the root of a newly-generated Phoenix application and run `mix phx.routes`. You should see something like the following, generated with all routes you currently have:\n\n```console\n$ mix phx.routes\nGET  /  HelloWeb.PageController :home\n...\n```\n\nThe route above tells us that any HTTP GET request for the root of the application will be handled by the `home` action of the `HelloWeb.PageController`.\n\n## Resources\n\nThe router supports other macros besides those for HTTP verbs like [`get`](`Phoenix.Router.get/3`), [`post`](`Phoenix.Router.post/3`), and [`put`](`Phoenix.Router.put/3`). The most important among them is [`resources`](`Phoenix.Router.resources/4`). Let's add a resource to our `lib/hello_web/router.ex` file like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  get \"/\", PageController, :home\n  resources \"/users\", UserController\n  ...\nend\n```\n\nFor now it doesn't matter that we don't actually have a `HelloWeb.UserController`.\n\nRun `mix phx.routes` once again at the root of your project. You should see something like the following:\n\n```console\n...\nGET     /users           HelloWeb.UserController :index\nGET     /users/:id/edit  HelloWeb.UserController :edit\nGET     /users/new       HelloWeb.UserController :new\nGET     /users/:id       HelloWeb.UserController :show\nPOST    /users           HelloWeb.UserController :create\nPATCH   /users/:id       HelloWeb.UserController :update\nPUT     /users/:id       HelloWeb.UserController :update\nDELETE  /users/:id       HelloWeb.UserController :delete\n...\n```\n\nThis is the standard matrix of HTTP verbs, paths, and controller actions. For a while, this was known as RESTful routes, but most consider this a misnomer nowadays. Let's look at them individually.\n\n- A GET request to `/users` will invoke the `index` action to show all the users.\n- A GET request to `/users/:id/edit` will invoke the `edit` action with an ID to retrieve an individual user from the data store and present the information in a form for editing.\n- A GET request to `/users/new` will invoke the `new` action to present a form for creating a new user.\n- A GET request to `/users/:id` will invoke the `show` action with an id to show an individual user identified by that ID.\n- A POST request to `/users` will invoke the `create` action to save a new user to the data store.\n- A PATCH request to `/users/:id` will invoke the `update` action with an ID to save the updated user to the data store.\n- A PUT request to `/users/:id` will also invoke the `update` action with an ID to save the updated user to the data store.\n- A DELETE request to `/users/:id` will invoke the `delete` action with an ID to remove the individual user from the data store.\n\nIf we don't need all these routes, we can be selective using the `:only` and `:except` options to filter specific actions.\n\nLet's say we have a read-only posts resource. We could define it like this:\n\n```elixir\nresources \"/posts\", PostController, only: [:index, :show]\n```\n\nRunning `mix phx.routes` shows that we now only have the routes to the index and show actions defined.\n\n```console\nGET     /posts      HelloWeb.PostController :index\nGET     /posts/:id  HelloWeb.PostController :show\n```\n\nSimilarly, if we have a comments resource, and we don't want to provide a route to delete one, we could define a route like this.\n\n```elixir\nresources \"/comments\", CommentController, except: [:delete]\n```\n\nRunning `mix phx.routes` now shows that we have all the routes except the DELETE request to the delete action.\n\n```console\nGET    /comments           HelloWeb.CommentController :index\nGET    /comments/:id/edit  HelloWeb.CommentController :edit\nGET    /comments/new       HelloWeb.CommentController :new\nGET    /comments/:id       HelloWeb.CommentController :show\nPOST   /comments           HelloWeb.CommentController :create\nPATCH  /comments/:id       HelloWeb.CommentController :update\nPUT    /comments/:id       HelloWeb.CommentController :update\n```\n\nThe `Phoenix.Router.resources/4` macro describes additional options for customizing resource routes.\n\n## Verified Routes\n\nPhoenix includes `Phoenix.VerifiedRoutes` module which provides compile-time checks of router paths against your router by using the `~p` sigil. For example, you can write paths in controllers, tests, and templates and the compiler will make sure those actually match routes defined in your router.\n\nLet's see it in action. Run `iex -S mix` at the root of the project. We'll define a throwaway example module that builds a couple `~p` route paths.\n\n```elixir\niex> defmodule RouteExample do\n...>   use HelloWeb, :verified_routes\n...>\n...>   def example do\n...>     ~p\"/comments\"\n...>     ~p\"/unknown/123\"\n...>   end\n...> end\nwarning: no route path for HelloWeb.Router matches \"/unknown/123\"\n  iex:5: RouteExample.example/0\n\n{:module, RouteExample, ...}\niex>\n```\n\nNotice how the first call to an existing route, `~p\"/comments\"` gave no warning, but a bad route path `~p\"/unknown/123\"` produced a compiler warning, just as it should. This is significant because it allows us to write otherwise hard-coded paths in our application and the compiler will let us know whenever we write a bad route or change our routing structure.\n\nPhoenix projects are set up out of the box to allow use of verified routes throughout your web layer, including tests. For example in your templates you can render `~p` links:\n\n```heex\n<a href={~p\"/\"}>Welcome Page!</a>\n<a href={~p\"/comments\"}>View Comments</a>\n```\n\nOr in a controller, issue a redirect:\n\n```elixir\nredirect(conn, to: ~p\"/comments/#{comment}\")\n```\n\nUsing `~p` for route paths ensures our application paths and URLs stay up to date with the router definitions. The compiler will catch bugs for us, and let us know when we change routes that are referenced elsewhere in our application.\n\n### More on verified routes\n\nWhat about paths with query strings? You can add query string key values directly, as a keyword list or map of values, for example:\n\n```elixir\n~p\"/users/17?admin=true&active=false\"\n\"/users/17?admin=true&active=false\"\n\n~p\"/users/17?#{[admin: true]}\"\n\"/users/17?admin=true\"\n\n~p\"/users/17?#{%{admin: true}}\"\n\"/users/17?admin=true\"\n```\n\nWhat if we need a full URL instead of a path? Just wrap your path with a call to `Phoenix.VerifiedRoutes.url/1`, which is imported everywhere that `~p` is available:\n\n```elixir\nurl(~p\"/users\")\n\"http://localhost:4000/users\"\n```\n\nThe `url` calls will get the host, port, proxy port, and SSL information needed to construct the full URL from the configuration parameters set for each environment. We'll talk about configuration in more detail in its own guide. For now, you can take a look at `config/dev.exs` file in your own project to see those values.\n\n## Nested resources\n\nIt is also possible to nest resources in a Phoenix router. Let's say we also have a `posts` resource that has a many-to-one relationship with `users`. That is to say, a user can create many posts, and an individual post belongs to only one user. We can represent that by adding a nested route in `lib/hello_web/router.ex` like this:\n\n```elixir\nresources \"/users\", UserController do\n  resources \"/posts\", PostController\nend\n```\n\nWhen we run `mix phx.routes` now, in addition to the routes we saw for `users` above, we get the following set of routes:\n\n```console\n...\nGET     /users/:user_id/posts           HelloWeb.PostController :index\nGET     /users/:user_id/posts/:id/edit  HelloWeb.PostController :edit\nGET     /users/:user_id/posts/new       HelloWeb.PostController :new\nGET     /users/:user_id/posts/:id       HelloWeb.PostController :show\nPOST    /users/:user_id/posts           HelloWeb.PostController :create\nPATCH   /users/:user_id/posts/:id       HelloWeb.PostController :update\nPUT     /users/:user_id/posts/:id       HelloWeb.PostController :update\nDELETE  /users/:user_id/posts/:id       HelloWeb.PostController :delete\n...\n```\n\nWe see that each of these routes scopes the posts to a user ID. For the first one, we will invoke `PostController`'s `index` action, but we will pass in a `user_id`. This implies that we would display all the posts for that individual user only. The same scoping applies for all these routes.\n\nWhen building paths for nested routes, we will need to interpolate the IDs where they belong in route definition. For the following `show` route, `42` is the `user_id`, and `17` is the `post_id`.\n\n```elixir\nuser_id = 42\npost_id = 17\n~p\"/users/#{user_id}/posts/#{post_id}\"\n\"/users/42/posts/17\"\n```\n\nVerified routes also support the `Phoenix.Param` protocol, but we don't need to concern ourselves with Elixir protocols just yet. Just know that once we start building our application with structs like `%User{}` and `%Post{}`, we'll be able to interpolate those data structures directly into our `~p` paths and Phoenix will pluck out the correct fields to use in the route.\n\n```elixir\n~p\"/users/#{user}/posts/#{post}\"\n\"/users/42/posts/17\"\n```\n\nNotice how we didn't need to interpolate `user.id` or `post.id`? This is particularly nice if we decide later we want to make our URLs a little nicer and start using slugs instead. We don't need to change any of our `~p`'s!\n\n## Scoped routes\n\nScopes are a way to group routes under a common path prefix and scoped set of plugs. We might want to do this for admin functionality, APIs, and especially for versioned APIs. Let's say we have user-generated reviews on a site, and that those reviews first need to be approved by an administrator. The semantics of these resources are quite different, and they might not share the same controller. Scopes enable us to segregate these routes.\n\nThe paths to the user-facing reviews would look like a standard resource.\n\n```console\n/reviews\n/reviews/1234\n/reviews/1234/edit\n...\n```\n\nThe administration review paths can be prefixed with `/admin`.\n\n```console\n/admin/reviews\n/admin/reviews/1234\n/admin/reviews/1234/edit\n...\n```\n\nWe accomplish this with a scoped route that sets a path option to `/admin` like this one. We can nest this scope inside another scope, but instead, let's set it by itself at the root, by adding to `lib/hello_web/router.ex` the following:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nWe define a new scope where all routes are prefixed with `/admin` and all controllers are under the `HelloWeb.Admin` namespace.\n\nRunning `mix phx.routes` again, in addition to the previous set of routes we get the following:\n\n```console\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n...\n```\n\nRemember that we wanted both user-facing review routes `/reviews` and the admin ones `/admin/reviews`. If we now include the user-facing reviews in our router under the root scope like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  ...\n  resources \"/reviews\", ReviewController\nend\n\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nand we run `mix phx.routes`, we get output for each scoped route:\n\n```console\n...\nGET     /reviews                 HelloWeb.ReviewController :index\nGET     /reviews/:id/edit        HelloWeb.ReviewController :edit\nGET     /reviews/new             HelloWeb.ReviewController :new\nGET     /reviews/:id             HelloWeb.ReviewController :show\nPOST    /reviews                 HelloWeb.ReviewController :create\nPATCH   /reviews/:id             HelloWeb.ReviewController :update\nPUT     /reviews/:id             HelloWeb.ReviewController :update\nDELETE  /reviews/:id             HelloWeb.ReviewController :delete\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n```\n\nWhat if we had a number of resources that were all handled by admins? We could put all of them inside the same scope like this:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/images\",  ImageController\n  resources \"/reviews\", ReviewController\n  resources \"/users\",   UserController\nend\n```\n\nHere's what `mix phx.routes` tells us:\n\n```console\n...\nGET     /admin/images            HelloWeb.Admin.ImageController :index\nGET     /admin/images/:id/edit   HelloWeb.Admin.ImageController :edit\nGET     /admin/images/new        HelloWeb.Admin.ImageController :new\nGET     /admin/images/:id        HelloWeb.Admin.ImageController :show\nPOST    /admin/images            HelloWeb.Admin.ImageController :create\nPATCH   /admin/images/:id        HelloWeb.Admin.ImageController :update\nPUT     /admin/images/:id        HelloWeb.Admin.ImageController :update\nDELETE  /admin/images/:id        HelloWeb.Admin.ImageController :delete\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\nGET     /admin/users             HelloWeb.Admin.UserController :index\nGET     /admin/users/:id/edit    HelloWeb.Admin.UserController :edit\nGET     /admin/users/new         HelloWeb.Admin.UserController :new\nGET     /admin/users/:id         HelloWeb.Admin.UserController :show\nPOST    /admin/users             HelloWeb.Admin.UserController :create\nPATCH   /admin/users/:id         HelloWeb.Admin.UserController :update\nPUT     /admin/users/:id         HelloWeb.Admin.UserController :update\nDELETE  /admin/users/:id         HelloWeb.Admin.UserController :delete\n```\n\nThis is great, exactly what we want. Note how every route and controller is properly namespaced.\n\nScopes can also be arbitrarily nested, but you should do it carefully as nesting can sometimes make our code confusing and less clear. With that said, suppose that we had a versioned API with resources defined for images, reviews, and users. Then technically, we could set up routes for the versioned API like this:\n\n```elixir\nscope \"/api\", HelloWeb.Api do\n  pipe_through :api\n\n  scope \"/v1\", V1 do\n    resources \"/images\",  ImageController\n    resources \"/reviews\", ReviewController\n    resources \"/users\",   UserController\n  end\nend\n```\n\nYou can run `mix phx.routes` to see how these definitions will look like.\n\nInterestingly, we can use multiple scopes with the same path as long as we are careful not to duplicate routes. The following router is perfectly fine with two scopes defined for the same path:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use Phoenix.Router\n  ...\n  scope \"/\", HelloWeb do\n    pipe_through :browser\n\n    resources \"/users\", UserController\n  end\n\n  scope \"/\", AnotherAppWeb do\n    pipe_through :browser\n\n    resources \"/posts\", PostController\n  end\n  ...\nend\n```\n\nIf we do duplicate a route — which means two routes having the same path — we'll get this familiar warning:\n\n```console\nwarning: this clause cannot match because a previous clause at line 16 always matches\n```\n\n## Pipelines\n\nWe have come quite a long way in this guide without talking about one of the first lines we saw in the router: `pipe_through :browser`. It's time to fix that.\n\nPipelines are a series of plugs that can be attached to specific scopes. If you are not familiar with plugs, we have an [in-depth guide about them](plug.html).\n\nRoutes are defined inside scopes and scopes may pipe through multiple pipelines. Once a route matches, Phoenix invokes all plugs defined in all pipelines associated to that route. For example, accessing `/` will pipe through the `:browser` pipeline, consequently invoking all of its plugs.\n\nPhoenix defines two pipelines by default, `:browser` and `:api`, which can be used for a number of common tasks. In turn we can customize them as well as create new pipelines to meet our needs.\n\n### The `:browser` and `:api` pipelines\n\nAs their names suggest, the `:browser` pipeline prepares for routes which render requests for a browser, and the `:api` pipeline prepares for routes which produce data for an API.\n\nThe `:browser` pipeline has six plugs: The `plug :accepts, [\"html\"]` defines the accepted request format or formats. `:fetch_session`, which, naturally, fetches the session data and makes it available in the connection. `:fetch_live_flash`, which fetches any flash messages from LiveView and merges them with the controller flash messages. Then, the plug `:put_root_layout` will store the root layout for rendering purposes. Later `:protect_from_forgery` and `:put_secure_browser_headers`, protects form posts from cross-site forgery.\n\nCurrently, the `:api` pipeline only defines `plug :accepts, [\"json\"]`.\n\nThe router invokes a pipeline on a route defined within a scope. Routes outside of a scope have no pipelines. Although the use of nested scopes is discouraged (see above the versioned API example), if we call `pipe_through` within a nested scope, the router will invoke all `pipe_through`'s from parent scopes, followed by the nested one.\n\nThose are a lot of words bunched up together. Let's take a look at some examples to untangle their meaning.\n\nHere's another look at the router from a newly generated Phoenix application, this time with the `/api` scope uncommented back in and a route added.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  scope \"/api\", HelloWeb do\n    pipe_through :api\n\n    resources \"/reviews\", ReviewController\n  end\n  # ...\nend\n```\n\nWhen the server accepts a request, the request will always first pass through the plugs in our endpoint, after which it will attempt to match on the path and HTTP verb.\n\nLet's say that the request matches our first route: a GET to `/`. The router will first pipe that request through the `:browser` pipeline - which will fetch the session data, fetch the flash, and execute forgery protection - before it dispatches the request to `PageController`'s `home` action.\n\nConversely, suppose the request matches any of the routes defined by the [`resources/2`](`Phoenix.Router.resources/2`) macro. In that case, the router will pipe it through the `:api` pipeline — which currently only performs content negotiation — before it dispatches further to the correct action of the `HelloWeb.ReviewController`.\n\nIf no route matches, no pipeline is invoked and a 404 error is raised.\n\n### Creating new pipelines\n\nPhoenix allows us to create our own custom pipelines anywhere in the router. To do so, we call the [`pipeline/2`](`Phoenix.Router.pipeline/2`) macro with these arguments: an atom for the name of our new pipeline and a block with all the plugs we want in it.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.Layouts, :root}\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n  end\n\n  pipeline :auth do\n    plug HelloWeb.Authentication\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through [:browser, :auth]\n\n    resources \"/\", ReviewController\n  end\nend\n```\n\nThe above assumes there is a plug called `HelloWeb.Authentication` that performs authentication and is now part of the `:auth` pipeline.\n\nNote that pipelines themselves are plugs, so we can plug a pipeline inside another pipeline. For example, we could rewrite the `auth` pipeline above to automatically invoke `browser`, simplifying the downstream pipeline call:\n\n```elixir\n  pipeline :auth do\n    plug :browser\n    plug :ensure_authenticated_user\n    plug :ensure_user_owns_review\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through :auth\n\n    resources \"/\", ReviewController\n  end\n```\n\n## How to organize my routes?\n\nIn Phoenix, we tend to define several pipelines, that provide specific functionality. For example, the `:browser` and `:api` pipelines are meant to be accessed by specific clients, browsers and http clients respectively.\n\nPerhaps more importantly, it is also very common to define pipelines specific to authentication and authorization. For example, you might have a pipeline that requires all users are authenticated. Another pipeline may enforce only admin users can access certain routes.\n\nOnce your pipelines are defined, you reuse the pipelines in the desired scopes, grouping your routes around their pipelines. For example, going back to our reviews example. Let's say anyone can read a review, but only authenticated users can create them. Your routes could look like this:\n\n```elixir\npipeline :browser do\n  ...\nend\n\npipeline :auth do\n  plug HelloWeb.Authentication\nend\n\nscope \"/\" do\n  pipe_through [:browser]\n\n  get \"/reviews\", PostController, :index\n  get \"/reviews/:id\", PostController, :show\nend\n\nscope \"/\" do\n  pipe_through [:browser, :auth]\n\n  get \"/reviews/new\", PostController, :new\n  post \"/reviews\", PostController, :create\nend\n```\n\nNote in the above how the routes are split across different scopes. While the separation can be confusing at first, it has one big upside: it is very easy to inspect your routes and see all routes that, for example, require authentication and which ones do not. This helps with auditing and making sure your routes have the proper scope.\n\nYou can create as few or as many scopes as you want. Because pipelines are reusable across scopes, they help encapsulate common functionality and you can compose them as necessary on each scope you define.\n\n## Forward\n\nThe `Phoenix.Router.forward/4` macro can be used to send all requests that start with a particular path to a particular plug. Let's say we have a part of our system that is responsible (it could even be a separate application or library) for running jobs in the background, it could have its own web interface for checking the status of the jobs. We can forward to this admin interface using:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\", HelloWeb do\n    ...\n  end\n\n  forward \"/jobs\", BackgroundJob.Plug\nend\n```\n\nThis means that all routes starting with `/jobs` will be sent to the `BackgroundJob.Plug` module. Inside the plug, you can match on subroutes, such as `/pending` and `/active` that shows the status of certain jobs.\n\nWe can even mix the [`forward/4`](`Phoenix.Router.forward/4`) macro with pipelines. If we wanted to ensure that the user was authenticated and was an administrator in order to see the jobs page, we could use the following in our router.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\" do\n    pipe_through [:authenticate_user, :ensure_admin]\n    forward \"/jobs\", BackgroundJob.Plug\n  end\nend\n```\n\nThis means the plugs in the `authenticate_user` and `ensure_admin` pipelines will be called before the `BackgroundJob.Plug` allowing them to send an appropriate response and halt the request accordingly.\n\n`BackgroundJob.Plug` can be implemented as any \"Module Plug\" discussed in the [Plug guide](plug.html). Note though it is not advised to forward to another Phoenix endpoint. This is because plugs defined by your app and the forwarded endpoint would be invoked twice, which may lead to errors.\n\n## Summary\n\nRouting is a big topic, and we have covered a lot of ground here. The important points to take away from this guide are:\n\n- Routes which begin with an HTTP verb name expand to a single clause of the match function.\n- Routes declared with `resources` expand to 8 clauses of the match function.\n- Resources may restrict the number of match function clauses by using the `only:` or `except:` options.\n- Any of these routes may be nested.\n- Any of these routes may be scoped to a given path.\n- Using verified routes with `~p` for compile-time route checks\n",".cursorrules (elixir-phoenix-docker-setup-cursorrules-prompt-fil.mdc)":"---\ndescription: \"Cursor rules for Elixir development with Phoenix and Docker integration.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: Elixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n- When writing code, you will think through any considerations or requirements to make sure we've thought of everything. Only after that do you write the code.\n\n- After a response, provide three follow-up questions worded as if I'm asking you. Format in bold as Q1, Q2, Q3. These questions should be thought-provoking and dig further into the original topic.\n\n- If my response starts with \"VV\", give the most succinct, concise, shortest answer possible.\n\n## Commit Message Guidelines:\n\n- Always suggest a conventional commit message with an optional scope in lowercase. Follow this structure:\n  [optional scope]: [optional body][optional footer(s)]\n\nWhere:\n\n- **type:** One of the following:\n  - `build`: Changes that affect the build system or external dependencies (e.g., Maven, npm)\n  - `chore`: Other changes that don't modify src or test files\n  - `ci`: Changes to our CI configuration files and scripts (e.g., Circle, BrowserStack, SauceLabs)\n  - `docs`: Documentation only changes\n  - `feat`: A new feature\n  - `fix`: A bug fix\n  - `perf`: A code change that improves performance\n  - `refactor`: A code change that neither fixes a bug nor adds a feature\n  - `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n  - `test`: Adding missing tests or correcting existing tests\n\n- **scope (optional):** A noun describing a section of the codebase (e.g., `fluxcd`, `deployment`).\n\n- **description:** A brief summary of the change in present tense.\n\n- **body (optional):** A more detailed explanation of the change.\n\n- **footer (optional):** One or more footers in the following format:\n  - `BREAKING CHANGE: ` (for breaking changes)\n  - `<issue_tracker_id>: ` (e.g., `Jira-123: Fixed bug in authentication`)\n"},"items":[{"name":"routing.md","path":"guides/routing.md","rawUrl":"https://raw.githubusercontent.com/phoenixframework/phoenix/HEAD/guides/routing.md","title":"guides - Multi-Agent Routing & Delegation Matrix","category":"root-instruction","format":"markdown","content":"# Routing\n\n> ### Requirement {: .tip}\n>\n> This guide expects that you have:\n>\n> * Gone through the [introductory guides](installation.html)\n> * Got a Phoenix application [up and running](up_and_running.html)\n> * Gone through the [request life-cycle guide](request_lifecycle.html)\n\nRouters are the main hubs of Phoenix applications. They match HTTP requests to controller actions, wire up real-time channel handlers, and define a series of pipeline transformations scoped to a set of routes.\n\nThe router file that Phoenix generates, `lib/hello_web/router.ex`, will look something like this one:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  # scope \"/api\", HelloWeb do\n  #   pipe_through :api\n  # end\n\n  # ...\nend\n```\n\nBoth the router and controller module names will be prefixed with the name you gave your application suffixed with `Web`.\n\nThe first line of this module, `use HelloWeb, :router`, simply makes Phoenix router functions available in our particular router.\n\nScopes have their own section in this guide, so we won't spend time on the `scope \"/\", HelloWeb do` block here. The `pipe_through :browser` line will get a full treatment in the \"Pipelines\" section of this guide. For now, you only need to know that pipelines allow a set of plugs to be applied to different sets of routes.\n\nInside the scope block, however, we have our first actual route:\n\n```elixir\nget \"/\", PageController, :home\n```\n\n`get` is a Phoenix macro that corresponds to the HTTP verb GET. Similar macros exist for other HTTP verbs, including POST, PUT, PATCH, DELETE, OPTIONS, CONNECT, TRACE, and HEAD.\n\n> #### Why the macros? {: .info}\n>\n> Phoenix does its best to keep the usage of macros low. You may have noticed, however, that the `Phoenix.Router` relies heavily on macros. Why is that?\n>\n> We use `get`, `post`, `put`, and `delete` to define your routes. We use macros for two purposes:\n>\n>   * They define the routing engine, used on every request, to choose which controller to dispatch the request to. Thanks to macros, Phoenix compiles all of your routes to a huge case-statement with pattern matching rules, which is heavily optimized by the Erlang VM\n>\n>   * For each route you define, we also define metadata to implement `Phoenix.VerifiedRoutes`. As we will soon learn, verified routes allow us to reference any route as if it were a plain looking string, except that it is verified by the compiler to be valid (making it much harder to ship broken links, forms, mails, etc to production)\n>\n> In other words, the router relies on macros to build applications that are faster and safer. Also remember that macros in Elixir are compile-time only, which gives plenty of stability after the code is compiled. As we will learn next, Phoenix also provides introspection for all defined routes via `mix phx.routes`.\n\n## Examining routes\n\nPhoenix provides an excellent tool for investigating routes in an application: `mix phx.routes`.\n\nLet's see how this works. Go to the root of a newly-generated Phoenix application and run `mix phx.routes`. You should see something like the following, generated with all routes you currently have:\n\n```console\n$ mix phx.routes\nGET  /  HelloWeb.PageController :home\n...\n```\n\nThe route above tells us that any HTTP GET request for the root of the application will be handled by the `home` action of the `HelloWeb.PageController`.\n\n## Resources\n\nThe router supports other macros besides those for HTTP verbs like [`get`](`Phoenix.Router.get/3`), [`post`](`Phoenix.Router.post/3`), and [`put`](`Phoenix.Router.put/3`). The most important among them is [`resources`](`Phoenix.Router.resources/4`). Let's add a resource to our `lib/hello_web/router.ex` file like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  get \"/\", PageController, :home\n  resources \"/users\", UserController\n  ...\nend\n```\n\nFor now it doesn't matter that we don't actually have a `HelloWeb.UserController`.\n\nRun `mix phx.routes` once again at the root of your project. You should see something like the following:\n\n```console\n...\nGET     /users           HelloWeb.UserController :index\nGET     /users/:id/edit  HelloWeb.UserController :edit\nGET     /users/new       HelloWeb.UserController :new\nGET     /users/:id       HelloWeb.UserController :show\nPOST    /users           HelloWeb.UserController :create\nPATCH   /users/:id       HelloWeb.UserController :update\nPUT     /users/:id       HelloWeb.UserController :update\nDELETE  /users/:id       HelloWeb.UserController :delete\n...\n```\n\nThis is the standard matrix of HTTP verbs, paths, and controller actions. For a while, this was known as RESTful routes, but most consider this a misnomer nowadays. Let's look at them individually.\n\n- A GET request to `/users` will invoke the `index` action to show all the users.\n- A GET request to `/users/:id/edit` will invoke the `edit` action with an ID to retrieve an individual user from the data store and present the information in a form for editing.\n- A GET request to `/users/new` will invoke the `new` action to present a form for creating a new user.\n- A GET request to `/users/:id` will invoke the `show` action with an id to show an individual user identified by that ID.\n- A POST request to `/users` will invoke the `create` action to save a new user to the data store.\n- A PATCH request to `/users/:id` will invoke the `update` action with an ID to save the updated user to the data store.\n- A PUT request to `/users/:id` will also invoke the `update` action with an ID to save the updated user to the data store.\n- A DELETE request to `/users/:id` will invoke the `delete` action with an ID to remove the individual user from the data store.\n\nIf we don't need all these routes, we can be selective using the `:only` and `:except` options to filter specific actions.\n\nLet's say we have a read-only posts resource. We could define it like this:\n\n```elixir\nresources \"/posts\", PostController, only: [:index, :show]\n```\n\nRunning `mix phx.routes` shows that we now only have the routes to the index and show actions defined.\n\n```console\nGET     /posts      HelloWeb.PostController :index\nGET     /posts/:id  HelloWeb.PostController :show\n```\n\nSimilarly, if we have a comments resource, and we don't want to provide a route to delete one, we could define a route like this.\n\n```elixir\nresources \"/comments\", CommentController, except: [:delete]\n```\n\nRunning `mix phx.routes` now shows that we have all the routes except the DELETE request to the delete action.\n\n```console\nGET    /comments           HelloWeb.CommentController :index\nGET    /comments/:id/edit  HelloWeb.CommentController :edit\nGET    /comments/new       HelloWeb.CommentController :new\nGET    /comments/:id       HelloWeb.CommentController :show\nPOST   /comments           HelloWeb.CommentController :create\nPATCH  /comments/:id       HelloWeb.CommentController :update\nPUT    /comments/:id       HelloWeb.CommentController :update\n```\n\nThe `Phoenix.Router.resources/4` macro describes additional options for customizing resource routes.\n\n## Verified Routes\n\nPhoenix includes `Phoenix.VerifiedRoutes` module which provides compile-time checks of router paths against your router by using the `~p` sigil. For example, you can write paths in controllers, tests, and templates and the compiler will make sure those actually match routes defined in your router.\n\nLet's see it in action. Run `iex -S mix` at the root of the project. We'll define a throwaway example module that builds a couple `~p` route paths.\n\n```elixir\niex> defmodule RouteExample do\n...>   use HelloWeb, :verified_routes\n...>\n...>   def example do\n...>     ~p\"/comments\"\n...>     ~p\"/unknown/123\"\n...>   end\n...> end\nwarning: no route path for HelloWeb.Router matches \"/unknown/123\"\n  iex:5: RouteExample.example/0\n\n{:module, RouteExample, ...}\niex>\n```\n\nNotice how the first call to an existing route, `~p\"/comments\"` gave no warning, but a bad route path `~p\"/unknown/123\"` produced a compiler warning, just as it should. This is significant because it allows us to write otherwise hard-coded paths in our application and the compiler will let us know whenever we write a bad route or change our routing structure.\n\nPhoenix projects are set up out of the box to allow use of verified routes throughout your web layer, including tests. For example in your templates you can render `~p` links:\n\n```heex\n<a href={~p\"/\"}>Welcome Page!</a>\n<a href={~p\"/comments\"}>View Comments</a>\n```\n\nOr in a controller, issue a redirect:\n\n```elixir\nredirect(conn, to: ~p\"/comments/#{comment}\")\n```\n\nUsing `~p` for route paths ensures our application paths and URLs stay up to date with the router definitions. The compiler will catch bugs for us, and let us know when we change routes that are referenced elsewhere in our application.\n\n### More on verified routes\n\nWhat about paths with query strings? You can add query string key values directly, as a keyword list or map of values, for example:\n\n```elixir\n~p\"/users/17?admin=true&active=false\"\n\"/users/17?admin=true&active=false\"\n\n~p\"/users/17?#{[admin: true]}\"\n\"/users/17?admin=true\"\n\n~p\"/users/17?#{%{admin: true}}\"\n\"/users/17?admin=true\"\n```\n\nWhat if we need a full URL instead of a path? Just wrap your path with a call to `Phoenix.VerifiedRoutes.url/1`, which is imported everywhere that `~p` is available:\n\n```elixir\nurl(~p\"/users\")\n\"http://localhost:4000/users\"\n```\n\nThe `url` calls will get the host, port, proxy port, and SSL information needed to construct the full URL from the configuration parameters set for each environment. We'll talk about configuration in more detail in its own guide. For now, you can take a look at `config/dev.exs` file in your own project to see those values.\n\n## Nested resources\n\nIt is also possible to nest resources in a Phoenix router. Let's say we also have a `posts` resource that has a many-to-one relationship with `users`. That is to say, a user can create many posts, and an individual post belongs to only one user. We can represent that by adding a nested route in `lib/hello_web/router.ex` like this:\n\n```elixir\nresources \"/users\", UserController do\n  resources \"/posts\", PostController\nend\n```\n\nWhen we run `mix phx.routes` now, in addition to the routes we saw for `users` above, we get the following set of routes:\n\n```console\n...\nGET     /users/:user_id/posts           HelloWeb.PostController :index\nGET     /users/:user_id/posts/:id/edit  HelloWeb.PostController :edit\nGET     /users/:user_id/posts/new       HelloWeb.PostController :new\nGET     /users/:user_id/posts/:id       HelloWeb.PostController :show\nPOST    /users/:user_id/posts           HelloWeb.PostController :create\nPATCH   /users/:user_id/posts/:id       HelloWeb.PostController :update\nPUT     /users/:user_id/posts/:id       HelloWeb.PostController :update\nDELETE  /users/:user_id/posts/:id       HelloWeb.PostController :delete\n...\n```\n\nWe see that each of these routes scopes the posts to a user ID. For the first one, we will invoke `PostController`'s `index` action, but we will pass in a `user_id`. This implies that we would display all the posts for that individual user only. The same scoping applies for all these routes.\n\nWhen building paths for nested routes, we will need to interpolate the IDs where they belong in route definition. For the following `show` route, `42` is the `user_id`, and `17` is the `post_id`.\n\n```elixir\nuser_id = 42\npost_id = 17\n~p\"/users/#{user_id}/posts/#{post_id}\"\n\"/users/42/posts/17\"\n```\n\nVerified routes also support the `Phoenix.Param` protocol, but we don't need to concern ourselves with Elixir protocols just yet. Just know that once we start building our application with structs like `%User{}` and `%Post{}`, we'll be able to interpolate those data structures directly into our `~p` paths and Phoenix will pluck out the correct fields to use in the route.\n\n```elixir\n~p\"/users/#{user}/posts/#{post}\"\n\"/users/42/posts/17\"\n```\n\nNotice how we didn't need to interpolate `user.id` or `post.id`? This is particularly nice if we decide later we want to make our URLs a little nicer and start using slugs instead. We don't need to change any of our `~p`'s!\n\n## Scoped routes\n\nScopes are a way to group routes under a common path prefix and scoped set of plugs. We might want to do this for admin functionality, APIs, and especially for versioned APIs. Let's say we have user-generated reviews on a site, and that those reviews first need to be approved by an administrator. The semantics of these resources are quite different, and they might not share the same controller. Scopes enable us to segregate these routes.\n\nThe paths to the user-facing reviews would look like a standard resource.\n\n```console\n/reviews\n/reviews/1234\n/reviews/1234/edit\n...\n```\n\nThe administration review paths can be prefixed with `/admin`.\n\n```console\n/admin/reviews\n/admin/reviews/1234\n/admin/reviews/1234/edit\n...\n```\n\nWe accomplish this with a scoped route that sets a path option to `/admin` like this one. We can nest this scope inside another scope, but instead, let's set it by itself at the root, by adding to `lib/hello_web/router.ex` the following:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nWe define a new scope where all routes are prefixed with `/admin` and all controllers are under the `HelloWeb.Admin` namespace.\n\nRunning `mix phx.routes` again, in addition to the previous set of routes we get the following:\n\n```console\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n...\n```\n\nRemember that we wanted both user-facing review routes `/reviews` and the admin ones `/admin/reviews`. If we now include the user-facing reviews in our router under the root scope like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  ...\n  resources \"/reviews\", ReviewController\nend\n\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nand we run `mix phx.routes`, we get output for each scoped route:\n\n```console\n...\nGET     /reviews                 HelloWeb.ReviewController :index\nGET     /reviews/:id/edit        HelloWeb.ReviewController :edit\nGET     /reviews/new             HelloWeb.ReviewController :new\nGET     /reviews/:id             HelloWeb.ReviewController :show\nPOST    /reviews                 HelloWeb.ReviewController :create\nPATCH   /reviews/:id             HelloWeb.ReviewController :update\nPUT     /reviews/:id             HelloWeb.ReviewController :update\nDELETE  /reviews/:id             HelloWeb.ReviewController :delete\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n```\n\nWhat if we had a number of resources that were all handled by admins? We could put all of them inside the same scope like this:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/images\",  ImageController\n  resources \"/reviews\", ReviewController\n  resources \"/users\",   UserController\nend\n```\n\nHere's what `mix phx.routes` tells us:\n\n```console\n...\nGET     /admin/images            HelloWeb.Admin.ImageController :index\nGET     /admin/images/:id/edit   HelloWeb.Admin.ImageController :edit\nGET     /admin/images/new        HelloWeb.Admin.ImageController :new\nGET     /admin/images/:id        HelloWeb.Admin.ImageController :show\nPOST    /admin/images            HelloWeb.Admin.ImageController :create\nPATCH   /admin/images/:id        HelloWeb.Admin.ImageController :update\nPUT     /admin/images/:id        HelloWeb.Admin.ImageController :update\nDELETE  /admin/images/:id        HelloWeb.Admin.ImageController :delete\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\nGET     /admin/users             HelloWeb.Admin.UserController :index\nGET     /admin/users/:id/edit    HelloWeb.Admin.UserController :edit\nGET     /admin/users/new         HelloWeb.Admin.UserController :new\nGET     /admin/users/:id         HelloWeb.Admin.UserController :show\nPOST    /admin/users             HelloWeb.Admin.UserController :create\nPATCH   /admin/users/:id         HelloWeb.Admin.UserController :update\nPUT     /admin/users/:id         HelloWeb.Admin.UserController :update\nDELETE  /admin/users/:id         HelloWeb.Admin.UserController :delete\n```\n\nThis is great, exactly what we want. Note how every route and controller is properly namespaced.\n\nScopes can also be arbitrarily nested, but you should do it carefully as nesting can sometimes make our code confusing and less clear. With that said, suppose that we had a versioned API with resources defined for images, reviews, and users. Then technically, we could set up routes for the versioned API like this:\n\n```elixir\nscope \"/api\", HelloWeb.Api do\n  pipe_through :api\n\n  scope \"/v1\", V1 do\n    resources \"/images\",  ImageController\n    resources \"/reviews\", ReviewController\n    resources \"/users\",   UserController\n  end\nend\n```\n\nYou can run `mix phx.routes` to see how these definitions will look like.\n\nInterestingly, we can use multiple scopes with the same path as long as we are careful not to duplicate routes. The following router is perfectly fine with two scopes defined for the same path:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use Phoenix.Router\n  ...\n  scope \"/\", HelloWeb do\n    pipe_through :browser\n\n    resources \"/users\", UserController\n  end\n\n  scope \"/\", AnotherAppWeb do\n    pipe_through :browser\n\n    resources \"/posts\", PostController\n  end\n  ...\nend\n```\n\nIf we do duplicate a route — which means two routes having the same path — we'll get this familiar warning:\n\n```console\nwarning: this clause cannot match because a previous clause at line 16 always matches\n```\n\n## Pipelines\n\nWe have come quite a long way in this guide without talking about one of the first lines we saw in the router: `pipe_through :browser`. It's time to fix that.\n\nPipelines are a series of plugs that can be attached to specific scopes. If you are not familiar with plugs, we have an [in-depth guide about them](plug.html).\n\nRoutes are defined inside scopes and scopes may pipe through multiple pipelines. Once a route matches, Phoenix invokes all plugs defined in all pipelines associated to that route. For example, accessing `/` will pipe through the `:browser` pipeline, consequently invoking all of its plugs.\n\nPhoenix defines two pipelines by default, `:browser` and `:api`, which can be used for a number of common tasks. In turn we can customize them as well as create new pipelines to meet our needs.\n\n### The `:browser` and `:api` pipelines\n\nAs their names suggest, the `:browser` pipeline prepares for routes which render requests for a browser, and the `:api` pipeline prepares for routes which produce data for an API.\n\nThe `:browser` pipeline has six plugs: The `plug :accepts, [\"html\"]` defines the accepted request format or formats. `:fetch_session`, which, naturally, fetches the session data and makes it available in the connection. `:fetch_live_flash`, which fetches any flash messages from LiveView and merges them with the controller flash messages. Then, the plug `:put_root_layout` will store the root layout for rendering purposes. Later `:protect_from_forgery` and `:put_secure_browser_headers`, protects form posts from cross-site forgery.\n\nCurrently, the `:api` pipeline only defines `plug :accepts, [\"json\"]`.\n\nThe router invokes a pipeline on a route defined within a scope. Routes outside of a scope have no pipelines. Although the use of nested scopes is discouraged (see above the versioned API example), if we call `pipe_through` within a nested scope, the router will invoke all `pipe_through`'s from parent scopes, followed by the nested one.\n\nThose are a lot of words bunched up together. Let's take a look at some examples to untangle their meaning.\n\nHere's another look at the router from a newly generated Phoenix application, this time with the `/api` scope uncommented back in and a route added.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  scope \"/api\", HelloWeb do\n    pipe_through :api\n\n    resources \"/reviews\", ReviewController\n  end\n  # ...\nend\n```\n\nWhen the server accepts a request, the request will always first pass through the plugs in our endpoint, after which it will attempt to match on the path and HTTP verb.\n\nLet's say that the request matches our first route: a GET to `/`. The router will first pipe that request through the `:browser` pipeline - which will fetch the session data, fetch the flash, and execute forgery protection - before it dispatches the request to `PageController`'s `home` action.\n\nConversely, suppose the request matches any of the routes defined by the [`resources/2`](`Phoenix.Router.resources/2`) macro. In that case, the router will pipe it through the `:api` pipeline — which currently only performs content negotiation — before it dispatches further to the correct action of the `HelloWeb.ReviewController`.\n\nIf no route matches, no pipeline is invoked and a 404 error is raised.\n\n### Creating new pipelines\n\nPhoenix allows us to create our own custom pipelines anywhere in the router. To do so, we call the [`pipeline/2`](`Phoenix.Router.pipeline/2`) macro with these arguments: an atom for the name of our new pipeline and a block with all the plugs we want in it.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.Layouts, :root}\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n  end\n\n  pipeline :auth do\n    plug HelloWeb.Authentication\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through [:browser, :auth]\n\n    resources \"/\", ReviewController\n  end\nend\n```\n\nThe above assumes there is a plug called `HelloWeb.Authentication` that performs authentication and is now part of the `:auth` pipeline.\n\nNote that pipelines themselves are plugs, so we can plug a pipeline inside another pipeline. For example, we could rewrite the `auth` pipeline above to automatically invoke `browser`, simplifying the downstream pipeline call:\n\n```elixir\n  pipeline :auth do\n    plug :browser\n    plug :ensure_authenticated_user\n    plug :ensure_user_owns_review\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through :auth\n\n    resources \"/\", ReviewController\n  end\n```\n\n## How to organize my routes?\n\nIn Phoenix, we tend to define several pipelines, that provide specific functionality. For example, the `:browser` and `:api` pipelines are meant to be accessed by specific clients, browsers and http clients respectively.\n\nPerhaps more importantly, it is also very common to define pipelines specific to authentication and authorization. For example, you might have a pipeline that requires all users are authenticated. Another pipeline may enforce only admin users can access certain routes.\n\nOnce your pipelines are defined, you reuse the pipelines in the desired scopes, grouping your routes around their pipelines. For example, going back to our reviews example. Let's say anyone can read a review, but only authenticated users can create them. Your routes could look like this:\n\n```elixir\npipeline :browser do\n  ...\nend\n\npipeline :auth do\n  plug HelloWeb.Authentication\nend\n\nscope \"/\" do\n  pipe_through [:browser]\n\n  get \"/reviews\", PostController, :index\n  get \"/reviews/:id\", PostController, :show\nend\n\nscope \"/\" do\n  pipe_through [:browser, :auth]\n\n  get \"/reviews/new\", PostController, :new\n  post \"/reviews\", PostController, :create\nend\n```\n\nNote in the above how the routes are split across different scopes. While the separation can be confusing at first, it has one big upside: it is very easy to inspect your routes and see all routes that, for example, require authentication and which ones do not. This helps with auditing and making sure your routes have the proper scope.\n\nYou can create as few or as many scopes as you want. Because pipelines are reusable across scopes, they help encapsulate common functionality and you can compose them as necessary on each scope you define.\n\n## Forward\n\nThe `Phoenix.Router.forward/4` macro can be used to send all requests that start with a particular path to a particular plug. Let's say we have a part of our system that is responsible (it could even be a separate application or library) for running jobs in the background, it could have its own web interface for checking the status of the jobs. We can forward to this admin interface using:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\", HelloWeb do\n    ...\n  end\n\n  forward \"/jobs\", BackgroundJob.Plug\nend\n```\n\nThis means that all routes starting with `/jobs` will be sent to the `BackgroundJob.Plug` module. Inside the plug, you can match on subroutes, such as `/pending` and `/active` that shows the status of certain jobs.\n\nWe can even mix the [`forward/4`](`Phoenix.Router.forward/4`) macro with pipelines. If we wanted to ensure that the user was authenticated and was an administrator in order to see the jobs page, we could use the following in our router.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\" do\n    pipe_through [:authenticate_user, :ensure_admin]\n    forward \"/jobs\", BackgroundJob.Plug\n  end\nend\n```\n\nThis means the plugs in the `authenticate_user` and `ensure_admin` pipelines will be called before the `BackgroundJob.Plug` allowing them to send an appropriate response and halt the request accordingly.\n\n`BackgroundJob.Plug` can be implemented as any \"Module Plug\" discussed in the [Plug guide](plug.html). Note though it is not advised to forward to another Phoenix endpoint. This is because plugs defined by your app and the forwarded endpoint would be invoked twice, which may lead to errors.\n\n## Summary\n\nRouting is a big topic, and we have covered a lot of ground here. The important points to take away from this guide are:\n\n- Routes which begin with an HTTP verb name expand to a single clause of the match function.\n- Routes declared with `resources` expand to 8 clauses of the match function.\n- Resources may restrict the number of match function clauses by using the `only:` or `except:` options.\n- Any of these routes may be nested.\n- Any of these routes may be scoped to a given path.\n- Using verified routes with `~p` for compile-time route checks\n","isInternal":false,"tokens":6653,"sizeBytes":28668},{"name":".cursorrules","path":".cursorrules (elixir-phoenix-docker-setup-cursorrules-prompt-fil.mdc)","rawUrl":"https://raw.githubusercontent.com/PatrickJS/awesome-cursorrules/main/rules/elixir-phoenix-docker-setup-cursorrules-prompt-fil.mdc","title":"Awesome Cursorrules: elixir phoenix docker setup cursorrules prompt fil","category":"cursor-rule","format":"markdown","content":"---\ndescription: \"Cursor rules for Elixir development with Phoenix and Docker integration.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: Elixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n- When writing code, you will think through any considerations or requirements to make sure we've thought of everything. Only after that do you write the code.\n\n- After a response, provide three follow-up questions worded as if I'm asking you. Format in bold as Q1, Q2, Q3. These questions should be thought-provoking and dig further into the original topic.\n\n- If my response starts with \"VV\", give the most succinct, concise, shortest answer possible.\n\n## Commit Message Guidelines:\n\n- Always suggest a conventional commit message with an optional scope in lowercase. Follow this structure:\n  [optional scope]: [optional body][optional footer(s)]\n\nWhere:\n\n- **type:** One of the following:\n  - `build`: Changes that affect the build system or external dependencies (e.g., Maven, npm)\n  - `chore`: Other changes that don't modify src or test files\n  - `ci`: Changes to our CI configuration files and scripts (e.g., Circle, BrowserStack, SauceLabs)\n  - `docs`: Documentation only changes\n  - `feat`: A new feature\n  - `fix`: A bug fix\n  - `perf`: A code change that improves performance\n  - `refactor`: A code change that neither fixes a bug nor adds a feature\n  - `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n  - `test`: Adding missing tests or correcting existing tests\n\n- **scope (optional):** A noun describing a section of the codebase (e.g., `fluxcd`, `deployment`).\n\n- **description:** A brief summary of the change in present tense.\n\n- **body (optional):** A more detailed explanation of the change.\n\n- **footer (optional):** One or more footers in the following format:\n  - `BREAKING CHANGE: ` (for breaking changes)\n  - `<issue_tracker_id>: ` (e.g., `Jira-123: Fixed bug in authentication`)\n","tokens":523,"sizeBytes":2176}],"systemPromptSnippet":"<yakaai_skills repo=\"phoenixframework/phoenix\">\n<!-- File: guides/routing.md (Tokens: ~6653 | Category: root-instruction) -->\n# Routing\n\n> ### Requirement {: .tip}\n>\n> This guide expects that you have:\n>\n> * Gone through the [introductory guides](installation.html)\n> * Got a Phoenix application [up and running](up_and_running.html)\n> * Gone through the [request life-cycle guide](request_lifecycle.html)\n\nRouters are the main hubs of Phoenix applications. They match HTTP requests to controller actions, wire up real-time channel handlers, and define a series of pipeline transformations scoped to a set of routes.\n\nThe router file that Phoenix generates, `lib/hello_web/router.ex`, will look something like this one:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  # scope \"/api\", HelloWeb do\n  #   pipe_through :api\n  # end\n\n  # ...\nend\n```\n\nBoth the router and controller module names will be prefixed with the name you gave your application suffixed with `Web`.\n\nThe first line of this module, `use HelloWeb, :router`, simply makes Phoenix router functions available in our particular router.\n\nScopes have their own section in this guide, so we won't spend time on the `scope \"/\", HelloWeb do` block here. The `pipe_through :browser` line will get a full treatment in the \"Pipelines\" section of this guide. For now, you only need to know that pipelines allow a set of plugs to be applied to different sets of routes.\n\nInside the scope block, however, we have our first actual route:\n\n```elixir\nget \"/\", PageController, :home\n```\n\n`get` is a Phoenix macro that corresponds to the HTTP verb GET. Similar macros exist for other HTTP verbs, including POST, PUT, PATCH, DELETE, OPTIONS, CONNECT, TRACE, and HEAD.\n\n> #### Why the macros? {: .info}\n>\n> Phoenix does its best to keep the usage of macros low. You may have noticed, however, that the `Phoenix.Router` relies heavily on macros. Why is that?\n>\n> We use `get`, `post`, `put`, and `delete` to define your routes. We use macros for two purposes:\n>\n>   * They define the routing engine, used on every request, to choose which controller to dispatch the request to. Thanks to macros, Phoenix compiles all of your routes to a huge case-statement with pattern matching rules, which is heavily optimized by the Erlang VM\n>\n>   * For each route you define, we also define metadata to implement `Phoenix.VerifiedRoutes`. As we will soon learn, verified routes allow us to reference any route as if it were a plain looking string, except that it is verified by the compiler to be valid (making it much harder to ship broken links, forms, mails, etc to production)\n>\n> In other words, the router relies on macros to build applications that are faster and safer. Also remember that macros in Elixir are compile-time only, which gives plenty of stability after the code is compiled. As we will learn next, Phoenix also provides introspection for all defined routes via `mix phx.routes`.\n\n## Examining routes\n\nPhoenix provides an excellent tool for investigating routes in an application: `mix phx.routes`.\n\nLet's see how this works. Go to the root of a newly-generated Phoenix application and run `mix phx.routes`. You should see something like the following, generated with all routes you currently have:\n\n```console\n$ mix phx.routes\nGET  /  HelloWeb.PageController :home\n...\n```\n\nThe route above tells us that any HTTP GET request for the root of the application will be handled by the `home` action of the `HelloWeb.PageController`.\n\n## Resources\n\nThe router supports other macros besides those for HTTP verbs like [`get`](`Phoenix.Router.get/3`), [`post`](`Phoenix.Router.post/3`), and [`put`](`Phoenix.Router.put/3`). The most important among them is [`resources`](`Phoenix.Router.resources/4`). Let's add a resource to our `lib/hello_web/router.ex` file like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  get \"/\", PageController, :home\n  resources \"/users\", UserController\n  ...\nend\n```\n\nFor now it doesn't matter that we don't actually have a `HelloWeb.UserController`.\n\nRun `mix phx.routes` once again at the root of your project. You should see something like the following:\n\n```console\n...\nGET     /users           HelloWeb.UserController :index\nGET     /users/:id/edit  HelloWeb.UserController :edit\nGET     /users/new       HelloWeb.UserController :new\nGET     /users/:id       HelloWeb.UserController :show\nPOST    /users           HelloWeb.UserController :create\nPATCH   /users/:id       HelloWeb.UserController :update\nPUT     /users/:id       HelloWeb.UserController :update\nDELETE  /users/:id       HelloWeb.UserController :delete\n...\n```\n\nThis is the standard matrix of HTTP verbs, paths, and controller actions. For a while, this was known as RESTful routes, but most consider this a misnomer nowadays. Let's look at them individually.\n\n- A GET request to `/users` will invoke the `index` action to show all the users.\n- A GET request to `/users/:id/edit` will invoke the `edit` action with an ID to retrieve an individual user from the data store and present the information in a form for editing.\n- A GET request to `/users/new` will invoke the `new` action to present a form for creating a new user.\n- A GET request to `/users/:id` will invoke the `show` action with an id to show an individual user identified by that ID.\n- A POST request to `/users` will invoke the `create` action to save a new user to the data store.\n- A PATCH request to `/users/:id` will invoke the `update` action with an ID to save the updated user to the data store.\n- A PUT request to `/users/:id` will also invoke the `update` action with an ID to save the updated user to the data store.\n- A DELETE request to `/users/:id` will invoke the `delete` action with an ID to remove the individual user from the data store.\n\nIf we don't need all these routes, we can be selective using the `:only` and `:except` options to filter specific actions.\n\nLet's say we have a read-only posts resource. We could define it like this:\n\n```elixir\nresources \"/posts\", PostController, only: [:index, :show]\n```\n\nRunning `mix phx.routes` shows that we now only have the routes to the index and show actions defined.\n\n```console\nGET     /posts      HelloWeb.PostController :index\nGET     /posts/:id  HelloWeb.PostController :show\n```\n\nSimilarly, if we have a comments resource, and we don't want to provide a route to delete one, we could define a route like this.\n\n```elixir\nresources \"/comments\", CommentController, except: [:delete]\n```\n\nRunning `mix phx.routes` now shows that we have all the routes except the DELETE request to the delete action.\n\n```console\nGET    /comments           HelloWeb.CommentController :index\nGET    /comments/:id/edit  HelloWeb.CommentController :edit\nGET    /comments/new       HelloWeb.CommentController :new\nGET    /comments/:id       HelloWeb.CommentController :show\nPOST   /comments           HelloWeb.CommentController :create\nPATCH  /comments/:id       HelloWeb.CommentController :update\nPUT    /comments/:id       HelloWeb.CommentController :update\n```\n\nThe `Phoenix.Router.resources/4` macro describes additional options for customizing resource routes.\n\n## Verified Routes\n\nPhoenix includes `Phoenix.VerifiedRoutes` module which provides compile-time checks of router paths against your router by using the `~p` sigil. For example, you can write paths in controllers, tests, and templates and the compiler will make sure those actually match routes defined in your router.\n\nLet's see it in action. Run `iex -S mix` at the root of the project. We'll define a throwaway example module that builds a couple `~p` route paths.\n\n```elixir\niex> defmodule RouteExample do\n...>   use HelloWeb, :verified_routes\n...>\n...>   def example do\n...>     ~p\"/comments\"\n...>     ~p\"/unknown/123\"\n...>   end\n...> end\nwarning: no route path for HelloWeb.Router matches \"/unknown/123\"\n  iex:5: RouteExample.example/0\n\n{:module, RouteExample, ...}\niex>\n```\n\nNotice how the first call to an existing route, `~p\"/comments\"` gave no warning, but a bad route path `~p\"/unknown/123\"` produced a compiler warning, just as it should. This is significant because it allows us to write otherwise hard-coded paths in our application and the compiler will let us know whenever we write a bad route or change our routing structure.\n\nPhoenix projects are set up out of the box to allow use of verified routes throughout your web layer, including tests. For example in your templates you can render `~p` links:\n\n```heex\n<a href={~p\"/\"}>Welcome Page!</a>\n<a href={~p\"/comments\"}>View Comments</a>\n```\n\nOr in a controller, issue a redirect:\n\n```elixir\nredirect(conn, to: ~p\"/comments/#{comment}\")\n```\n\nUsing `~p` for route paths ensures our application paths and URLs stay up to date with the router definitions. The compiler will catch bugs for us, and let us know when we change routes that are referenced elsewhere in our application.\n\n### More on verified routes\n\nWhat about paths with query strings? You can add query string key values directly, as a keyword list or map of values, for example:\n\n```elixir\n~p\"/users/17?admin=true&active=false\"\n\"/users/17?admin=true&active=false\"\n\n~p\"/users/17?#{[admin: true]}\"\n\"/users/17?admin=true\"\n\n~p\"/users/17?#{%{admin: true}}\"\n\"/users/17?admin=true\"\n```\n\nWhat if we need a full URL instead of a path? Just wrap your path with a call to `Phoenix.VerifiedRoutes.url/1`, which is imported everywhere that `~p` is available:\n\n```elixir\nurl(~p\"/users\")\n\"http://localhost:4000/users\"\n```\n\nThe `url` calls will get the host, port, proxy port, and SSL information needed to construct the full URL from the configuration parameters set for each environment. We'll talk about configuration in more detail in its own guide. For now, you can take a look at `config/dev.exs` file in your own project to see those values.\n\n## Nested resources\n\nIt is also possible to nest resources in a Phoenix router. Let's say we also have a `posts` resource that has a many-to-one relationship with `users`. That is to say, a user can create many posts, and an individual post belongs to only one user. We can represent that by adding a nested route in `lib/hello_web/router.ex` like this:\n\n```elixir\nresources \"/users\", UserController do\n  resources \"/posts\", PostController\nend\n```\n\nWhen we run `mix phx.routes` now, in addition to the routes we saw for `users` above, we get the following set of routes:\n\n```console\n...\nGET     /users/:user_id/posts           HelloWeb.PostController :index\nGET     /users/:user_id/posts/:id/edit  HelloWeb.PostController :edit\nGET     /users/:user_id/posts/new       HelloWeb.PostController :new\nGET     /users/:user_id/posts/:id       HelloWeb.PostController :show\nPOST    /users/:user_id/posts           HelloWeb.PostController :create\nPATCH   /users/:user_id/posts/:id       HelloWeb.PostController :update\nPUT     /users/:user_id/posts/:id       HelloWeb.PostController :update\nDELETE  /users/:user_id/posts/:id       HelloWeb.PostController :delete\n...\n```\n\nWe see that each of these routes scopes the posts to a user ID. For the first one, we will invoke `PostController`'s `index` action, but we will pass in a `user_id`. This implies that we would display all the posts for that individual user only. The same scoping applies for all these routes.\n\nWhen building paths for nested routes, we will need to interpolate the IDs where they belong in route definition. For the following `show` route, `42` is the `user_id`, and `17` is the `post_id`.\n\n```elixir\nuser_id = 42\npost_id = 17\n~p\"/users/#{user_id}/posts/#{post_id}\"\n\"/users/42/posts/17\"\n```\n\nVerified routes also support the `Phoenix.Param` protocol, but we don't need to concern ourselves with Elixir protocols just yet. Just know that once we start building our application with structs like `%User{}` and `%Post{}`, we'll be able to interpolate those data structures directly into our `~p` paths and Phoenix will pluck out the correct fields to use in the route.\n\n```elixir\n~p\"/users/#{user}/posts/#{post}\"\n\"/users/42/posts/17\"\n```\n\nNotice how we didn't need to interpolate `user.id` or `post.id`? This is particularly nice if we decide later we want to make our URLs a little nicer and start using slugs instead. We don't need to change any of our `~p`'s!\n\n## Scoped routes\n\nScopes are a way to group routes under a common path prefix and scoped set of plugs. We might want to do this for admin functionality, APIs, and especially for versioned APIs. Let's say we have user-generated reviews on a site, and that those reviews first need to be approved by an administrator. The semantics of these resources are quite different, and they might not share the same controller. Scopes enable us to segregate these routes.\n\nThe paths to the user-facing reviews would look like a standard resource.\n\n```console\n/reviews\n/reviews/1234\n/reviews/1234/edit\n...\n```\n\nThe administration review paths can be prefixed with `/admin`.\n\n```console\n/admin/reviews\n/admin/reviews/1234\n/admin/reviews/1234/edit\n...\n```\n\nWe accomplish this with a scoped route that sets a path option to `/admin` like this one. We can nest this scope inside another scope, but instead, let's set it by itself at the root, by adding to `lib/hello_web/router.ex` the following:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nWe define a new scope where all routes are prefixed with `/admin` and all controllers are under the `HelloWeb.Admin` namespace.\n\nRunning `mix phx.routes` again, in addition to the previous set of routes we get the following:\n\n```console\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n...\n```\n\nRemember that we wanted both user-facing review routes `/reviews` and the admin ones `/admin/reviews`. If we now include the user-facing reviews in our router under the root scope like this:\n\n```elixir\nscope \"/\", HelloWeb do\n  pipe_through :browser\n\n  ...\n  resources \"/reviews\", ReviewController\nend\n\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/reviews\", ReviewController\nend\n```\n\nand we run `mix phx.routes`, we get output for each scoped route:\n\n```console\n...\nGET     /reviews                 HelloWeb.ReviewController :index\nGET     /reviews/:id/edit        HelloWeb.ReviewController :edit\nGET     /reviews/new             HelloWeb.ReviewController :new\nGET     /reviews/:id             HelloWeb.ReviewController :show\nPOST    /reviews                 HelloWeb.ReviewController :create\nPATCH   /reviews/:id             HelloWeb.ReviewController :update\nPUT     /reviews/:id             HelloWeb.ReviewController :update\nDELETE  /reviews/:id             HelloWeb.ReviewController :delete\n...\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\n```\n\nWhat if we had a number of resources that were all handled by admins? We could put all of them inside the same scope like this:\n\n```elixir\nscope \"/admin\", HelloWeb.Admin do\n  pipe_through :browser\n\n  resources \"/images\",  ImageController\n  resources \"/reviews\", ReviewController\n  resources \"/users\",   UserController\nend\n```\n\nHere's what `mix phx.routes` tells us:\n\n```console\n...\nGET     /admin/images            HelloWeb.Admin.ImageController :index\nGET     /admin/images/:id/edit   HelloWeb.Admin.ImageController :edit\nGET     /admin/images/new        HelloWeb.Admin.ImageController :new\nGET     /admin/images/:id        HelloWeb.Admin.ImageController :show\nPOST    /admin/images            HelloWeb.Admin.ImageController :create\nPATCH   /admin/images/:id        HelloWeb.Admin.ImageController :update\nPUT     /admin/images/:id        HelloWeb.Admin.ImageController :update\nDELETE  /admin/images/:id        HelloWeb.Admin.ImageController :delete\nGET     /admin/reviews           HelloWeb.Admin.ReviewController :index\nGET     /admin/reviews/:id/edit  HelloWeb.Admin.ReviewController :edit\nGET     /admin/reviews/new       HelloWeb.Admin.ReviewController :new\nGET     /admin/reviews/:id       HelloWeb.Admin.ReviewController :show\nPOST    /admin/reviews           HelloWeb.Admin.ReviewController :create\nPATCH   /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nPUT     /admin/reviews/:id       HelloWeb.Admin.ReviewController :update\nDELETE  /admin/reviews/:id       HelloWeb.Admin.ReviewController :delete\nGET     /admin/users             HelloWeb.Admin.UserController :index\nGET     /admin/users/:id/edit    HelloWeb.Admin.UserController :edit\nGET     /admin/users/new         HelloWeb.Admin.UserController :new\nGET     /admin/users/:id         HelloWeb.Admin.UserController :show\nPOST    /admin/users             HelloWeb.Admin.UserController :create\nPATCH   /admin/users/:id         HelloWeb.Admin.UserController :update\nPUT     /admin/users/:id         HelloWeb.Admin.UserController :update\nDELETE  /admin/users/:id         HelloWeb.Admin.UserController :delete\n```\n\nThis is great, exactly what we want. Note how every route and controller is properly namespaced.\n\nScopes can also be arbitrarily nested, but you should do it carefully as nesting can sometimes make our code confusing and less clear. With that said, suppose that we had a versioned API with resources defined for images, reviews, and users. Then technically, we could set up routes for the versioned API like this:\n\n```elixir\nscope \"/api\", HelloWeb.Api do\n  pipe_through :api\n\n  scope \"/v1\", V1 do\n    resources \"/images\",  ImageController\n    resources \"/reviews\", ReviewController\n    resources \"/users\",   UserController\n  end\nend\n```\n\nYou can run `mix phx.routes` to see how these definitions will look like.\n\nInterestingly, we can use multiple scopes with the same path as long as we are careful not to duplicate routes. The following router is perfectly fine with two scopes defined for the same path:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use Phoenix.Router\n  ...\n  scope \"/\", HelloWeb do\n    pipe_through :browser\n\n    resources \"/users\", UserController\n  end\n\n  scope \"/\", AnotherAppWeb do\n    pipe_through :browser\n\n    resources \"/posts\", PostController\n  end\n  ...\nend\n```\n\nIf we do duplicate a route — which means two routes having the same path — we'll get this familiar warning:\n\n```console\nwarning: this clause cannot match because a previous clause at line 16 always matches\n```\n\n## Pipelines\n\nWe have come quite a long way in this guide without talking about one of the first lines we saw in the router: `pipe_through :browser`. It's time to fix that.\n\nPipelines are a series of plugs that can be attached to specific scopes. If you are not familiar with plugs, we have an [in-depth guide about them](plug.html).\n\nRoutes are defined inside scopes and scopes may pipe through multiple pipelines. Once a route matches, Phoenix invokes all plugs defined in all pipelines associated to that route. For example, accessing `/` will pipe through the `:browser` pipeline, consequently invoking all of its plugs.\n\nPhoenix defines two pipelines by default, `:browser` and `:api`, which can be used for a number of common tasks. In turn we can customize them as well as create new pipelines to meet our needs.\n\n### The `:browser` and `:api` pipelines\n\nAs their names suggest, the `:browser` pipeline prepares for routes which render requests for a browser, and the `:api` pipeline prepares for routes which produce data for an API.\n\nThe `:browser` pipeline has six plugs: The `plug :accepts, [\"html\"]` defines the accepted request format or formats. `:fetch_session`, which, naturally, fetches the session data and makes it available in the connection. `:fetch_live_flash`, which fetches any flash messages from LiveView and merges them with the controller flash messages. Then, the plug `:put_root_layout` will store the root layout for rendering purposes. Later `:protect_from_forgery` and `:put_secure_browser_headers`, protects form posts from cross-site forgery.\n\nCurrently, the `:api` pipeline only defines `plug :accepts, [\"json\"]`.\n\nThe router invokes a pipeline on a route defined within a scope. Routes outside of a scope have no pipelines. Although the use of nested scopes is discouraged (see above the versioned API example), if we call `pipe_through` within a nested scope, the router will invoke all `pipe_through`'s from parent scopes, followed by the nested one.\n\nThose are a lot of words bunched up together. Let's take a look at some examples to untangle their meaning.\n\nHere's another look at the router from a newly generated Phoenix application, this time with the `/api` scope uncommented back in and a route added.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.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 \"/\", HelloWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :home\n  end\n\n  # Other scopes may use custom stacks.\n  scope \"/api\", HelloWeb do\n    pipe_through :api\n\n    resources \"/reviews\", ReviewController\n  end\n  # ...\nend\n```\n\nWhen the server accepts a request, the request will always first pass through the plugs in our endpoint, after which it will attempt to match on the path and HTTP verb.\n\nLet's say that the request matches our first route: a GET to `/`. The router will first pipe that request through the `:browser` pipeline - which will fetch the session data, fetch the flash, and execute forgery protection - before it dispatches the request to `PageController`'s `home` action.\n\nConversely, suppose the request matches any of the routes defined by the [`resources/2`](`Phoenix.Router.resources/2`) macro. In that case, the router will pipe it through the `:api` pipeline — which currently only performs content negotiation — before it dispatches further to the correct action of the `HelloWeb.ReviewController`.\n\nIf no route matches, no pipeline is invoked and a 404 error is raised.\n\n### Creating new pipelines\n\nPhoenix allows us to create our own custom pipelines anywhere in the router. To do so, we call the [`pipeline/2`](`Phoenix.Router.pipeline/2`) macro with these arguments: an atom for the name of our new pipeline and a block with all the plugs we want in it.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :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: {HelloWeb.Layouts, :root}\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n  end\n\n  pipeline :auth do\n    plug HelloWeb.Authentication\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through [:browser, :auth]\n\n    resources \"/\", ReviewController\n  end\nend\n```\n\nThe above assumes there is a plug called `HelloWeb.Authentication` that performs authentication and is now part of the `:auth` pipeline.\n\nNote that pipelines themselves are plugs, so we can plug a pipeline inside another pipeline. For example, we could rewrite the `auth` pipeline above to automatically invoke `browser`, simplifying the downstream pipeline call:\n\n```elixir\n  pipeline :auth do\n    plug :browser\n    plug :ensure_authenticated_user\n    plug :ensure_user_owns_review\n  end\n\n  scope \"/reviews\", HelloWeb do\n    pipe_through :auth\n\n    resources \"/\", ReviewController\n  end\n```\n\n## How to organize my routes?\n\nIn Phoenix, we tend to define several pipelines, that provide specific functionality. For example, the `:browser` and `:api` pipelines are meant to be accessed by specific clients, browsers and http clients respectively.\n\nPerhaps more importantly, it is also very common to define pipelines specific to authentication and authorization. For example, you might have a pipeline that requires all users are authenticated. Another pipeline may enforce only admin users can access certain routes.\n\nOnce your pipelines are defined, you reuse the pipelines in the desired scopes, grouping your routes around their pipelines. For example, going back to our reviews example. Let's say anyone can read a review, but only authenticated users can create them. Your routes could look like this:\n\n```elixir\npipeline :browser do\n  ...\nend\n\npipeline :auth do\n  plug HelloWeb.Authentication\nend\n\nscope \"/\" do\n  pipe_through [:browser]\n\n  get \"/reviews\", PostController, :index\n  get \"/reviews/:id\", PostController, :show\nend\n\nscope \"/\" do\n  pipe_through [:browser, :auth]\n\n  get \"/reviews/new\", PostController, :new\n  post \"/reviews\", PostController, :create\nend\n```\n\nNote in the above how the routes are split across different scopes. While the separation can be confusing at first, it has one big upside: it is very easy to inspect your routes and see all routes that, for example, require authentication and which ones do not. This helps with auditing and making sure your routes have the proper scope.\n\nYou can create as few or as many scopes as you want. Because pipelines are reusable across scopes, they help encapsulate common functionality and you can compose them as necessary on each scope you define.\n\n## Forward\n\nThe `Phoenix.Router.forward/4` macro can be used to send all requests that start with a particular path to a particular plug. Let's say we have a part of our system that is responsible (it could even be a separate application or library) for running jobs in the background, it could have its own web interface for checking the status of the jobs. We can forward to this admin interface using:\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\", HelloWeb do\n    ...\n  end\n\n  forward \"/jobs\", BackgroundJob.Plug\nend\n```\n\nThis means that all routes starting with `/jobs` will be sent to the `BackgroundJob.Plug` module. Inside the plug, you can match on subroutes, such as `/pending` and `/active` that shows the status of certain jobs.\n\nWe can even mix the [`forward/4`](`Phoenix.Router.forward/4`) macro with pipelines. If we wanted to ensure that the user was authenticated and was an administrator in order to see the jobs page, we could use the following in our router.\n\n```elixir\ndefmodule HelloWeb.Router do\n  use HelloWeb, :router\n\n  ...\n\n  scope \"/\" do\n    pipe_through [:authenticate_user, :ensure_admin]\n    forward \"/jobs\", BackgroundJob.Plug\n  end\nend\n```\n\nThis means the plugs in the `authenticate_user` and `ensure_admin` pipelines will be called before the `BackgroundJob.Plug` allowing them to send an appropriate response and halt the request accordingly.\n\n`BackgroundJob.Plug` can be implemented as any \"Module Plug\" discussed in the [Plug guide](plug.html). Note though it is not advised to forward to another Phoenix endpoint. This is because plugs defined by your app and the forwarded endpoint would be invoked twice, which may lead to errors.\n\n## Summary\n\nRouting is a big topic, and we have covered a lot of ground here. The important points to take away from this guide are:\n\n- Routes which begin with an HTTP verb name expand to a single clause of the match function.\n- Routes declared with `resources` expand to 8 clauses of the match function.\n- Resources may restrict the number of match function clauses by using the `only:` or `except:` options.\n- Any of these routes may be nested.\n- Any of these routes may be scoped to a given path.\n- Using verified routes with `~p` for compile-time route checks\n\n<!-- File: .cursorrules (elixir-phoenix-docker-setup-cursorrules-prompt-fil.mdc) (Tokens: ~523 | Category: cursor-rule) -->\n---\ndescription: \"Cursor rules for Elixir development with Phoenix and Docker integration.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: Elixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n- When writing code, you will think through any considerations or requirements to make sure we've thought of everything. Only after that do you write the code.\n\n- After a response, provide three follow-up questions worded as if I'm asking you. Format in bold as Q1, Q2, Q3. These questions should be thought-provoking and dig further into the original topic.\n\n- If my response starts with \"VV\", give the most succinct, concise, shortest answer possible.\n\n## Commit Message Guidelines:\n\n- Always suggest a conventional commit message with an optional scope in lowercase. Follow this structure:\n  [optional scope]: [optional body][optional footer(s)]\n\nWhere:\n\n- **type:** One of the following:\n  - `build`: Changes that affect the build system or external dependencies (e.g., Maven, npm)\n  - `chore`: Other changes that don't modify src or test files\n  - `ci`: Changes to our CI configuration files and scripts (e.g., Circle, BrowserStack, SauceLabs)\n  - `docs`: Documentation only changes\n  - `feat`: A new feature\n  - `fix`: A bug fix\n  - `perf`: A code change that improves performance\n  - `refactor`: A code change that neither fixes a bug nor adds a feature\n  - `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n  - `test`: Adding missing tests or correcting existing tests\n\n- **scope (optional):** A noun describing a section of the codebase (e.g., `fluxcd`, `deployment`).\n\n- **description:** A brief summary of the change in present tense.\n\n- **body (optional):** A more detailed explanation of the change.\n\n- **footer (optional):** One or more footers in the following format:\n  - `BREAKING CHANGE: ` (for breaking changes)\n  - `<issue_tracker_id>: ` (e.g., `Jira-123: Fixed bug in authentication`)\n</yakaai_skills>"}