Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to structure a Phoenix umbrella framework for many applications

I'm playing around with an architecture for a new suite of products using phx 1.3 and umbrella apps.

I have an existing Phoenix based enterprise class WebRTC soft phone (many keys, a display, multiple input and output audio device selection, and more). I have developed a Slack clone messaging app prototype with Phoenix. Both applications are fairly large I need to integrate the phone with the chat app into one front end that may be either just the phone, just the chat client, and both. I will need to add a lot of new features to the chat client moving forward I also want the architecture to support using the same client to provision additional setting on the call server (user based) and potentially a large number of admin level settings. I may also be adding other applications in the future like an operator panel, log viewer, and the list goes on... The client side JS is pretty simple, no front end framework. I render templates server side and push the html out over channels.

I would like to build this pluggable. Same endpoint and database. One common UX.

I think there will be two common apps in the umbrella, one for the Phoenix endpoint and a couple controllers and another for the main Repo and a couple schemas. I'm trying to figure out how difficult it will be to use two or more additional apps for each application. One for context and schema, another for controllers, views, templates, and brunch resource. Possibly another for 3rd party APIs.

To make this work, I'll need a dynamic dispatch for routers in each of the apps. A method for handling migrations contained in each of the apps, and probably more that I have not thought of yet.

As anyone tried this? Are there any open source projects with a similar structure?

like image 379
Steve Pallen Avatar asked Apr 19 '17 09:04

Steve Pallen


1 Answers

The elixir app I work with day-to-day is an umbrella with 13 apps.

The at the root is the Phoenix endpoint and top level Router which forwards requests to Routers defined in the other apps.

This means the app is not split into layers (web/business/data) but rather into vertical domain slices.

This has scaled well as the app has grown significantly over the last 12 months.

The biggest gotcha I've had is that Phoenix routers strip the leading path from the request when forwarding to other routers, so we created a mount macro to use with the Plug router which keeps the request path unchanged:

defmodule MyApp.Router do
  @moduledoc """
  Top level routing to each of the sub-systems
  """

  use Plug.Router

  plug :match
  plug :dispatch

  mount "/events/*_", Events.Router
  mount "/report/*_", Report.Router
  mount "/stats/*_",  Stats.Router
  mount "/auth/*_",   Auth.Router
end

and mount:

defmacro mount(path, router, opts \\ []) do
  quote do
    @opts unquote(router).init(unquote(opts))
    match unquote(path), do: unquote(router).call(var!(conn), @opts)
  end
end

We manage the migrations of the entire database in a single app just for simplicity, but Ecto Schemas are declared in each app separately.

Here is a project that demonstrates some of the concepts.

like image 69
Mike Buhot Avatar answered Oct 31 '22 12:10

Mike Buhot