dsignr
Hi all, my first post here. Certainly not new here.
First of all, huge congrats on the team for 1.3. It’s amazing in so many ways that it has actually forced me to re-think the way I create applications. I found myself spending hours at coffee shops drawing diagrams, contexts, etc. and each time I do it, I discover something new about the business problem space that I didn’t think of before (as a programmer). I’m loving it so far! However, I’ve seem to hit a roadblock..
Before I dive into my question, I’d like to give you a heads up:
- I’ve so far read all 3 of the major books on DDD
- Watched Chris’s video of Phx 1.3
- Searched the forum posts
So, now for the question.
I’m building an ECommerce portal based off Phoenix 1.3. Let’s assume I have just 2 contexts - CMS and Ecommerce.
- CMS
- E-Commerce
Now, it so happens that the CMS domain has a page entity. While the Ecommerce entity has a product entity. I want to create a category model within the CMS context as well as the Ecommerce context.
- CMS
--- Category
- E-Commerce
--- Category
However, when I run the generators for the category, they seem to conflict:
mix phx.gen.html CMS Category categories name:string shortcode:string description:text
mix phx.gen.html ECommerce Category categories name:string shortcode:string description:text
They seem to overwrite the controllers and the views with one another, since they are all generated inside the Web context:
* creating lib/marketer/web/controllers/category_controller.ex
lib/marketer/web/controllers/category_controller.ex already exists, overwrite? [Yn] y
* creating lib/marketer/web/templates/category/edit.html.eex
lib/marketer/web/templates/category/edit.html.eex already exists, overwrite? [Yn] y
So, community, kindly help me to understand:
A. What exactly is the web context for?
B. Why can’t my Ecommerce and CMS namespaces handle their own templates, views, etc, separately
For example:
Ecommerce/
controllers/
....
templates/
....
CMS/
controllers/
....
templates/
....
C. The whole problem seems to arise because everything is being dumped into the Web context. I don’t understand, everything is technically a web-facing entity, right? Phoenix is a web application framework, so my CMS, Ecommerce by right are all web-based functionalities already. Why should I dump it all into the web folder?
D. How would you re-architect this, instead? Clearly, I don’t seem to understand the new structure, or I’m missing something basic. I would really appreciate if someone can point me in the right direction.
Your thoughts, advice or any sort of help is much appreciated ![]()
Thank you for your time.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #ai
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #blog-post
- #ecto-query
- #elixirconf-us
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
easco
As I understand it, Contexts in Phoenix are meant to separate your model behaviors from the way those models are persisted (e.g. In a database). What you seem to want to do is separate elements in the view and controller layers using the same context concept. Seems like something you could legitimately want to do, but I just don’t think they Context concept from Phoenix 1.3 is meant to do that.
What make make more sense, in your case, is having separate applications (one for E-commerce and one for CMS) in an umbrella framework. Your two web front ends for each of those areas could share underlying logic in a third application for shared model level functionality.
dsignr
Thank you for your quick response. Suddenly, Umbrella makes total sense. However, I have a rather (stupid) question - Umbrella apps can’t run on the same port, if I’m not mistaken. So, in this case, my users can’t edit CMS pages and Ecommerce products on the same port (4000) right? How do you deal with this scenario?
I’m concerned that when my port 4000 is tied to CMS, it would be something like:
URL 1:
admin/cms/pages/newAnd say, 4001 would be tied to Ecommerce, it would be on a url like:
URL 2:
admin/ecommerce/products/newSo, my user simply/easily can’t navigate from URL 1 to URL 2, right?
Please correct me if I’m wrong.
Thank you for taking the time to help me out
yurko
I don’t think there is a right (or wrong) answer here, my 2 cents: I’d probably leave the web part in one app, but refactor the generated controllers (I always do that, no matter the phoenix version). Generators are meant to be the starting point, they don’t have to define your structure.
Here is an example from 1.2 application: I have admin area with crud etc and frontend with some lists for say products. These two are different in all but models - admin needs to have a separate login etc.
So I have stuff like this in router:
and in controllers there is an
App.ProductControllerfor frontend as well as nestedApp.Admin.ProductControllerin the admin subdirectory. Same with views and templates.In bigger projects I use further nesting of entities, it doesn’t have to be the way to do things but treating the generator’s results as a starting point works all the time
dom
You can use a “proxy” app like in the Acme Bank sample project.
dsignr
Hi Dom,
Thank you very much. That’s an interesting approach. Do you know if this proxy will negatively impact performance? Thank you
dom
The “proxy” is just a plug that looks at the URL and calls the right function: acme_bank/apps/master_proxy/lib/master_proxy/plug.ex at master · wojtekmach/acme_bank · GitHub
So, the impact should be negligible.
dsignr
Thank you, Dom.
One quick question, still relevant to the topic:
How do you handle authentication?
I foresee two scenarios:
A. I setup a separate app called “Auth” for handling authentication. But then every other app will need to go through this app to check if a given user is authenticated and is authorized to perform the requested action. (Eg. view a particular resource/page). This seems like a violation of boundaries in terms of DDD to me.
B. I setup an auth sub-module under each app, and the
current_useris simply tossed around from one app to another. Honestly I have no idea how to get this done.Additonal info:
I come from a Rails background, so I’m still trying to break free of the Rails mindset. While at the same time, I want to make sure I’m not making a spaghetti (code wrangling from different modules) in the process.
I use coherence for my app setup. I have no idea how to break
authandusersince they seem to be tied together.After the advice on this thread, I’m now using an umbrella structure.
All I want to do:
From my previous example, when I visit Ecommerce to CMS, I would still need to be logged in.
I remember vaguely @josevalim mentioned somewhere in this forum along the lines of
I believe this is exactly where I’m stuck.
Thank you for your time, your help will be much appreciated
mjadczak
I don’t see how this is a violation of boundaries—if you have an app whose purpose is to handle authentication and authorisation, you could write a clean interface there and it would absolutely conform to DDD. The Auth app does not necessarily need to “know” about users past e.g. their emails or IDs.
So you could have an interface that lets you, say at signup, say to the Auth app “the user with ID 78 is allowed to buy products”. On login, you could call into the Auth app with the credentials, and if correct, it could give you the user_id (to be used with the Users context) as well as perhaps some sort of identity blob. Later, e.g. in an ECommerce controller, you could have a plug which grabs this identity blob (representing a logged-in user) and ask the Auth app if the user is allowed to, say buy an item. If not, you take appropriate action.
Another thing to consider is whether you actually want to separate your frontends into two apps. It is totally valid to have three apps, one managing ECommerce logic, one managing CMS logic, and one Phoenix app being the frontend to both. I like to separate things into their own modules first, and only if it becomes clear I really am running two independent systems do I refactor those out into separate apps in the umbrella.
One big thing which I’m not sure has been mentioned, and which is really different from Rails, is that Phoenix is not your app. When people say “app” in the Elixir community, they often mean an OTP application, which is just a bunch of modules and processes running together, often under one supervision tree. The advice you’re being given is to create your business logic in separate apps without a web interface, i.e. you should be able to run your app from iex directly (also great for testability), and then you can put a Phoenix-powered web interface on top of this, where the controllers simply call the appropriate business logic functions.
dsignr
Thank you for your excellent, detailed reply Matt. Much appreciated. That was a very thorough detailed reply.
My concerns regarding separation were mostly around the routes. How do you organize the routes?
For example, if
Authmodule is taking care of the authentication and authorization, surely it needs to be a part of every route within every other module right?So,
cms’s route file should make a reference to this auth for every request, if I’m not wrong. My logic says it’s wise to go with a shared kernel (DDD), using a pipeline forauththat every route from every other domain can use, but I honestly don’t know how to go about it. (If you’ve got some sample code, it would be great too!)Would love to hear your thoughts.
Thank you.
mjadczak
I think you’re still thinking of your web interface and your actual app as the same thing. The Auth module doesn’t need to know anything about routes, or be “part” of any routes.
The Auth module is simply a piece of code you can ask whether a certain principal (e.g. user) can do a certain thing (e.g. buy a product).
Routes are only relevant in the web layer—each route will have some controller handling it, and that controller can ask the Auth module whether the current user is allowed to do the action they’re trying to, and if not, error out. If they are, the controller proceeds to call into the appropriate context module, e.g. CMS, to perform the desired action, and then renders out the results as JSON or HTML.
This means you decouple your web interface from what your app actually does—you should be able to use your app fully from the iex shell before your web layer is ready.