Other Articles in the Series
- Overview
- Add new Permission
- Project structure
- Multi-Languages (i18n)
- DI & IoC - Why and Why not?
- RESTful & WebApi
- Manage Application Lifecycle
- Build & Deploy Application
- New version of TinyERP with Angular 2 (typescript)
- CQRS: Avoiding performance issues in enterprise app (basic)
- Multiple data-stores: Scale your repository (Part 1)
- Multiple data-stores: Scale your repository (Part 2)
- Basic authentication (user name/ password) with OWIN
- Token based authorization with OWIN
Introduction
In this tip, we learn how to organize the project for our application.
I assume that our application has the following features as shown in the image below:
In this image, we see that:
- The application has 3 big features: Security, HRM, CRM. We usually call them as module. So in the sample application, we have 3 modules: Security module, HRM module and CRM module
- Each module should be isolated from others. I mean, in Security module will not manage staff, ...
- From 1 module, should not depend on others as they are isolated each others.
- We should use event for module communication, I mean, Security module wants to call some action in HRM module. Security should fire an event, HRM will subscribe to that event with appropriate event handler. This will help us reduce the complexity of the application, and is easier for maintenance in the future.
- Each big feature has it own sub features, such as in Security, we have Permission, User Role, User, ...
- Each sub feature (such as Permission) can be implemented in one or more pages (such as list of permissions, create permission, update permission, ...)
Project Structure
With the above application, we will organize the structure as below:
From the image above:
- Each module will have its own route, menu items, .... this information was specified in "<root>/app/modules/<name of module>/_share/config/module.ts"
- Each module and its sub features will be located in it own folder in <root>/app/modules/<name-of-module>.
- Sub feature of module has its own folder (such as permission for permission sub feature) and contains its detailed implementation (list of permissions, add permission, update permission). This will make it easier for us to locate and modify the code.
- Service class, used by appropriated sub feature (such as
permissionService
) should be located in "_share/services" folder in appropriated module. permissionService
was not only used inside permission sub feature but also in other sub features in the same module (such as usergroup, user). - For directives, used by any sub-features on module. they should be located in "_shared/directives" folder. For example, "
permissions
" directive (showing the list of permissions) can be users in permission, user sub-feature.
If this directive was located inside "<root>/app/security/permission". In user sub-feature, we need to duplicate or import from permission sub-feature (this will create dependency between user and permission sub-feature). It is not good.
If this directive was located inside "<root>/app/common/directives". The number of directives in this folder will be immense and most of them were used in 1 module only.
- Inside 1 module, we will fire event if we want to notify other modules.
let eventManager = window.ioc.resolve("IEventManager");
eventManager.publish("<event-key>", <event argument>);
- Multi languages (i18n) resource was located in "<root>/app/resources/locales/<name of module>.<language>.json" (such as: security.en.json or security.vn.json).
Each module should have only 1 file for 1 language.
All sub-features of module should use texts inside this json file following the convention "<name of module>.<name of sub-feature>.<name of implementation>.<name of text>". For example, "security.permission.permissions.pageTitle
" will return the text used for title of permission page in permission sub-feature of security module.
The same rules were applied for HRM, CRM modules.