sbuttgereit

sbuttgereit

Phoenix 1.7-rc0 Project Organization; Multi-Endpoint & UI

Hi–

So my project has reached a point where how users will interact with the application is important and so this week I’ve started to jump into Phoenix with a more serious eye than that required to get through the typical tutorials & training courses you find out and about.

Phoenix comes with its own opinionated views of how applications are organized as encouraged via its scaffolding and generators. I think this is a good thing in general and fine, as-is, for a lot of applications. Nonetheless, I’ve got a few requirements in my application that have me thinking about this more deeply and thinking I might need to do something at least a bit different. There are a few requirements that are motivating my questions here. My application needs a user interface for normal users logging in from wherever they might be (within some limits)… call this the Public UI. I also need an administrative user interface to manage and monitor the system operations which should not be trivially accessible from just anywhere, this is the Admin UI. Finally, and this is the odd bit, the application should be capable of being run from a single node for… reasons. This suggests that solutions where a phoenix application ‘A’ provides the Public UI and a different phoenix application ‘B’ does the admin interface start to look less good for what I’m trying to build. And my sense it that’s not necessary; though I am happy to be corrected.

At this point I’ve managed to get multiple endpoints for each of the UI types working and I can see I’ll probably also need/want individual routers for the Public UI & Admin UI. This part of dealing with Phoenix feels pretty straightforward and I’ve not really run into anything difficult to grasp (famous last words)… I’m seeing how things are pieced together and I know I’m not exactly treading new territory; that the flexibility to do the things I’m trying to do exists is not surprising. And one last bit of context, my questions below are not really dealing with organizing business logic or database concerns so much; that I’ve got significant progress on outside of what will be the Phoenix implementation: My Phoenix project is really just the interface for users and to provide an API to other systems. With that background… some questions.

My Admin UI I expect to have a modest footprint, but the Public UI has the potential to get complex. As I’m looking at the different modules I’m duplicating, or am likely to duplicate, in some fashion for the different UIs, I’m coming around to the idea that maybe instead of having a myapp_web directory which contains files supporting both UIs kinda thrown together I should split that out into two directory hierarchies a myapp_public_web and myapp_admin_webeach containing the necessary files/modules/etc required to operate each UI. Outside of some possible duplication are there any downsides to doing that? Is there some better way to organize that which I’m not thinking of? Does this hose the ability of Phoenix to be upgraded over time? I could see a third directory in there myapp_common_web for bits that could be shared between the two projects (like maybe the gettext stuff), and I could see where assets have the potential to be tricky in all this, though right now I don’t see an issue with assets. With the above my thinking is that Phoenix likely technically will be fine and that at least I’ll be organizing things in the spirit of Phoenix’s own scaffolded code.

I appreciate that I’m asking more philosophical questions than technical questions, but I guess what I’m really trying to do is get a second opinion before I get too far down a bad path that I can’t see for want of Phoenix experience.

Thanks!
Steve

Marked As Solved

al2o3cr

al2o3cr

I’ve found umbrella projects streamline doing things like this quite a bit. You wind up with a directory structure like this:

apps/
  admin_web/ - standard Phoenix stuff for the admin portal. Has its own asset pipeline, etc
  public_web/ - standard Phoenix stuff for the public portal. Has its own asset pipeline, etc
  shared_web/ - maybe? If there are common function components or similar
  data/ - pick a better name for this, but it's contexts / schemas / etc 

The one minor hassle with this approach is that the two Endpoints expect to run on different ports; you can either use something like main_proxy to route traffic to them from one listener, or you could handle that in the load-balancer / SSL-termination layer. The latter is particularly handy if you want to impose rules like “only users on the company VPN can access admin_web”.

Also Liked

cmo

cmo

I put the admin UI pages and components in app_web/live/admin or app_web/dead/admin, common components live in app_web/components and control access with a live_session or Plug pipeline. But I only use the one endpoint.

You could do

app_web/
  admin/
    live/
    dead/
    components/
  public/
    live/
    dead/
    components/

Separate web folders makes sense if they’re separate BEAM applications.

sbuttgereit

sbuttgereit

Many thanks for the reply. What you’ve suggested is an absolutely reasonable approach.

Originally I figured I’d be doing something very much like you’re suggesting, however this comment is the distinction that pushes me to have mulitple “web” root directories:

With a single endpoint, the files at the root of app_web directory don’t really change that much; sure the routes are going to reflect how you access the “admin” or “public” side and maybe a couple of other tweaks, but the Endpoint module, the Router module it’s coded to look at, etc. can all fundamentally be as they’re scaffolded by mix phx.new (everything else being equal). But multiple Endpoint modules push the Admin/Public distinction down to the level where endpoint.ex, router.ex, etc. exist. So I’m going to have Admin Endpoint and a Public Endpoint modules, for that distinction to be useful I’m going to need an Admin Router module and a Public Router module, and my hunch is that the Telemetry module will also have some differences (telemetry is a problem for far future me). As the Admin/Public distinction leaks into these bottom level files in app_web, it starts to raise the question if app_web is fundamental or if we should bring the Admin/Public distinction there, too.

All of that is style points stuff though, more important to the humans reading the code than to the technical operations of the software. Your reply is helpful to me because it shows me there is precedence for treating the out-of-box scaffolded directory structure as something that can be futzed with as needed; the biggest concern I have is whether a style related choice is going to break technical requirement (or established conventions); I know there are some naming expectations between certain files and related directories… and I don’t know how deep that might go or how it manifests elsewhere so I get nervous :-).

Thanks again! It was helpful.

sbuttgereit

sbuttgereit

For my use case, this is actually the primary motivation for using multiple endpoints. The Admin UI will be security sensitive and so if I can make a firewall the first barrier to unwanted Admin UI attention all the better; I actually don’t know what the final runtime environment will be, but binding the Admin UI to only a non-public IP address wouldn’t be unwelcome if the situation permitted. :slight_smile: If my requirements were a little different, much of the administrative access I’m planning would be in a separate application on its own node, well away from anything directly facing the public internet… oh well.

I do like the umbrella idea as it produces a Phoenix application which looks like the “common model” that gets scaffolded; I just finished setting up an initial environment using my first idea and while I’ve got it up and running I can see where, from a maintenance perspective, it might not be ideal. Given how much stuff will need to be consciously aligned according to UI silo; this is really a problem of needing to remember more “names” of things and being sure the right names are used in the right places. The umbrella method seems like it would quiet that cognitive load since each application in the umbrella would effectively be independent (and largely use the same names for the same things).

Thanks for the ideas!

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New

Other popular topics Top

JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement