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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With