From e28af8a048a261215d49c1a96e9923d8311c7cc3 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Pasquier <contact@jbpasquier.eu>
Date: Mon, 22 Feb 2021 21:27:58 +0100
Subject: [PATCH] major: startinblox-feature-requests#181

---
 README.md                                     | 510 ++++++++++++------
 config.sample.json                            | 105 +++-
 cypress/integration/delete-channel.spec.js    |  10 +-
 cypress/integration/edit-channel.spec.js      |  16 +-
 cypress/integration/edit-project.spec.js      |  20 +-
 cypress/integration/edit-user.spec.js         |  34 +-
 cypress/integration/leave-channel.spec.js     |   2 +-
 cypress/integration/retire-channel.spec.js    |   8 +-
 cypress/integration/retire-project.spec.js    |   6 +-
 cypress/integration/signin.spec.js            |   2 +-
 internal/parcel.js                            |  13 +-
 src/components/getRoute.js                    |  14 +
 src/components/hubl-auto-login.js             |  10 +-
 src/components/hubl-reactivity.js             |   6 +-
 src/components/hubl-search-users.js           |   8 +-
 src/components/hubl-status.js                 |  13 +-
 src/components/sentry.js                      |   2 +-
 src/context.pug                               |  17 +-
 src/dependencies.pug                          |  71 +--
 src/hubl-router.pug                           |  56 ++
 src/index.pug                                 | 386 ++++++-------
 src/scripts/firefox-scroll.js                 |  60 ---
 src/scripts/intl.js                           |  12 +-
 src/scripts/login-element-visibility.js       |  88 +--
 src/scripts/navigate-event.js                 | 243 +++++----
 src/scripts/register-sw.js                    |  12 +-
 src/scripts/theme-checker.js                  |   5 +-
 src/scripts/timeout-goeswrong.js              |  10 +-
 src/scripts/user-creation-form.js             |  13 +-
 src/styles/index.scss                         |  30 +-
 src/styles/profile/_index.scss                |   7 -
 src/views/page-admin.pug                      | 111 ++--
 src/views/page-circle.pug                     |  82 ++-
 src/views/page-dashboard.pug                  |   2 +-
 src/views/page-directory.pug                  |   4 +-
 src/views/page-events.pug                     |   8 +-
 src/views/page-job-board.pug                  |   5 +
 src/views/page-job-offers.pug                 |   5 -
 src/views/page-messages.pug                   |   4 +-
 src/views/page-polls.pug                      |   6 +-
 src/views/page-profile.pug                    |   4 +-
 src/views/page-project.pug                    |  29 +-
 src/views/page-registering.pug                | 107 ++++
 src/views/page-resources.pug                  |  10 +-
 ...-create.pug => page-admin-chat-create.pug} |  18 +-
 ...in-communities.pug => page-admin-chat.pug} |  25 +-
 .../admin/page-admin-circles-create.pug       |  14 +-
 .../partials/admin/page-admin-circles.pug     | 110 +---
 .../admin/page-admin-projects-create.pug      |  12 +-
 .../partials/admin/page-admin-projects.pug    | 116 +---
 .../partials/circle/page-circle-chat.pug      |   2 +-
 .../partials/circle/page-circle-edit.pug      |  27 +-
 .../partials/circle/page-circle-events.pug    |  19 +-
 .../partials/circle/page-circle-left.pug      |   3 +-
 .../partials/circle/page-circle-polls.pug     |  17 +-
 .../partials/circle/page-circle-profile.pug   |  82 ++-
 .../partials/circle/page-circle-resources.pug |  21 +-
 src/views/partials/header.pug                 | 200 +++----
 src/views/partials/menu-left.pug              | 381 ++++++-------
 .../partials/project/page-project-chat.pug    |   2 +-
 .../partials/project/page-project-edit.pug    |  36 +-
 .../partials/project/page-project-left.pug    |  22 +-
 .../partials/project/page-project-picture.pug |  28 +-
 .../partials/project/page-project-profile.pug |  52 +-
 src/views/partials/widgets.pug                |  33 +-
 .../widgets/hubl-action-community.pug         |  12 +
 .../hubl-admin-circle-counter-alternate.pug   |  11 +
 .../widgets/hubl-admin-circle-counter.pug     |  11 +
 .../hubl-admin-circle-link-alternate.pug      |  11 +
 .../widgets/hubl-admin-circle-link.pug        |  11 +
 .../widgets/hubl-admin-community-counter.pug  |  11 +
 .../hubl-admin-project-counter-alternate.pug  |  11 +
 .../widgets/hubl-admin-project-counter.pug    |  12 +
 .../hubl-admin-project-link-alternate.pug     |  11 +
 .../widgets/hubl-admin-project-link.pug       |  11 +
 src/views/partials/widgets/hubl-captain.pug   |  48 +-
 .../widgets/hubl-circle-edit-admin.pug        |   3 +
 .../hubl-circle-edit-members-delete.pug       |  10 +
 .../widgets/hubl-circle-join-button.pug       |  15 +
 .../partials/widgets/hubl-circle-owner.pug    |  19 +
 .../widgets/hubl-circle-team-contact.pug      |   4 +
 .../widgets/hubl-circle-user-admin.pug        |   3 +
 src/views/partials/widgets/hubl-counter.pug   |   7 +
 .../partials/widgets/hubl-create-contact.pug  |   9 +
 .../partials/widgets/hubl-email-field.pug     |   6 +
 .../partials/widgets/hubl-menu-create.pug     |  10 +
 .../widgets/hubl-menu-fix-url-circle.pug      |  24 +
 .../widgets/hubl-menu-fix-url-contact.pug     |  18 +
 .../widgets/hubl-menu-fix-url-project.pug     |  25 +
 .../partials/widgets/hubl-menu-jabberid.pug   |   6 +
 .../widgets/hubl-menu-publicprivate.pug       |   6 +
 .../partials/widgets/hubl-project-admins.pug  |   9 +
 .../partials/widgets/hubl-project-captain.pug |  19 +
 .../widgets/hubl-project-edit-admin.pug       |   3 +
 .../hubl-project-edit-members-delete.pug      |  10 +
 .../widgets/hubl-project-team-contact.pug     |   4 +
 .../partials/widgets/hubl-username-field.pug  |   5 +
 97 files changed, 2151 insertions(+), 1610 deletions(-)
 create mode 100644 src/components/getRoute.js
 create mode 100644 src/hubl-router.pug
 delete mode 100644 src/scripts/firefox-scroll.js
 delete mode 100644 src/styles/profile/_index.scss
 create mode 100644 src/views/page-job-board.pug
 delete mode 100644 src/views/page-job-offers.pug
 create mode 100644 src/views/page-registering.pug
 rename src/views/partials/admin/{page-admin-users-create.pug => page-admin-chat-create.pug} (75%)
 rename src/views/partials/admin/{page-admin-communities.pug => page-admin-chat.pug} (68%)
 create mode 100644 src/views/partials/widgets/hubl-action-community.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-circle-counter-alternate.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-circle-counter.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-circle-link-alternate.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-circle-link.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-community-counter.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-project-counter-alternate.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-project-counter.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-project-link-alternate.pug
 create mode 100644 src/views/partials/widgets/hubl-admin-project-link.pug
 create mode 100644 src/views/partials/widgets/hubl-circle-edit-admin.pug
 create mode 100644 src/views/partials/widgets/hubl-circle-edit-members-delete.pug
 create mode 100644 src/views/partials/widgets/hubl-circle-join-button.pug
 create mode 100644 src/views/partials/widgets/hubl-circle-owner.pug
 create mode 100644 src/views/partials/widgets/hubl-circle-team-contact.pug
 create mode 100644 src/views/partials/widgets/hubl-circle-user-admin.pug
 create mode 100644 src/views/partials/widgets/hubl-counter.pug
 create mode 100644 src/views/partials/widgets/hubl-create-contact.pug
 create mode 100644 src/views/partials/widgets/hubl-email-field.pug
 create mode 100644 src/views/partials/widgets/hubl-menu-create.pug
 create mode 100644 src/views/partials/widgets/hubl-menu-fix-url-circle.pug
 create mode 100644 src/views/partials/widgets/hubl-menu-fix-url-contact.pug
 create mode 100644 src/views/partials/widgets/hubl-menu-fix-url-project.pug
 create mode 100644 src/views/partials/widgets/hubl-menu-jabberid.pug
 create mode 100644 src/views/partials/widgets/hubl-menu-publicprivate.pug
 create mode 100644 src/views/partials/widgets/hubl-project-admins.pug
 create mode 100644 src/views/partials/widgets/hubl-project-captain.pug
 create mode 100644 src/views/partials/widgets/hubl-project-edit-admin.pug
 create mode 100644 src/views/partials/widgets/hubl-project-edit-members-delete.pug
 create mode 100644 src/views/partials/widgets/hubl-project-team-contact.pug
 create mode 100644 src/views/partials/widgets/hubl-username-field.pug

diff --git a/README.md b/README.md
index 7d12f54b..b0f6867f 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
   <br>
 </h1>
 
-<h4 align="center">A magic tool that allows the Freelance Network to thrive in a decentralized way, built on top of <a href="https://startinblox.com/" target="_blank">Startin'blox</a>.</h4>
+<h4 align="center">A magic orchestrator that allows the Freelance Network to thrive in a decentralized way, built on top of <a href="https://startinblox.com/" target="_blank">Startin'blox</a>.</h4>
 
 <hr>
 
@@ -22,24 +22,20 @@ These instructions will get you a copy of the project up and running on your loc
 
 To install Hubl, you'll need:
 
-* A [Hubl Server](https://git.startinblox.com/djangoldp-packages/server-manager/) (djangoldp>1)
-* A [Prosody Server](https://prosody.im/) (with [appropriate modules](https://git.startinblox.com/infra/prosody-modules/))
+* A [Hubl Server](https://git.startinblox.com/djangoldp-packages/server-manager/) (djangoldp>2)
+* A [Prosody Server](https://prosody.im/) (with [appropriate modules](https://git.startinblox.com/infra/prosody-modules/)) (optional)
 * A SMTP Server (optional)
 * NodeJS on your machine
 
 Before diving in you have to check your Hubl Server supports the following LDP packages:
 
 * djangoldp_account
-* djangoldp_community
-* djangoldp_notification
-* djangoldp_profile
-* djangoldp_skill
 * djangoldp_uploader
-* oidc_provider: django-webidoidc-provider
+* an oidc_provider (eg: [django-webidoidc-provider](https://git.startinblox.com/djangoldp-packages/django-webidoidc-provider))
 
 Those packages are given with the last stable version tested.
 
-Refer to the [documentation to install a Hubl Server](https://docs.startinblox.com/import_documentation/install-sib-server.html) with this configuration.
+Refer to the [documentation to install a Hubl Server](https://docs.startinblox.com/import_documentation/install-djangoldp-server.html) with this configuration.
 
 ## Build the application
 
@@ -71,6 +67,8 @@ Serve, watch files & rebuild on change with this command:
 npm run watch
 ```
 
+Notice that you may have to restart the watcher for the config.json and for locales files.
+
 ### Multiple config.json
 
 You can have as many `config.*.json` as you need.
@@ -87,114 +85,208 @@ Build with a custom config file:
 CONFIG_PATH='config.customName.json' npm run build
 ```
 
-### Theme checker
-
-The [Hubl theme manager](https://cdn.startinblox.com/hubl/theme/) is very handy for customer to easily customize the main colors they want to use.
-But developers should verify that their development use those colors to fit the customer wishes. The theme checker make this task easier :
-just add `"themeChecker": true` to the config.json to display the color picker tool in the header bar. Changing the color will set them on the
-whole app so that you can verify that your development take them into account correctly.
-
 ## Mandatory modules
 
 By default, a Hubl includes only individual chat modules.
 
-On Server: `djangoldp_account`, `djangoldp_profile`, `djangoldp_notification`, `djangoldp_skill`, `djangoldp_upload`, `oidc_provider` packages
+On Server: `djangoldp_account`, `djangoldp_upload`, `django-webidoidc-provider` packages
 
 On `config.json`:
 
 ```json
 {
-  "xmppWebsocket": "wss://jabber.happy-dev.fr/xmpp-websocket",
-  "clientName": "My local Hubl",
-  "clientLogo": "/images/logo.webp",
-  "authority": "http://localhost:8000/",
-  "endpoints": {
-    "get": {
-      "communities": "http://server.url/open-communities/",
-      "skills": "http://server.url/skills/",
-      "users": "http://server.url/users/"
-    },
-    "post": {
-      "uploads": "http://server.url/upload/"
-    }
+  "client": {
+    "name": "Localhost",
+    "logo": "/images/logo.webp"
   }
+  "components": []
 }
 ```
 
 Where:
 
-* `clientName` is the name of your Hubl
-* `clientLogo` is an URL to an image file
-* `xmppWebsocket` is your [Prosody](https://prosody.im/) with [appropriate modules](https://git.startinblox.com/infra/prosody-modules/) configured on.
-* `authority` is the OpenID Provider. Usually, if you use `djangoldp-account` it's the same as your djangoldp server.
-* `endpoints.*.communities` is the API endpoints for Open Communities on your djangoldp server. (djangoldp-community)
-* `endpoints.*.users` is the API endpoints for Users on your djangoldp server. (djangoldp-account)
-* `endpoints.*.skills` is the API endpoints for Skills on your djangoldp server. (djangoldp-skill)
-* `endpoints.*.uploads` is the API endpoints for Uploads on your djangoldp server. (djangoldp-upload)
+* `client.name` is the name of your Hubl
+* `client.logo` is an URL to an image file
+* `components` is your modules declaration registry
 
-### Communities
+### Optional personalisation
 
-Communities are mandatory to have an Hubl. If you're upgrading an existion Hubl, you can assign all your local users to a community this way:
+On `config.json`:
 
-```bash
-./manage.py create_community --name="My community"
+```json
+{
+  "client": {
+    "favicon": "/images/favicon.webp",
+    "css": "/path/to/custom.css",
+  }
+}
 ```
 
-Don't forget to set some users as admin from the Django Admin if you want to allow them to create new users from app.
+Where:
 
-If you set `allow_self_registration` on your community, it'll disable the auto-login feature of Hubl and allow your users to self register on your application.
+* `client.avicon` is an URL to a distant favicon
+* `client.css` is an URL to a distant CSS that'll be the last one loaded by the Hubl
 
-### Optional personalisation
+### Allow to login to your application
 
-On `config.json`:
+Most of other modules will need to have an user logged in, if you want to use communities, then scroll back to the User Registration module, else you'll need to activate the Auto Login module:
 
 ```json
-  "clientFavicon": "/images/favicon.webp",
-  "clientLogoHeight": "32px",
-  "clientCSS": "/path/to/custom.css",
-  "authorityName": "djangoldp-server-name"
+    {
+      "type": "autoLogin",
+      "parameters": {
+        "authority": "http://server.url/"
+      }
+    }
 ```
 
 Where:
 
-* `clientFavicon` is an URL to a distant favicon
-* `clientLogoHeight` allow a quick fix to manage different height logos
-* `clientCSS` is an URL to a distant CSS that'll be the last one loaded by the Hubl
-* `authorityName` is a visual name of your OpenID Provider
+* `authority` is the OpenID Provider. Usually, if you use `djangoldp_account` it's the same as your djangoldp server.
 
 ## Optional modules
 
+### Adding modules
+
+You can append any module listed bellow to your `components` entry on your `config.json`
+
+Eg. to add the `notification` module:
+
+```json
+{
+  "components": [
+    {
+      "type": "notification",
+      "route": false
+    }
+  ]
+}
+```
+
+### About
+
+About is a short page about the technology behind Hubl.
+
+To activate about on Hubl, add this module declaration your `config.json`:
+
+```json
+    {
+      "type": "about",
+      "route": false
+    }
+```
+
+### Administration
+
+Administration is a minimal modulable admin module for all other ones.
+
+To activate administration on Hubl, add this module declaration your `config.json`:
+
+```json
+    {
+      "type": "admin",
+      "route": false
+    }
+```
+
 ### Analytics
 
 Hubl support Google or Matomo as analytics trackers. To use them, add to your `config.json`:
 
 ```json
-  "analytics": [
     {
-      "type": "matomo", //Or "google"
-      "url": "https://my-personal.matomo.cloud/",
-      "id": "1"
+      "type": "analytics",
+      "parameters": {
+        "type": "matomo",
+        "url": "https://my-personal.matomo.cloud/",
+        "id": "1"
+      },
+      "route": false
     }
-  ]
 ```
 
 ### Circles
 
-Circles are a public group chat. To activate them, you need:
+Circles define group of users that can chat & share documents togethers.
 
-On Server: `djangoldp_circle` packages
+Community module is mandatory.
 
-On `config.json`:
+To activate them, you need:
+
+On Server: `djangoldp_circle`, `djangoldp_communities`, `djangoldp_notifications` packages
+
+Module declaration, on `config.json`:
 
 ```json
-  "endpoints": {
-    "get": {
-      "circle": "http://server.url/circles/"
-    },
-    "post": {
-      "circle": "http://server.url/circles/"
-    },
-  }
+    {
+      "type": "circles",
+      "endpoints": {
+        "get": "http://server.url/circles/",
+        "post": "http://server.url/circles/",
+        "owners": "http://server.url/users/",
+        "users": "http://server.url/users/",
+        "xmpp": "wss://xmpp-dev.startinblox.com/xmpp-websocket"
+      }
+    }
+```
+
+Where:
+
+* `owners`: is your users container which contains valid owners
+* `users`: is your users container
+* `xmpp` is your [Prosody](https://prosody.im/) with [appropriate modules](https://git.startinblox.com/infra/prosody-modules/) configured on.
+
+#### Circles extensions
+
+You can extend circles with other components, the same way you would add them to your modules.
+
+Actually it support: Events, Resources & Polls.
+
+Eg.:
+
+```json
+    {
+      "type": "circles",
+      "endpoints": {
+        "get": "http://server.url/circles/",
+        "post": "http://server.url/circles/",
+        "owners": "http://server.url/users/",
+        "users": "http://server.url/users/",
+        "xmpp": "wss://xmpp-dev.startinblox.com/xmpp-websocket"
+      },
+      "extensions": [
+        {
+          "type": "events",
+          "endpoints": {
+            "get": "http://server.url/events/",
+            "post": "http://server.url/events/",
+            "typeevents": "http://server.url/typeevents/",
+            "postTypeevents": "http://server.url/typeevents/"
+          }
+        }
+      ]
+    }
+```
+
+### Communities
+
+Communities are an optional layer to add on an Hubl. They add a SOLID representation of one to many group of users on your data server.
+
+If you're upgrading an existion Hubl, you can assign all your local users to a community this way:
+
+```bash
+./manage.py create_community --name="My community"
+```
+
+Don't forget to set some users as admin of the community from the Django Admin if you want to allow them to create new users from app.
+
+To activate community on Hubl, add this module declaration your `config.json`:
+
+```json
+    {
+      "type": "communities",
+      "route": false
+    }
 ```
 
 ### Dashboard
@@ -203,168 +295,274 @@ Dashboard includes card generation from HTML. To activate them, you need:
 
 On Server: `djangoldp_dashboard` packages
 
-On `config.json`:
+Module declaration, on `config.json`:
 
 ```json
-  "endpoints": {
-    "get": {
-      "dashboard": "http://server.url/dashboard/"
+    {
+      "type": "dashboard",
+      "endpoints": {
+        "get": "http://server.url/dashboards/"
+      }
     }
-  }
 ```
 
 A [sample fixture](https://git.startinblox.com/djangoldp-packages/djangoldp-dashboard/blob/master/djangoldp_dashboard/fixtures/sample.json) can be loaded with `./manage.py loaddata sample`.
 
+You can have multiple dashboard module, see the [related documentation](https://git.startinblox.com/components/solid-dashboard#having-multiple-dashboard).
+
+### Events
+
+The events module includes a listing of upcoming events and the capability to create new ones.
+To activate it, you need:
+
+On Server: `djangoldp_event` packages
+
+Module declaration, on `config.json`:
+
+```json
+    {
+      "type": "events",
+      "endpoints": {
+        "get": "http://server.url/events/",
+        "post": "http://server.url/events/",
+        "typeevents": "http://server.url/typeevents/",
+        "postTypeevents": "http://server.url/typeevents/"
+      }
+    }
+```
+
+You can get only future events by using:
+
+```json
+        "get": "http://server.url/events/future/",
+```
+
 ### Job Offers
 
-Job Offers includes a job board with conversation. To activate them, you need:
+Job Offers includes a job board with conversation. To activate them
+
+Community module is mandatory.
+
+You'll need:
 
 On Server: `djangoldp_joboffer`, `djangoldp_skill`, `djangoldp_upload`, `djangoldp_conversation` packages
 
-On `config.json`:
+Module declaration, on `config.json`:
 
 ```json
-  "endpoints": {
-    "get": {
-      "joboffers": "http://server.url/job-offers/"
+    {
+      "type": "jobBoard",
+      "endpoints": {
+        "get": "http://server.url/job-offers/",
+        "post": "http://server.url/job-offers/",
+        "skills": "http://server.url/skills/"
+      }
     }
-  }
 ```
 
-### Project
+### Notifications
 
-Project are a private group chat including Customer and Business Provider management. To activate them, you need:
+The notification module adds a bell with user's notification list and a badge on each menus with how much notifications are related to this resource. You'll need:
 
-On Server: `djangoldp_project` packages
+On Server: `djangoldp_notifications` packages
 
 On `config.json`:
 
 ```json
-  "endpoints": {
-    "get": {
-      "projects": "http://server.url/projects/"
-    },
-    "post": {
-      "projects": "http://server.url/projects/"
+    {
+      "type": "notification",
+      "route": false
     }
-  }
 ```
 
-### Users Directory
+### One-to-one chat
 
-Directory includes a listing of each users of your app and editable individual profile. To activate them, you need:
+One-to-one chat allow your users to chat together on a private channel.
 
-On Server: `djangoldp_skill`, `djangoldp_upload` packages
+Community & User Directory modules are mandatory.
 
-On `config.json`:
+You'll need:
+
+Module declaration, on `config.json`:
 
 ```json
-  "publicDirectory": true
+    {
+      "type": "chat",
+      "endpoints": {
+        "xmpp": "wss://xmpp-dev.startinblox.com/xmpp-websocket"
+      }
+    }
 ```
 
-## Optional community modules
+Where:
 
-### Events
+* `xmpp` is your [Prosody](https://prosody.im/) with [appropriate modules](https://git.startinblox.com/infra/prosody-modules/) configured on.
 
-The events module includes a listing of upcoming events and the capability to create new ones. 
-This module will also work inside the circles.
-To activate it, you need:
+### Polls
 
-On Server: `djangoldp_event`, `djangoldp_upload` packages
+The polls module allows user to create polls. To activate it, you need:
+
+On Server: `djangoldp_polls`, `djangoldp_conversation` packages
 
 On `config.json`:
 
 ```json
-  "endpoints": {
-    "get": {
-      "events":"http://server.url/events/",
-      "typeevents":"http://server.url/typeevents/"
-    },
-    "post": {
-      "events":"http://server.url/events/",
-      "typeevents":"http://server.url/typeevents/"
+    {
+      "type": "polls",
+      "endpoints": {
+        "get": "http://server.url/polls/",
+        "post": "http://server.url/polls/"
+      }
     }
-  }
 ```
 
-You can get only future events by using
+### Project
+
+Project are a private group chat including Customer and Business Provider management.
+
+Community module is mandatory.
+
+To activate them, you need:
+
+On Server: `djangoldp_project` packages
+
+Module declaration, on `config.json`:
+
 ```json
-    "get": {
-      "events":"http://server.url/events/future/",
+    {
+      "type": "projects",
+      "endpoints": {
+        "get": "http://server.url/projects/",
+        "post": "http://server.url/projects/",
+        "captains": "http://server.url/users/",
+        "xmpp": "wss://xmpp-dev.startinblox.com/xmpp-websocket"
+      }
     }
 ```
 
+Where:
+
+* `captains`: is your users container which contains valid captains
+* `xmpp` is your [Prosody](https://prosody.im/) with [appropriate modules](https://git.startinblox.com/infra/prosody-modules/) configured on.
+
 ### Resources
 
-The resources module includes a listing of indexed resources and the capability to index new ones. 
-This module will also work inside the circles.
+The resources module includes a listing of indexed resources and the capability to index new ones.
 To activate it, you need:
 
-On Server: `djangoldp_resource`, `djangoldp_upload`, `djangoldp_conversation` packages
+On Server: `djangoldp_resource`, `djangoldp_conversation` packages
 
-On `config.json`:
+Module declaration, on `config.json`:
 
 ```json
-  "endpoints": {
-    "get": {
-      "resources":"http://server.url/resources/",
-      "resourceskeywords":"http://server.url/keywords/",
-      "resourcestypes":"http://server.url/types/"
-    },
-    "post": {
-      "resources":"http://server.url/resources/",
-      "resourceskeywords":"http://server.url/keywords/",
-      "resourcestypes":"http://server.url/types/"
+    {
+      "type": "events",
+      "endpoints": {
+        "get": "http://server.url/resources/",
+        "post": "http://server.url/resources/",
+        "types": "http://server.url/keywords/",
+        "keywords": "http://server.url/types/",
+        "postTypes": "http://server.url/keywords/",
+        "postKeywords": "http://server.url/types/"
+      }
     }
-  }
 ```
 
-### Polls
+### User registration
 
-The polls module allows user to create polls related (or not) to circles. To activate it, you need:
+The user registration module allows users to self-register.
 
-On Server: `djangoldp_polls`, `djangoldp_upload`, `djangoldp_conversation` packages
+Community module is mandatory.
 
-On `config.json`:
+If you set `allow_self_registration` on a community, it'll disable the auto-login feature of Hubl and allow your users to self register on your application.
+
+To activate it, you need:
+
+Module declaration, on `config.json`:
 
 ```json
-  "endpoints": {
-    "get": {
-      "polls":"http://server.url/polls/"
-    },
-    "post": {
-      "polls":"http://server.url/polls/"
+    {
+      "type": "registering",
+      "parameters": {
+        "authority": "http://server.url/",
+        "authorityName": "your-authority-indentifier"
+      },
+      "endpoints": {
+        "get": "http://server.url/open-communities/"
+      }
     }
-  }
 ```
 
-## Use with docker
+Where:
 
-### Multi services
+* `authority` is the OpenID Provider. Usually, if you use `djangoldp_account` it's the same as your djangoldp server.
+* `authorityName` is a visual name of your OpenID Provider
 
-Run with a local binding on localhost:
+### Theme checker
 
-```bash
-docker-compose build
-docker-compose up -d client server
+The [Hubl theme manager](https://cdn.startinblox.com/hubl/theme/) is very handy for customer to easily customize the main colors they want to use.
+
+But developers should verify that their development use those colors to fit the customer wishes.
+
+Module declaration, on `config.json`:
+
+```json
+    {
+      "type": "themeChecker",
+      "route": false
+    }
 ```
 
-Use in CI context:
+Then you'll find the color picker tool in the header bar.
 
-```bash
-docker-compose -f docker-compose.yml build
-docker-compose -f docker-compose.yml up -d client server
-docker-compose -f docker-compose.yml run --rm e2e
+Changing the color will set them on the whole app so that you can verify that your development take them into account correctly.
+
+### Users Directory
+
+Directory includes a listing of each users of your app and editable individual profile. To activate them, you need:
+
+On Server: `djangoldp_skill` packages
+
+Community module is mandatory.
+
+Module declaration, on `config.json`:
+
+```json
+    {
+      "type": "profileDirectory",
+      "endpoints": {
+        "get": "http://server.url/users/",
+        "skills": "http://server.url/skills/",
+        "uploads": "http://server.url/upload/"
+      }
+    }
 ```
 
-Build and push the server to registry:
+### Route generation
 
-```bash
-docker build -f docker/djangoldp.docker --build-arg serve="http://localhost:8000" -t registry.startinblox.com/applications/hubl/server:0.1 .
-docker push registry.startinblox.com/applications/hubl/server:0.1
+Hubl will, by default, generate an unique route for every of your module. You can customize this route by setting a `route` attribute on your module declaration.
+
+Eg. for the Users Directory:
+
+```json
+    {
+      "type": "profileDirectory",
+      "endpoints": {
+        "get": "http://server.url/users/",
+        "skills": "http://server.url/skills/",
+        "uploads": "http://server.url/upload/"
+      },
+      "route": "directory"
+    }
 ```
 
-Note: within a Kubernetes pod all services are bound to `localhost`.
+Will lead to `http://client.url/directory` as URL to reach the module instead of the default `http://client.url/profileDirectory`.
+
+If you provide no `route`, then Hubl will use the `type` as route view name. If two modules share the same `route`, they'll get suffixed with a random unique id.
+
+Some module don't need any route to be active, set `route` to `false` so.
+
+Components can get the route of a module with `window.hubl.getRoute('componentName')`.
 
 ## Troubleshooting
 
diff --git a/config.sample.json b/config.sample.json
index 295b9c67..1a97d264 100644
--- a/config.sample.json
+++ b/config.sample.json
@@ -1,18 +1,93 @@
 {
-  "xmppWebsocket": "wss://jabber.happy-dev.fr/xmpp-websocket",
-  "clientName": "My local Hubl",
-  "clientLogo": "/images/logo.webp",
-  "authority": "http://localhost:8000/",
-  "endpoints": {
-    "get": {
-      "communities": "http://localhost:8000/open-communities/",
-      "skills": "http://localhost:8000/skills/",
-      "users": "http://localhost:8000/users/"
-    },
-    "post": {
-      "communities": "http://localhost:8000/communities/",
-      "users": "http://localhost:8000/users/",
-      "upload": "http://localhost:8000/upload/"
+  "client": {
+    "name": "Sample of a functional Hubl",
+    "logo": "https://cdn.startinblox.com/logos/webp/hubl.webp"
+  },
+  "components": [{
+      "type": "registering",
+      "parameters": {
+        "authority": "http://localhost:8000/",
+        "authorityName": "dataserver"
+      },
+      "endpoints": {
+        "get": "http://localhost:8000/open-communities/"
+      },
+      "route": false
+    },
+    {
+      "type": "notification",
+      "route": false
+    },
+    {
+      "type": "admin",
+      "route": false
+    },
+    {
+      "type": "about"
+    },
+    {
+      "type": "communities",
+      "route": false
+    },
+    {
+      "type": "dashboard",
+      "endpoints": {
+        "get": "http://localhost:8000/dashboards/"
+      }
+    },
+    {
+      "type": "profileDirectory",
+      "endpoints": {
+        "get": "http://localhost:8000/users/",
+        "skills": "http://localhost:8000/skills/",
+        "uploads": "http://localhost:8000/upload/"
+      },
+      "route": "members"
+    },
+    {
+      "type": "jobBoard",
+      "endpoints": {
+        "get": "http://localhost:8000/job-offers/",
+        "post": "http://localhost:8000/job-offers/",
+        "skills": "http://localhost:8000/skills/"
+      },
+      "route": "job-offers"
+    },
+    {
+      "type": "projects",
+      "endpoints": {
+        "get": "http://localhost:8000/projects/",
+        "post": "http://localhost:8000/projects/",
+        "captains": "http://localhost:8000/users/",
+        "users": "http://localhost:8000/users/",
+        "xmpp": "wss://xmpp-dev.startinblox.com/xmpp-websocket"
+      }
+    },
+    {
+      "type": "circles",
+      "endpoints": {
+        "get": "http://localhost:8000/circles/",
+        "post": "http://localhost:8000/circles/",
+        "owners": "http://localhost:8000/users/",
+        "users": "http://localhost:8000/users/",
+        "xmpp": "wss://xmpp-dev.startinblox.com/xmpp-websocket"
+      }
+    },
+    {
+      "type": "chat",
+      "endpoints": {
+        "xmpp": "wss://xmpp-dev.startinblox.com/xmpp-websocket"
+      },
+      "route": "messages"
+    },
+    {
+      "type": "analytics",
+      "parameters": {
+        "type": "matomo",
+        "url": "https://matomo.startinblox.com/",
+        "id": "2"
+      },
+      "route": false
     }
-  }
+  ]
 }
\ No newline at end of file
diff --git a/cypress/integration/delete-channel.spec.js b/cypress/integration/delete-channel.spec.js
index 5a4d81df..10a2d056 100644
--- a/cypress/integration/delete-channel.spec.js
+++ b/cypress/integration/delete-channel.spec.js
@@ -33,9 +33,9 @@ context('Delete Channel Browser Testing', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
-          cy.visit('/circle/@' + id + '/circle-information');
+          cy.visit('/circles/@' + id + '/circles-information');
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/circle/@' + id + '/circle-information');
+            expect(loc.pathname).to.eq('/circles/@' + id + '/circles-information');
           });
         }));
     });
@@ -43,18 +43,18 @@ context('Delete Channel Browser Testing', () => {
       cy.get(menuCountQuery.join(' ')).its('length').then(length => channelsLength = length);
     });
     it('should click button to retire the channel', () => {
-      cy.get('#circle-profile solid-delete[data-label="Supprimer le canal"] button').click();
+      cy.get('#circles-profile solid-delete[data-label="Supprimer le canal"] button').click();
     });
     it('should stay on channel edit screen', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/circle/@' + id + '/circle-information');
+            expect(loc.pathname).to.eq('/circles/@' + id + '/circles-information');
           });
         }));
     });
-    it('should check if chennel was retired', () => {
+    it('should check if channel was retired', () => {
       cy.get(menuCountQuery.join(' ')).its('length').should(length => {
         expect(length).to.eq(channelsLength - 1);
       });
diff --git a/cypress/integration/edit-channel.spec.js b/cypress/integration/edit-channel.spec.js
index 501e8b7e..58acfa4c 100644
--- a/cypress/integration/edit-channel.spec.js
+++ b/cypress/integration/edit-channel.spec.js
@@ -33,27 +33,27 @@ context('Edit Channel Browser Testing', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
-          cy.visit('/circle/@' + id + '/circle-information/circle-edit');
+          cy.visit('/circles/@' + id + '/circles-information/circles-edit');
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/circle/@' + id + '/circle-information/circle-edit');
+            expect(loc.pathname).to.eq('/circles/@' + id + '/circles-information/circles-edit');
           });
         }));
     });
     it('should enter new channel data', () => {
-      cy.get('#circle-edit input[name="name"]').clear().type(channelName);
-      cy.get('#circle-edit input[name="name"]').should('have.value', channelName);
-      cy.get('#circle-edit input[name="description"]').clear().type(description);
-      cy.get('#circle-edit input[name="description"]').should('have.value', description);
+      cy.get('#circles-edit input[name="name"]').clear().type(channelName);
+      cy.get('#circles-edit input[name="name"]').should('have.value', channelName);
+      cy.get('#circles-edit input[name="description"]').clear().type(description);
+      cy.get('#circles-edit input[name="description"]').should('have.value', description);
     });
     it('should click button to save the channel', () => {
-      cy.get('#circle-edit input[value="Enregistrer"]').click();
+      cy.get('#circles-edit input[value="Enregistrer"]').click();
     });
     it('should land on channel information screen', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/circle/@' + id + '/circle-information');
+            expect(loc.pathname).to.eq('/circles/@' + id + '/circles-information');
           });
         }));
     });
diff --git a/cypress/integration/edit-project.spec.js b/cypress/integration/edit-project.spec.js
index 171105bf..462e183c 100644
--- a/cypress/integration/edit-project.spec.js
+++ b/cypress/integration/edit-project.spec.js
@@ -35,29 +35,29 @@ context('Edit Project Browser Testing', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
-          cy.visit('/project/@' + id + '/project-information/project-edit');
+          cy.visit('/projects/@' + id + '/projects-information/projects-edit');
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/project/@' + id + '/project-information/project-edit');
+            expect(loc.pathname).to.eq('/projects/@' + id + '/projects-information/projects-edit');
           });
         }));
     });
     it('should enter new project data', () => {
-      cy.get('#project-edit input[name="customer.name"]').clear().type(customerName);
-      cy.get('#project-edit input[name="customer.name"]').should('have.value', customerName);
-      cy.get('#project-edit input[name="name"]').clear().type(projectName);
-      cy.get('#project-edit input[name="name"]').should('have.value', projectName);
-      cy.get('#project-edit textarea[name="description"]').clear().type(description);
-      cy.get('#project-edit textarea[name="description"]').should('have.value', description);
+      cy.get('#projects-edit input[name="customer.name"]').clear().type(customerName);
+      cy.get('#projects-edit input[name="customer.name"]').should('have.value', customerName);
+      cy.get('#projects-edit input[name="name"]').clear().type(projectName);
+      cy.get('#projects-edit input[name="name"]').should('have.value', projectName);
+      cy.get('#projects-edit textarea[name="description"]').clear().type(description);
+      cy.get('#projects-edit textarea[name="description"]').should('have.value', description);
     });
     it('should click button to save the project', () => {
-      cy.get('#project-edit input[value="Enregistrer"]').click();
+      cy.get('#projects-edit input[value="Enregistrer"]').click();
     });
     it('should land on project information screen', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/project/@' + id + '/project-information');
+            expect(loc.pathname).to.eq('/projects/@' + id + '/projects-information');
           });
         }));
     });
diff --git a/cypress/integration/edit-user.spec.js b/cypress/integration/edit-user.spec.js
index ff82266d..bc36816b 100644
--- a/cypress/integration/edit-user.spec.js
+++ b/cypress/integration/edit-user.spec.js
@@ -27,38 +27,38 @@ context('Edit User Browser Testing', () => {
   it('should login', () => cy.login());
   describe('User Edition process', () => {
     it('should visit the user edit screen', () => {
-      cy.visit('/profile/solid-profile-edit-profile');
+      cy.visit('/members/members-edit-profile');
       cy.location().should((loc) => {
-        expect(loc.pathname).to.eq('/profile/solid-profile-edit-profile');
+        expect(loc.pathname).to.eq('/members/members-edit-profile');
       });
     });
     /// Workaround - Routing bug - user won't land on edit profile screen
     it('should navigate to user edit screen', () => {
-      cy.get('#solid-profile-my-profile solid-link[next="solid-profile-edit-profile"]').click();
+      cy.get('#members-my-profile solid-link[next="members-edit-profile"]').click();
     });
     /// End workaround
     it('should enter new user data', () => {
-      cy.get('#solid-profile-edit-profile input[name="first_name"]').clear().type(userFirstName);
-      cy.get('#solid-profile-edit-profile input[name="first_name"]').should('have.value', userFirstName);
-      cy.get('#solid-profile-edit-profile input[name="last_name"]').clear().type(userLastName);
-      cy.get('#solid-profile-edit-profile input[name="last_name"]').should('have.value', userLastName);
-      cy.get('#solid-profile-edit-profile textarea[name="profile.job"]').clear().type(jobDescription);
-      cy.get('#solid-profile-edit-profile textarea[name="profile.job"]').should('have.value', jobDescription);
-      cy.get('#solid-profile-edit-profile input[name="profile.city"]').clear().type(city);
-      cy.get('#solid-profile-edit-profile input[name="profile.city"]').should('have.value', city);
-      cy.get('#solid-profile-edit-profile input[name="profile.phone"]').clear().type(phone);
-      cy.get('#solid-profile-edit-profile input[name="profile.phone"]').should('have.value', phone);
-      cy.get('#solid-profile-edit-profile input[name="profile.website"]').clear().type(website);
-      cy.get('#solid-profile-edit-profile input[name="profile.website"]').should('have.value', website);
+      cy.get('#members-edit-profile input[name="first_name"]').clear().type(userFirstName);
+      cy.get('#members-edit-profile input[name="first_name"]').should('have.value', userFirstName);
+      cy.get('#members-edit-profile input[name="last_name"]').clear().type(userLastName);
+      cy.get('#members-edit-profile input[name="last_name"]').should('have.value', userLastName);
+      cy.get('#members-edit-profile textarea[name="profile.job"]').clear().type(jobDescription);
+      cy.get('#members-edit-profile textarea[name="profile.job"]').should('have.value', jobDescription);
+      cy.get('#members-edit-profile input[name="profile.city"]').clear().type(city);
+      cy.get('#members-edit-profile input[name="profile.city"]').should('have.value', city);
+      cy.get('#members-edit-profile input[name="profile.phone"]').clear().type(phone);
+      cy.get('#members-edit-profile input[name="profile.phone"]').should('have.value', phone);
+      cy.get('#members-edit-profile input[name="profile.website"]').clear().type(website);
+      cy.get('#members-edit-profile input[name="profile.website"]').should('have.value', website);
     });
     it('should click button to save the user', () => {
-      cy.get('#solid-profile-edit-profile input[value="ENREGISTRER"]').click();
+      cy.get('#members-edit-profile input[value="ENREGISTRER"]').click();
     });
     it('should land on user information screen', () => {
       cy.location().should(location => {
         /// Workaround - Routing bug - route pathname won't be /profile as it should
         expect(location.pathname).to.eq('/');
-        // expect(location.pathname).to.eq('/profile');
+        // expect(location.pathname).to.eq('/members');
         /// End workaround
       });
     });
diff --git a/cypress/integration/leave-channel.spec.js b/cypress/integration/leave-channel.spec.js
index 9895e86b..03116dfb 100644
--- a/cypress/integration/leave-channel.spec.js
+++ b/cypress/integration/leave-channel.spec.js
@@ -33,7 +33,7 @@ context('Leave Channel Browser Testing', () => {
       cy.get(tableListQuery.join(' ')).its('length').as('channelsLength');
       cy.get(tableQuery.join(' ')).click();
     });
-    it('should check if chennel was left', () => {
+    it('should check if channel was left', () => {
       cy.get(tableListQuery.join(' ')).its('length').should(length => {
         expect(length).to.eq(this.channelsLength - 1);
       });
diff --git a/cypress/integration/retire-channel.spec.js b/cypress/integration/retire-channel.spec.js
index d7c3bf67..e0201d4d 100644
--- a/cypress/integration/retire-channel.spec.js
+++ b/cypress/integration/retire-channel.spec.js
@@ -33,9 +33,9 @@ context('Retire Channel Browser Testing', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
-          cy.visit('/circle/@' + id + '/circle-information/circle-edit');
+          cy.visit('/circles/@' + id + '/circles-information/circles-edit');
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/circle/@' + id + '/circle-information/circle-edit');
+            expect(loc.pathname).to.eq('/circles/@' + id + '/circles-information/circles-edit');
           });
         }));
     });
@@ -50,11 +50,11 @@ context('Retire Channel Browser Testing', () => {
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/circle/@' + id + '/circle-information/circle-edit');
+            expect(loc.pathname).to.eq('/circles/@' + id + '/circles-information/circles-edit');
           });
         }));
     });
-    it('should check if chennel was retired', () => {
+    it('should check if channel was retired', () => {
       cy.get(menuCountQuery.join(' ')).its('length').should(length => {
         expect(length).to.eq(channelsLength - 1);
       });
diff --git a/cypress/integration/retire-project.spec.js b/cypress/integration/retire-project.spec.js
index e1fc249a..fa296ced 100644
--- a/cypress/integration/retire-project.spec.js
+++ b/cypress/integration/retire-project.spec.js
@@ -33,9 +33,9 @@ context('Retire Project Browser Testing', () => {
       cy.get(menuQuery.join(' '))
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
-          cy.visit('/project/@' + id + '/project-information/project-edit');
+          cy.visit('/projects/@' + id + '/projects-information/projects-edit');
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/project/@' + id + '/project-information/project-edit');
+            expect(loc.pathname).to.eq('/projects/@' + id + '/projects-information/projects-edit');
           });
         }));
     });
@@ -50,7 +50,7 @@ context('Retire Project Browser Testing', () => {
         .invoke('attr', 'data-src')
         .then(url => cy.encodeUrl(url).then(id  => {
           cy.location().should((loc) => {
-            expect(loc.pathname).to.eq('/project/@' + id + '/project-information/project-edit');
+            expect(loc.pathname).to.eq('/projects/@' + id + '/projects-information/projects-edit');
           });
         }));
     });
diff --git a/cypress/integration/signin.spec.js b/cypress/integration/signin.spec.js
index adf1238d..8c0a9f88 100644
--- a/cypress/integration/signin.spec.js
+++ b/cypress/integration/signin.spec.js
@@ -78,7 +78,7 @@ context('Browser testing', () => {
 //        it('should open the circle information page', () => {
 //          cy.screenshot();
 //          cy.get('#navbar-router').contains(name).click();
-//          cy.get('[name="circle-information"] > li').click();
+//          cy.get('[name="circles-information"] > li').click();
 //        });
 //        it('should delete the circle', () => {
 //          cy.get('.box-button > solid-ac-checker > .button').click();
diff --git a/internal/parcel.js b/internal/parcel.js
index f6b64526..040c6504 100644
--- a/internal/parcel.js
+++ b/internal/parcel.js
@@ -32,17 +32,14 @@ const options = {
 
   let config = JSON.parse(fs.readFileSync(configPath));
 
-  if(!config.clientName) throw `[Error] (Mandatory) Missing clientName on ${configPath}`;
-  if(!config.clientLogo) throw `[Error] (Mandatory) Missing clientLogo on ${configPath}`;
-
   let manifest = {
     "lang": "fr",
     "dir": "ltr",
-    "name": config.clientName,
-    "description": `Hubl of ${config.clientName}`,
-    "short_name": config.clientName,
+    "name": config.client.name || "My Personal Hubl",
+    "description": `Hubl of ${config.client.name || "My Personal Hubl"}`,
+    "short_name": config.client.name || "My Personal Hubl",
     "icons": [{
-      "src": config.clientLogo,
+      "src": config.client.logo || '/images/logo.webp',
       "purpose": "any"
     }, {
       "src": "/images/hubl-icon-192.png",
@@ -61,7 +58,7 @@ const options = {
   }
 
   await fse.writeJSON('./src/manifest.webmanifest', manifest)
-  console.log(`Created manifest for ${config.clientName}`);
+  console.log(`Created manifest for ${config.client.name || "My Personal Hubl"}`);
 
   await fse.copy("./src/locales", "./dist/locales")
   console.log(`Copied locales to dist folder`);
diff --git a/src/components/getRoute.js b/src/components/getRoute.js
new file mode 100644
index 00000000..20fe2cbf
--- /dev/null
+++ b/src/components/getRoute.js
@@ -0,0 +1,14 @@
+window.hubl.getRoute = (type, returnFirst = false) => {
+  let availables = window.hubl.components.filter(c => c.type == type);
+  if (availables.length > 1) {
+    if (returnFirst) {
+      return availables[0].route;
+    } else {
+      console.error(`Too much components availables for route ${type}`);
+    }
+  } else if (availables.length < 1) {
+    console.error(`No component found for route ${type}`);
+  } else {
+    return availables[0].route;
+  }
+}
\ No newline at end of file
diff --git a/src/components/hubl-auto-login.js b/src/components/hubl-auto-login.js
index cf4a318e..6d1914d0 100644
--- a/src/components/hubl-auto-login.js
+++ b/src/components/hubl-auto-login.js
@@ -1,15 +1,17 @@
-import { Sib } from 'https://cdn.skypack.dev/@startinblox/core@0.15';
+import {
+  Sib
+} from 'https://cdn.skypack.dev/@startinblox/core@0.15';
 
 export const HublAutoLogin = {
   name: 'hubl-auto-login',
   created() {
     document
-    .querySelectorAll(".loggedIn-loader")
-    .forEach(el => (el.style.display = "flex"));
+      .querySelectorAll(".loggedIn-loader")
+      .forEach(el => (el.style.display = "flex"));
     window.dispatchEvent(
       new CustomEvent('requestNavigation', {
         detail: {
-          route: "dashboard"
+          route: window.hubl.getRoute("dashboard", true)
         }
       }),
     );
diff --git a/src/components/hubl-reactivity.js b/src/components/hubl-reactivity.js
index e661bfef..79c134dc 100644
--- a/src/components/hubl-reactivity.js
+++ b/src/components/hubl-reactivity.js
@@ -1,4 +1,8 @@
-import { store, Sib, StoreMixin } from 'https://cdn.skypack.dev/@startinblox/core@0.15';
+import {
+  store,
+  Sib,
+  StoreMixin
+} from 'https://cdn.skypack.dev/@startinblox/core@0.15';
 
 export const HublReactivity = {
   name: 'hubl-reactivity',
diff --git a/src/components/hubl-search-users.js b/src/components/hubl-search-users.js
index acc5e7d8..01537359 100644
--- a/src/components/hubl-search-users.js
+++ b/src/components/hubl-search-users.js
@@ -1,4 +1,6 @@
-import { widgetFactory } from 'https://cdn.skypack.dev/@startinblox/core@0.15';
+import {
+  widgetFactory
+} from 'https://cdn.skypack.dev/@startinblox/core@0.15';
 
 const HublSearchUsers = widgetFactory(
   'hubl-search-users',
@@ -12,4 +14,6 @@ const HublSearchUsers = widgetFactory(
   >`
 );
 
-export { HublSearchUsers }
\ No newline at end of file
+export {
+  HublSearchUsers
+}
\ No newline at end of file
diff --git a/src/components/hubl-status.js b/src/components/hubl-status.js
index 319096df..f6d6fc09 100644
--- a/src/components/hubl-status.js
+++ b/src/components/hubl-status.js
@@ -1,4 +1,7 @@
-import { widgetFactory, Helpers } from 'https://cdn.skypack.dev/@startinblox/core@0.15';
+import {
+  widgetFactory,
+  Helpers
+} from 'https://cdn.skypack.dev/@startinblox/core@0.15';
 import SlimSelect from 'https://cdn.skypack.dev/slim-select@1.23';
 
 const HublStatus = widgetFactory(
@@ -18,10 +21,14 @@ const HublStatus = widgetFactory(
   formWidget => {
     let select = formWidget.querySelector('select');
     if (!select) return;
-    const slimSelect = new SlimSelect({select: select});
+    const slimSelect = new SlimSelect({
+      select: select
+    });
     Helpers.importCSS('https://dev.jspm.io/slim-select/dist/slimselect.min.css');
     select.addEventListener('change', () => slimSelect.render());
   },
 );
 
-export { HublStatus }
\ No newline at end of file
+export {
+  HublStatus
+}
\ No newline at end of file
diff --git a/src/components/sentry.js b/src/components/sentry.js
index e4349e4d..bdbb7f2a 100644
--- a/src/components/sentry.js
+++ b/src/components/sentry.js
@@ -1,4 +1,4 @@
-if(typeof Sentry !== 'undefined') {
+if (typeof Sentry !== 'undefined') {
     Sentry.init({
         dsn: 'https://b4b29557689049a39168599577adb940@sentry.startinblox.com/4',
         integrations: [new Sentry.Integrations.BrowserTracing()],
diff --git a/src/context.pug b/src/context.pug
index 5967859d..ae2ff5b5 100644
--- a/src/context.pug
+++ b/src/context.pug
@@ -1,9 +1,10 @@
+-
+  const context = JSON.stringify({
+    "inbox": "http://happy-dev.fr/owl/#inbox",
+    "object": "http://happy-dev.fr/owl/#object",
+    "author": "http://happy-dev.fr/owl/#author",
+    "account": "http://happy-dev.fr/owl/#account",
+    "jabberID": "foaf:jabberID"
+  })
 //- Context - Fix for default context
-script(data-default-context, type="application/ld+json")
-  | {
-  |     "inbox": "http://happy-dev.fr/owl/#inbox",
-  |     "object": "http://happy-dev.fr/owl/#object",
-  |     "author": "http://happy-dev.fr/owl/#author",
-  |     "account": "http://happy-dev.fr/owl/#account",
-  |     "jabberID": "foaf:jabberID"
-  | }
\ No newline at end of file
+script(data-default-context, type="application/ld+json")!=context
\ No newline at end of file
diff --git a/src/dependencies.pug b/src/dependencies.pug
index ef3c86c5..4e22af0f 100644
--- a/src/dependencies.pug
+++ b/src/dependencies.pug
@@ -1,49 +1,52 @@
 script(type="module" src="https://cdn.skypack.dev/@startinblox/core@0.15" defer)
 //- script(type="module" src="/lib/sib-core/dist/index.js" defer)
 
-script(type="module" src="https://cdn.skypack.dev/@startinblox/oidc@0.13" defer)
-//- script(type="module" src="/lib/sib-auth/index.js" defer)
-
 script(type="module" src="https://cdn.skypack.dev/@startinblox/router@0.11" defer)
 //- script(type="module" src="/lib/sib-router/src/index.js" defer)
 
-script(type="module" src="https://cdn.skypack.dev/@startinblox/component-notifications@0.11" defer)
-//- script(type="module" src="/lib/sib-notifications/index.js" defer)
+- const componentSet = new Set(components.map(c=>c.type));
+
+if componentSet.has("autoLogin") || componentSet.has("registering")
+  script(type="module" src="https://cdn.skypack.dev/@startinblox/oidc@0.13" defer)
+  //- script(type="module" src="/lib/sib-auth/index.js" defer)
+
+if componentSet.has("chat") || componentSet.has("circles") || componentSet.has("projects")
+  script(type="module" src="https://cdn.skypack.dev/@startinblox/component-chat@4.1" defer)
+  //- script(type="module" src="/lib/solid-xmpp-chat/dist/index.js" defer)
 
-if themeChecker
-    script(src="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js")
-    link(rel='stylesheet', href='https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/nano.min.css')
+if componentSet.has("dashboard")
+  script(type="module" src="https://cdn.skypack.dev/@startinblox/component-dashboard@3.0" defer)
+  //- script(type="module" src="/lib/solid-dashboard/dist/index.js" defer)
 
-if endpoints.get
-  if endpoints.get.events && endpoints.get.typeevents
-    script(type="module", src="https://cdn.skypack.dev/@startinblox/component-event@2.1", defer)
-    //- script(type="module", src="/lib/solid-event/solid-event.js", defer)
+if componentSet.has("events")
+  script(type="module", src="https://cdn.skypack.dev/@startinblox/component-event@2.1", defer)
+  //- script(type="module", src="/lib/solid-event/solid-event.js", defer)
 
-  //- Disabled - Not in core@0.15
-  //- if endpoints.get.resources && endpoints.get.resourceskeywords && endpoints.get.resourcestypes
-  //-   script(type="module" src="https://cdn.skypack.dev/@startinblox/component-resource@1.2" defer)
-    //- script(type="module" src="/lib/sib-resource/sib-resource.js" defer)
+if componentSet.has("events") || componentSet.has("polls") || componentSet.has("resources")
+  script(type="module" src="https://cdn.skypack.dev/@startinblox/component-conversation@0.9" defer)
 
-  if endpoints.get.joboffers
-    script(type="module" src="https://cdn.skypack.dev/@startinblox/component-job-board@3.1" defer)
-    //- script(type="module" src="/lib/solid-job-board/dist/index.js" defer)
+if componentSet.has("jobBoard")
+  script(type="module" src="https://cdn.skypack.dev/@startinblox/component-job-board@4.0" defer)
+  //- script(type="module" src="/lib/solid-job-board/dist/index.js" defer)
 
-  if endpoints.get.uploads && endpoints.get.skills && endpoints.get.users
-    script(type="module" src="https://cdn.skypack.dev/@startinblox/component-directory@3.3" defer)
-    //- script(type="module" src="/lib/solid-directory/dist/index.js" defer)
+if componentSet.has("notification")
+  script(type="module" src="https://cdn.skypack.dev/@startinblox/component-notifications@0.11" defer)
+  //- script(type="module" src="/lib/sib-notifications/index.js" defer)
 
-  if endpoints.get.dashboards
-    script(type="module" src="https://cdn.skypack.dev/@startinblox/component-dashboard@2.0" defer)
-    //- script(type="module" src="/lib/solid-dashboard/dist/index.js" defer)
+//- Disabled - Not in core@0.15
+//- if componentSet.has("polls")
+//-   script(type="module" src="https://cdn.skypack.dev/@startinblox/component-poll@1.2" defer)
+//-   //- script(type="module" src="/lib/sib-polls-component/index.js" defer)
 
-  if endpoints.get.users
-    script(type="module" src="https://cdn.skypack.dev/@startinblox/component-chat@4.1" defer)
-    //- script(type="module" src="/lib/solid-xmpp-chat/dist/index.js" defer)
+//- Disabled - Not in core@0.15
+//- if componentSet.has("resources")
+//-   script(type="module" src="https://cdn.skypack.dev/@startinblox/component-resource@1.2" defer)
+//-   //- script(type="module" src="/lib/sib-resource/sib-resource.js" defer)
 
-  //- Disabled - Not in core@0.15
-  //- if endpoints.get.polls
-  //-   script(type="module" src="https://cdn.skypack.dev/@startinblox/component-poll@1.2" defer)
-    //- script(type="module" src="/lib/sib-polls-component/index.js" defer)
+if componentSet.has("themeChecker")
+  script(src="https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js" defer)
+  link(rel='stylesheet', href='https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/nano.min.css')
 
-  if endpoints.get.polls || endpoints.get.events || endpoints.get.resources
-    script(type="module" src="https://cdn.skypack.dev/@startinblox/component-conversation@0.9" defer)
+if componentSet.has("profileDirectory")
+  script(type="module" src="https://cdn.skypack.dev/@startinblox/component-directory@4.0" defer)
+  //- script(type="module" src="/lib/solid-directory/dist/index.js" defer)
diff --git a/src/hubl-router.pug b/src/hubl-router.pug
new file mode 100644
index 00000000..3d0fb8df
--- /dev/null
+++ b/src/hubl-router.pug
@@ -0,0 +1,56 @@
+//-
+  Hubl router declaration for latter generation
+  Create a window.hubl.components, accessible by all components with the route declaration.
+  Components can also get benefits from the `getRoute` function
+  Eg.
+  ```
+    window.hubl.getRoute('chat', true)
+  ```
+  will return the route of the first chat component, if exists, or triggers an error.
+-
+  let routes = new Set();
+  const getRoute = (type, returnFirst = false) => {
+    let availables = components.filter(c=>c.type==type);
+    if(availables.length > 1) {
+      if(returnFirst) {
+        return availables[0].route;
+      } else {
+        console.error(`Too much components availables for route ${type}`);
+      }
+    } else if(availables.length < 1) {
+      console.error(`No component found for route ${type}`);
+    } else {
+      return availables[0].route;
+    }
+  }
+  const getComponent = (type, returnFirst = false) => {
+    let availables = components.filter(c=>c.type==type);
+    if(availables.length > 1) {
+      if(returnFirst) {
+        return availables[0];
+      } else {
+        console.error(`Too much components availables for type ${type}`);
+      }
+    } else if(availables.length < 1) {
+      console.error(`No component found for type ${type}`);
+    } else {
+      return availables[0];
+    }
+  }
+
+for component of components
+  -
+    if(typeof component.route === 'undefined') {
+      component.route = component.type;
+    }
+    if(component.route) {
+      component.uniq = Math.random().toString(16).slice(2);
+      let route = component.route;
+      if (routes.has(component.route)) {
+        route += "-" + component.uniq;
+      }
+      routes.add(route);
+      component.route = route;
+    }
+- const hublComponents = `window.hubl={};window.hubl.components = ${JSON.stringify(components)};`;
+script!=hublComponents
\ No newline at end of file
diff --git a/src/index.pug b/src/index.pug
index 48e6c472..6475e964 100644
--- a/src/index.pug
+++ b/src/index.pug
@@ -3,13 +3,13 @@ html(lang="en")
   head
     meta(charset="UTF-8")
 
-    title #{clientName || "My Personal Hubl"}
+    title #{client.name || "My Personal Hubl"}
 
     meta(name="viewport", content="width=device-width, initial-scale=1.0")
     meta(http-equiv="X-UA-Compatible", content="ie=edge")
 
-    if clientFavicon
-      link(rel="icon" type="image/png" href=`${clientFavicon}`)
+    if client.favicon
+      link(rel="icon" type="image/png" href=`${client.favicon}`)
     else
       link(rel="icon" type="image/webp" href="./images/favicon.webp")
 
@@ -18,13 +18,16 @@ html(lang="en")
 
     link(rel='stylesheet', href='/styles/index.scss')
 
-    if clientCSS
-      link(rel='stylesheet', href=`${clientCSS}`)
+    if client.css
+      link(rel='stylesheet', href=`${client.css}`)
 
     link(rel="manifest" href="/manifest.webmanifest")
 
     script(src="https://browser.sentry-cdn.com/5.25.0/bundle.tracing.min.js" defer)
 
+    include hubl-router.pug
+
+    script(type="module" src="/components/getRoute.js" defer)
     script(type="module" src="/components/sentry.js" defer)
     script(type="module" src="/components/hubl-auto-login.js" defer)
     script(type="module" src="/components/hubl-search-users.js" defer)
@@ -40,235 +43,152 @@ html(lang="en")
     script(src="index.js" defer)
 
   body.bg-color-grey
-    if endpoints.get && endpoints.post
-      .notLoggedIn(style='visibility:hidden;')
-        sib-auth(style='display:none!important')
-          sib-auth-provider(
-            data-authority=`${authority}`
-            data-id=`${authorityName || "authority"}`
-            data-client-name=`${clientName || "Hubl"}`
-          )
 
-        include views/partials/notifications.pug
+    if componentSet.has("autoLogin") || componentSet.has("registering")
+      for component of components
+        if component.type == "autoLogin" || component.type == "registering"
+          if component.parameters
+            if component.parameters.authority
+                sib-auth(style='display:none!important')
+                  sib-auth-provider(
+                    data-authority=`${component.parameters.authority}`
+                    data-id=`${component.parameters.authorityName || "authority"}`
+                    data-client-name=`${client.name || "My Personal Hubl"}`
+                  )
+
+    if componentSet.has("registering")
+      include views/page-registering.pug
+
+    .notLoggedIn(style='visibility:hidden;')
+      header#header.segment.full.padding-left-large.padding-right-large.sm-padding-right-xsmall.sm-padding-left-small.shadow-small.text-disable-selection.bg-color-white
+        include views/partials/header.pug
+
+      nav#main__menu.scrollbar-nav.segment.bg-color-heading.text-top.quarter.text-disable-selection.jsLeftMenu
+        include views/partials/menu-left.pug
+
+      main#content.segment.three-quarter.sm-full.text-top
+
         include views/partials/widgets.pug
 
-        header#header.segment.full.padding-left-large.padding-right-large.sm-padding-right-xsmall.sm-padding-left-small.shadow-small.text-disable-selection.bg-color-white
-          include views/partials/header.pug
-
-        nav#main__menu.scrollbar-nav.segment.bg-color-heading.text-top.quarter.text-disable-selection.jsLeftMenu
-          include views/partials/menu-left.pug
-
-        main#content.segment.three-quarter.sm-full.text-top
-
-          if endpoints.get.dashboards
-            #dashboard(hidden, data-view="dashboard").scrollbar-content
-              include views/page-dashboard.pug
-
-          if publicDirectory && endpoints.get.users
-            #members(hidden, data-view="members", no-render).scrollbar-content
-              hubl-reactivity(bind-user nested-field="profile" target-src="store://user")
-              hubl-reactivity(bind-user nested-field="account" target-src="store://user")
-              include views/page-directory.pug
-          
-          if endpoints.get.projects
-            #project(hidden, data-view="project").with-sidebar.whitespace-normal
-              hubl-reactivity(bind-user nested-field='inbox' target-src="store://user.projects")
-              hubl-reactivity(bind-user nested-field="projects" target-src="store://user")
-              hubl-reactivity(data-src=`${endpoints.post.projects}joinable/` target-src=`${endpoints.get.projects}`)
-              hubl-reactivity(data-src=`${endpoints.post.projects}` target-src=`${endpoints.get.projects}`)
-              hubl-reactivity(bind-user nested-field="projects" target-src=`${endpoints.post.projects}`)
-              hubl-reactivity(bind-user nested-field="projects" target-src=`${endpoints.post.projects}joinable/`)
-              hubl-reactivity(data-src=`${endpoints.get.projects}joinable/` target-src=`${endpoints.get.projects}`)
-              hubl-reactivity(bind-user nested-field="projects" target-src=`${endpoints.get.projects}`)
-              hubl-reactivity(bind-user nested-field="projects" target-src=`${endpoints.get.projects}joinable/`)
-              include views/page-project.pug
-
-          if endpoints.get.circles
-            #circle(hidden, data-view="circle").with-sidebar.whitespace-normal
-              hubl-reactivity(bind-user nested-field='inbox' target-src="store://user.circles")
-              hubl-reactivity(bind-user nested-field="circles" target-src="store://user")
-              hubl-reactivity(data-src=`${endpoints.post.circles}joinable/` target-src=`${endpoints.get.circles}`)
-              hubl-reactivity(data-src=`${endpoints.post.circles}` target-src=`${endpoints.get.circles}`)
-              hubl-reactivity(bind-user nested-field="circles" target-src=`${endpoints.post.circles}`)
-              hubl-reactivity(bind-user nested-field="circles" target-src=`${endpoints.post.circles}joinable/`)
-              hubl-reactivity(data-src=`${endpoints.get.circles}joinable/` target-src=`${endpoints.get.circles}`)
-              hubl-reactivity(bind-user nested-field="circles" target-src=`${endpoints.get.circles}`)
-              hubl-reactivity(bind-user nested-field="circles" target-src=`${endpoints.get.circles}joinable/`)
-              include views/page-circle.pug
-
-          if endpoints.get.users
-            #messages(hidden, data-view="messages", no-render).whitespace-normal
-              hubl-reactivity(bind-user nested-field='inbox' target-src="store://user.contacts")
-              include views/page-messages.pug
-
-          if endpoints.get.polls
-              #polls(hidden, data-view="polls").with-sidebar
-                include views/page-polls.pug
-
-          if endpoints.get.events
-            #events(hidden, data-view="events").scrollbar-content.bg-color-white
-              include views/page-events.pug
-
-          if endpoints.get.resources
-            #resources(hidden, data-view="resources")
-              include views/page-resources.pug
-
-          #admin
-            include views/page-admin.pug
-
-          #about(hidden, data-view="about", no-render)
-            include views/page-about.pug
-            
-          if endpoints.get.skills && endpoints.post.uploads && endpoints.post.users
-            #profile(hidden, data-view="profile", no-render).scrollbar-content
-              include views/page-profile.pug
-          
-          if endpoints.get.joboffers
-            #job-offers(hidden, data-view="job-offers", no-render).scrollbar-content
-              hubl-reactivity(data-src=`${endpoints.post.joboffers}current/` target-src=`${endpoints.get.joboffers}`)
-              hubl-reactivity(data-src=`${endpoints.post.joboffers}expired/` target-src=`${endpoints.get.joboffers}`)
-              hubl-reactivity(data-src=`${endpoints.post.joboffers}` target-src=`${endpoints.get.joboffers}`)
-              hubl-reactivity(data-src=`${endpoints.get.joboffers}current/` target-src=`${endpoints.get.joboffers}`)
-              hubl-reactivity(data-src=`${endpoints.get.joboffers}current/` target-src=`${endpoints.get.joboffers}expired/`)
-              hubl-reactivity(data-src=`${endpoints.get.joboffers}expired/` target-src=`${endpoints.get.joboffers}`)
-              hubl-reactivity(bind-user nested-field="joboffers" target-src=`${endpoints.get.joboffers}expired/`)
-              hubl-reactivity(bind-user nested-field="joboffers" target-src=`${endpoints.get.joboffers}`)
-              hubl-reactivity(bind-user nested-field="joboffers" target-src=`${endpoints.get.joboffers}current/`)
-              include views/page-job-offers.pug
-
-      #login(data-view="login", hidden).segment.full.bg-color-secondary.text-center.index-community.loggedIn
-        .segment.half.sm-full.bg-color-white.text-center
-          .segment.half.sm-full
-            div.community-logo
-              img(src=clientLogo style='max-width:100%;max-height:100%;')
-            p.text-xlarge.text-semibold.margin-top-xxlarge.line-xlarge(data-trans="communities.index.youKnow")
-            button.segment.full.sm-three-quarter.button.text-xsmall.text-bold.text-uppercase.color-secondary.bordered.padding-bottom.xlarge.padding-top.xlarge.community-button#loginButton(
-              data-trans="communities.index.login"
-            )
-            p.text-xlarge.text-semibold.margin-top-xxlarge.line-xlarge(data-trans="communities.index.newUser")
-            solid-widget(name='hubl-index-community-logo')
-              template ${value != "" ? `<div class="community-button-flexed"><img src="${value}" style="max-width:100%;max-height:80px" class="padding-xsmall" /></div>` : ""}
-            solid-widget(name='hubl-index-community-text')
-              template
-                .community-button-flexed-large.whitespace-normal
-                  span(data-trans="communities.index.createAccount")
-                  span &nbsp;
-                  span ${value}
-            solid-widget(name='hubl-index-select-community')
-              template
-                solid-link.segment.full.sm-three-quarter.button.text-xsmall.text-bold.text-uppercase.color-secondary.bordered.padding-bottom.xlarge.padding-top.xlarge.margin-top-xsmall.community-button.community-button-flex-container(
-                  next='join-community'
-                  data-src='${src}'
-                )
-                  solid-display(
-                    data-src='${src}'
-                    fields='logo, name'
-                    widget-logo='hubl-index-community-logo'
-                    widget-name='hubl-index-community-text'
+        for component of components
+
+          if component.route
+            //- Components declaration with route (no `route` attribute or `route`="something")
+            div(
+              id=component.route
+              data-view=component.route
+              hidden
+            )&attributes({"no-render": component.noRender})
+
+              if component.type == "about"
+                include views/page-about.pug
+
+              if component.type == "chat"
+                .whitespace-normal
+                  hubl-reactivity(bind-user nested-field='inbox' target-src="store://user.contacts")
+                  include views/page-messages.pug
+
+              if component.type == "circles"
+                .with-sidebar.whitespace-normal
+                  hubl-reactivity(bind-user nested-field='inbox' target-src="store://user.circles")
+                  hubl-reactivity(bind-user nested-field="circles" target-src="store://user")
+                  hubl-reactivity(data-src=`${component.endpoints.get}joinable/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(data-src=`${component.endpoints.post}` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="circles" target-src=`${component.endpoints.post}`)
+                  hubl-reactivity(bind-user nested-field="circles" target-src=`${component.endpoints.post}joinable/`)
+                  hubl-reactivity(data-src=`${component.endpoints.get}joinable/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="circles" target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="circles" target-src=`${component.endpoints.get}joinable/`)
+                  include views/page-circle.pug
+
+              if component.type == "dashboard"
+                .scrollbar-content
+                  include views/page-dashboard.pug
+
+              if component.type == "events"
+                .scrollbar-content.bg-color-white
+                  include views/page-events.pug
+
+              if component.type == "jobBoard"
+                .scrollbar-content
+                  hubl-reactivity(data-src=`${component.endpoints.post}current/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(data-src=`${component.endpoints.post}expired/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(data-src=`${component.endpoints.post}` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(data-src=`${component.endpoints.get}current/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(data-src=`${component.endpoints.get}current/` target-src=`${component.endpoints.get}expired/`)
+                  hubl-reactivity(data-src=`${component.endpoints.get}expired/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="joboffers" target-src=`${component.endpoints.get}expired/`)
+                  hubl-reactivity(bind-user nested-field="joboffers" target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="joboffers" target-src=`${component.endpoints.get}current/`)
+                  include views/page-job-board.pug
+
+              if component.type == "polls"
+                .with-sidebar
+                  include views/page-polls.pug
+
+              if component.type == "projects"
+                .with-sidebar.whitespace-normal
+                  hubl-reactivity(bind-user nested-field='inbox' target-src="store://user.projects")
+                  hubl-reactivity(bind-user nested-field="projects" target-src="store://user")
+                  hubl-reactivity(data-src=`${component.endpoints.post}joinable/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(data-src=`${component.endpoints.post}` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="projects" target-src=`${component.endpoints.post}`)
+                  hubl-reactivity(bind-user nested-field="projects" target-src=`${component.endpoints.post}joinable/`)
+                  hubl-reactivity(data-src=`${component.endpoints.get}joinable/` target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="projects" target-src=`${component.endpoints.get}`)
+                  hubl-reactivity(bind-user nested-field="projects" target-src=`${component.endpoints.get}joinable/`)
+                  include views/page-project.pug
+
+              if component.type == "resources"
+                #resources(hidden, data-view="resources")
+                  include views/page-resources.pug
+
+              if component.type == "profileDirectory"
+                .scrollbar-content
+                  hubl-reactivity(bind-user nested-field="profile" target-src="store://user")
+                  hubl-reactivity(bind-user nested-field="account" target-src="store://user")
+                  include views/page-directory.pug
+          else
+            //- Components declaration without any route (`route`="false") but that need some code declaration
+
+            if component.type == "admin"
+              include views/page-admin.pug
+
+            if component.type == "analytics"
+              if component.parameters
+                if component.parameters.type && component.parameters.url && component.parameters.url
+                  solid-analytics(
+                    type=`${component.parameters.type}`
+                    url=`${component.parameters.url}`
+                    id=`${component.parameters.id}`
                   )
-            if endpoints.get.communities
-              div.loader#hubl-index-community-selector-loader
-                div
-                div
-                div
-                div
-              solid-display.community-flex-container(
-                data-src=`${endpoints.get.communities}`
-                fields='action'
-                action-action='action'
-                widget-action='hubl-index-select-community'
-                loader-id='hubl-index-community-selector-loader'
-                order-asc='name'
-                empty-widget='hubl-auto-login'
-                id='hubl-index-community-selector'
-              )
-
-      #join-community(data-view="join-community", hidden, no-render).segment.full.bg-color-secondary.text-center.index-community.loggedIn
-        .segment.half.sm-full.bg-color-white.text-center
-          .segment.half.sm-full
-            solid-widget(name="hubl-index-community-join-logo")
-              template
-                img(src="${value}" style="max-width:100%;max-height:100%;")
-            solid-display(
-              bind-resources
-              fields="logo"
-              widget-logo="hubl-index-community-join-logo"
-              class-logo='community-logo'
-              default-logo=clientLogo
-            )
-            solid-widget(name='hubl-input-type-password')
-              template
-                label ${label}
-                input(
-                  type="password"
-                  name="user.password"
-                  required
-                  data-holder
-                )
-            solid-widget(name='hubl-input-type-email')
-              template
-                label ${label}
-                input(
-                  type="email"
-                  name="user.email"
-                  required
-                  data-holder
-                )
-            solid-form.segment.full.padding-top-xlarge.padding-very-xxlarge.sm-padding-xsmall.sm-padding-top-medium.whitespace-normal.form(
-              bind-resources
-              nested-field='members'
-              fields='user.first_name, user.last_name, user.email, user.username, user.password'
-              label-user.first_name='Prénom*'
-              label-user.last_name='Nom*'
-              label-user.email='E-mail*'
-              label-user.password='Mot de passe*'
-              data-trans='label-user.password=communities.index.password;label-user.email=communities.index.email;label-user.last_name=communities.index.last_name;label-user.first_name=communities.index.first_name;submit-button=communities.index.formCreateAccount'
-              widget-user.first_name='solid-form-text-label'
-              widget-user.last_name='solid-form-text-label'
-              widget-user.email='hubl-input-type-email'
-              widget-user.password='hubl-input-type-password'
-              widget-user.username='solid-form-hidden'
-              class-user.first_name='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
-              class-user.last_name='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
-              class-user.email='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
-              class-user.password='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
-              required-user.first_name
-              required-user.last_name
-              required-user.email
-              required-user.password
-              pattern-user.first_name='.+'
-              pattern-user.last_name='.+'
-              value-user.username='generate-an-username'
-              submit-button=''
-              id='user-creation-form'
-              next='dashboard'
-            )
-
-      .loggedIn-loader.bg-color-grey(style='position:fixed;width:100%;height:100%;;z-index:999999;top:0;left:0;display:flex;align-items:center;justify-content:center;')
-        div
-          div.loader
-            div
-            div
-            div
-            div
-          div#something-goes-wrong(hidden) 
-            br
-            span(data-trans="errors.somethingGoesWrong")
-            span &nbsp;
-            a(data-trans='errors.reload' href='/')
-
-      div(
-        id="swal-content-text"
-        hidden
-        data-trans="success")
-
-      if analytics
-        each provider in analytics
-          if provider.type && provider.url && provider.url
-              solid-analytics(
-                type=`${provider.type}`
-                url=`${provider.url}`
-                id=`${provider.id}`
-              )
-    else
-      h1(style='color:red') Invalid config.json (missing `endpoints.get` or `endpoints.post`)
+
+            if component.type == "notification"
+              include views/partials/notifications.pug
+
+        if componentSet.has('profileDirectory')
+          .scrollbar-content(
+            id=`${getRoute("profileDirectory", true)}-profile`
+            hidden
+            data-view=`${getRoute("profileDirectory", true)}-profile`
+            no-render
+          )
+            include views/page-profile.pug
+
+    .loggedIn-loader.bg-color-grey.global-loader
+      div
+        div.loader
+          div
+          div
+          div
+          div
+        div#something-goes-wrong(hidden) 
+          br
+          span(data-trans="errors.somethingGoesWrong")
+          span &nbsp;
+          a(data-trans='errors.reload' href='/')
+
+    div(
+      id="swal-content-text"
+      hidden
+      data-trans="success")
diff --git a/src/scripts/firefox-scroll.js b/src/scripts/firefox-scroll.js
deleted file mode 100644
index c3428079..00000000
--- a/src/scripts/firefox-scroll.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// document.addEventListener("DOMContentLoaded", () => {
-//   const resizeChat = () => {
-//     let isMobile = window.innerWidth < 993;
-//     let isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
-//     let isFirefoxMobile = navigator.platform.toLowerCase().indexOf("mobile") > -1 || navigator.platform.toLowerCase().indexOf("tablet") > -1;
-//     let chatBox = Array.from(document.querySelectorAll("solid-xmpp-chat"))
-//       .map((el) => el.shadowRoot ? el.shadowRoot.getElementById("conversejs") : false)
-//       .filter((el) => el)
-//       .pop();
-//     if (chatBox) {
-//       let chatTextArea = chatBox.querySelector(".message-form-container");
-//       let ischatTextArea = setInterval(() => {
-//         chatTextArea = chatBox.querySelector(".message-form-container");
-//         if (chatTextArea) {
-//           clearInterval(ischatTextArea);
-//           if (
-//             chatBox.getBoundingClientRect().height -
-//             chatTextArea.getBoundingClientRect().height !=
-//             chatTextArea.offsetTop
-//           ) {
-//             let viewportChat = Array.from(
-//               document.querySelectorAll("#viewport .chat-view")
-//             );
-//             viewportChat.forEach(
-//               (c) => (c.style.height = isMobile ? (isFirefox && isFirefoxMobile) ? "calc(100vh - 106px - 57px)" : "calc(100vh - 106px)" : "calc(100vh - 64px - 83px)")
-//             );
-//           }
-//         }
-//       }, 15);
-//     }
-//   };
-//   resizeChat();
-
-//   let isbody = setInterval(() => {
-//     if (document.body) {
-//       clearInterval(isbody);
-//       resizeChat();
-//     }
-//   }, 50);
-
-//   window.addEventListener("load", () => {
-//     setTimeout(() => {
-//       resizeChat();
-//     }, 0);
-//   });
-
-//   let windowResizing;
-//   window.addEventListener("resize", () => {
-//     windowResizing = setTimeout(() => {
-//       clearInterval(windowResizing);
-//       resizeChat();
-//     }, 50);
-//   });
-
-//   document.addEventListener("navigate", () => {
-//     setTimeout(() => {
-//       resizeChat();
-//     }, 0);
-//   });
-// });
\ No newline at end of file
diff --git a/src/scripts/intl.js b/src/scripts/intl.js
index 116f47d6..fbf0abc8 100644
--- a/src/scripts/intl.js
+++ b/src/scripts/intl.js
@@ -41,8 +41,8 @@ class JsI18n {
         } else {
           // https://git.startinblox.com/framework/sib-core/issues/733
           if (attr.startsWith('label-')) {
-            let label = node.querySelector('[name="'+attr.replace("label-", "")+'"] > label');
-            if(label != null) {
+            let label = node.querySelector('[name="' + attr.replace("label-", "") + '"] > label');
+            if (label != null) {
               this.translateNodeContent(label, k);
             }
           }
@@ -61,14 +61,14 @@ class JsI18n {
     if (node != null && translation != undefined) {
       if (node.nodeType == 1) { //Element
         try {
-          if(node.innerHTML != translation)
+          if (node.innerHTML != translation)
             node.innerHTML = translation;
         } catch (e) {
-          if(node.text != translation)
+          if (node.text != translation)
             node.text = translation;
         }
       } else if (node.nodeType == 2) { //Attribute
-        if(node.value != translation)
+        if (node.value != translation)
           node.value = translation;
       }
     }
@@ -185,7 +185,7 @@ document.addEventListener("DOMContentLoaded", () => {
   let timer;
   (new MutationObserver((mutations) => {
     mutations.forEach(mutation => {
-      if(mutation.target.attributes["data-trans"] != null) {
+      if (mutation.target.attributes["data-trans"] != null) {
         // Render the target of the mutation instantly
         jsI18n.processNode(mutation.target);
         // Then wait one arbitrary second to re-render the whole document in case a widget re-rendered
diff --git a/src/scripts/login-element-visibility.js b/src/scripts/login-element-visibility.js
index dcf0ea75..e46f07b6 100644
--- a/src/scripts/login-element-visibility.js
+++ b/src/scripts/login-element-visibility.js
@@ -1,55 +1,59 @@
 window.requestLogin = false;
 document.addEventListener("DOMContentLoaded", function () {
-  document
-    .querySelector("sib-auth")
-    .getUser()
-    .then(user => {
-      if (user !== null) {
-        document
-          .querySelectorAll(".notLoggedIn")
-          .forEach(el => (el.style.visibility = "visible"));
-        document
-          .querySelectorAll(".loggedIn")
-          .forEach(el => (el.style.display = "none"));
-        document
-          .querySelectorAll(".loggedIn-loader")
-          .forEach(el => (el.style.display = "none"));
-      } else {
-        window.requestLogin = true;
-        window.dispatchEvent(
-          new CustomEvent('requestNavigation', {
-            detail: {
-              route: "login",
-              wanted: true
-            }
-          }),
-        );
-        document
-          .querySelectorAll(".loggedIn-loader")
-          .forEach(el => (el.style.display = "none"));
-      }
-    });
+  const sibAuth = document.querySelector("sib-auth");
+  if (sibAuth) {
+    sibAuth.getUser()
+      .then(user => {
+        if (user !== null) {
+          document
+            .querySelectorAll(".notLoggedIn")
+            .forEach(el => (el.style.visibility = "visible"));
+          document
+            .querySelectorAll(".loggedIn")
+            .forEach(el => (el.style.display = "none"));
+          document
+            .querySelectorAll(".loggedIn-loader")
+            .forEach(el => (el.style.display = "none"));
+        } else {
+          window.requestLogin = true;
+          window.dispatchEvent(
+            new CustomEvent('requestNavigation', {
+              detail: {
+                route: "login",
+                wanted: true
+              }
+            }),
+          );
+          document
+            .querySelectorAll(".loggedIn-loader")
+            .forEach(el => (el.style.display = "none"));
+        }
+      });
+  }
 });
 window.addEventListener("navigate", e => {
   if (e.detail.route == "login" && !window.requestLogin) {
     window.dispatchEvent(
       new CustomEvent('requestNavigation', {
         detail: {
-          route: "dashboard"
+          route: window.hubl.getRoute("dashboard", true)
         }
       }),
     );
   }
 });
-document.querySelector('#loginButton').addEventListener('click', () => {
-  document
-    .querySelectorAll(".loggedIn")
-    .forEach(el => (el.style.display = "none"));
-  document
-    .querySelectorAll(".loggedIn-loader")
-    .forEach(el => (el.style.display = "flex"));
-  setTimeout(() => {
-    document.querySelector('#something-goes-wrong').removeAttribute('hidden');
-  }, 5000);
-  document.querySelector('sib-auth').login();
-});
\ No newline at end of file
+const loginButton = document.querySelector('#loginButton');
+if (loginButton) {
+  loginButton.addEventListener('click', () => {
+    document
+      .querySelectorAll(".loggedIn")
+      .forEach(el => (el.style.display = "none"));
+    document
+      .querySelectorAll(".loggedIn-loader")
+      .forEach(el => (el.style.display = "flex"));
+    setTimeout(() => {
+      document.querySelector('#something-goes-wrong').removeAttribute('hidden');
+    }, 5000);
+    document.querySelector('sib-auth').login();
+  });
+}
\ No newline at end of file
diff --git a/src/scripts/navigate-event.js b/src/scripts/navigate-event.js
index 67765d43..d2fc2e7f 100644
--- a/src/scripts/navigate-event.js
+++ b/src/scripts/navigate-event.js
@@ -1,120 +1,136 @@
 // auxiliary function closes the user profile menu
 function closeUserControls() {
-    let userControls = Array.from(document.querySelectorAll(".user-controls"));
-    userControls.forEach(e => e.removeAttribute("open"));
-  }
-  
-  function closeLeftMenu() {
-    let leftMenu = document.querySelector("#main__menu");
-    if (leftMenu) leftMenu.removeAttribute("open");
-  }
-  
-  function closeRightMenu() {
-    let rightMenu = document.querySelectorAll(".jsRightMenu");
-    if (Array.from(rightMenu).filter(el => el.hasAttribute("open")).length > 0) {
-      Array.from(document.querySelectorAll(".views-container")).forEach(vC =>
-        vC.classList.toggle("sidebar-is-closed")
-      );
-      Array.from(document.querySelectorAll(".jsOffsiteToggle")).forEach(el => {
-        el.querySelector('.text-right').setAttribute('hidden', '');
-        el.querySelector('.text-left').removeAttribute('hidden');
-      });
-      Array.from(rightMenu).forEach(el => el.removeAttribute("open"));
-    }
-  }
-  
-  function openRightMenu() {
-    let rightMenu = document.querySelectorAll(".jsRightMenu");
-    Array.from(rightMenu).forEach(el => el.setAttribute("open", ""));
-    Array.from(document.querySelectorAll(".jsOffsiteToggle")).forEach(el => {
-      el.querySelector('.text-left').setAttribute('hidden', '');
-      el.querySelector('.text-right').removeAttribute('hidden');
-    });
+  let userControls = Array.from(document.querySelectorAll(".user-controls"));
+  userControls.forEach(e => e.removeAttribute("open"));
+}
+
+function closeLeftMenu() {
+  let leftMenu = document.querySelector("#main__menu");
+  if (leftMenu) leftMenu.removeAttribute("open");
+}
+
+function closeRightMenu() {
+  let rightMenu = document.querySelectorAll(".jsRightMenu");
+  if (Array.from(rightMenu).filter(el => el.hasAttribute("open")).length > 0) {
     Array.from(document.querySelectorAll(".views-container")).forEach(vC =>
       vC.classList.toggle("sidebar-is-closed")
     );
+    Array.from(document.querySelectorAll(".jsOffsiteToggle")).forEach(el => {
+      el.querySelector('.text-right').setAttribute('hidden', '');
+      el.querySelector('.text-left').removeAttribute('hidden');
+    });
+    Array.from(rightMenu).forEach(el => el.removeAttribute("open"));
   }
+}
 
-document.addEventListener("DOMContentLoaded", function() {
-  
-    //- View change event
-    window.addEventListener("navigate", e => {
-      if(e.detail.route.startsWith('admin-')) {
-        document.querySelector('.only-on-admin').removeAttribute('hidden');
-      } else {
-        document.querySelector('.only-on-admin').setAttribute('hidden','');
-      }
-      if(e.detail.route.startsWith("admin-communities")) {
-        document.querySelector('solid-route[name="admin-communities"]').setAttribute('active','');
-        document.querySelector('.jsRightMenu solid-link[next="admin-communities"]').setAttribute('active','');
-      } else {
-        document.querySelector('solid-route[name="admin-communities"]').removeAttribute('active');
-        document.querySelector('.jsRightMenu solid-link[next="admin-communities"]').removeAttribute('active');
-      }
-      if(e.detail.route.startsWith("admin-circles")) {
-        document.querySelector('solid-route[name="admin-circles"]').setAttribute('active','');
-        document.querySelector('.jsRightMenu solid-link[next="admin-circles"]').setAttribute('active','');
-      } else {
-        document.querySelector('solid-route[name="admin-circles"]').removeAttribute('active');
-        document.querySelector('.jsRightMenu solid-link[next="admin-circles"]').removeAttribute('active');
+function openRightMenu() {
+  let rightMenu = document.querySelectorAll(".jsRightMenu");
+  Array.from(rightMenu).forEach(el => el.setAttribute("open", ""));
+  Array.from(document.querySelectorAll(".jsOffsiteToggle")).forEach(el => {
+    el.querySelector('.text-left').setAttribute('hidden', '');
+    el.querySelector('.text-right').removeAttribute('hidden');
+  });
+  Array.from(document.querySelectorAll(".views-container")).forEach(vC =>
+    vC.classList.toggle("sidebar-is-closed")
+  );
+}
+
+document.addEventListener("DOMContentLoaded", function () {
+  const componentSet = new Set(window.hubl.components.map(c => c.type));
+
+  // Workaround - No "navigate" event after the login on `/login`
+  if (window.location.pathname == "/login") {
+    const sibAuth = document.querySelector("sib-auth");
+    if (sibAuth) {
+      sibAuth.getUser()
+        .then(user => {
+          if (user !== null) {
+            window.dispatchEvent(
+              new CustomEvent('requestNavigation', {
+                detail: {
+                  route: window.hubl.getRoute("dashboard", true)
+                }
+              }),
+            );
+          }
+        });
+    }
+  }
+
+  //- View change event
+  window.addEventListener("navigate", e => {
+    if (componentSet.has('admin')) {
+      const onlyAdmin = document.querySelector('.only-on-admin');
+      if (onlyAdmin) {
+        if (e.detail.route.startsWith('admin-')) {
+          onlyAdmin.removeAttribute('hidden');
+        } else {
+          onlyAdmin.setAttribute('hidden', '');
+        }
       }
-      if(e.detail.route.startsWith("admin-projects")) {
-        document.querySelector('solid-route[name="admin-projects"]').setAttribute('active','');
-        document.querySelector('.jsRightMenu solid-link[next="admin-projects"]').setAttribute('active','');
-      } else {
-        let adminProjects = document.querySelector('solid-route[name="admin-projects"]');
-        let rightMenu = document.querySelector('.jsRightMenu solid-link[next="admin-projects"]');
-        if( adminProjects ) adminProjects.removeAttribute('active');
-        if( rightMenu ) rightMenu.removeAttribute('active');
+      for (component of window.hubl.components) {
+        let adminTarget = document.querySelector(`solid-route[name="admin-${component.route}"]`);
+        let adminTargetTwo = document.querySelector(`.jsRightMenu solid-link[next="admin-${component.route}"]`);
+        if (e.detail.route.startsWith(`admin-${component.route}`)) {
+          if (adminTarget) adminTarget.setAttribute('active', '');
+          if (adminTargetTwo) adminTargetTwo.setAttribute('active', '');
+        } else {
+          if (adminTarget) adminTarget.removeAttribute('active');
+          if (adminTargetTwo) adminTargetTwo.removeAttribute('active');
+        }
       }
-      closeLeftMenu();
-      closeUserControls();
-      if(e.detail.route.startsWith('login')) {
-        document
-          .querySelector("sib-auth")
-          .getUser()
+    }
+    closeLeftMenu();
+    closeUserControls();
+    if (e.detail.route.startsWith('login')) {
+      const sibAuth = document.querySelector("sib-auth");
+      if (sibAuth) {
+        sibAuth.getUser()
           .then(user => {
             if (user !== null) {
               window.dispatchEvent(
                 new CustomEvent('requestNavigation', {
                   detail: {
-                    route: "dashboard"
+                    route: window.hubl.getRoute("dashboard", true)
                   }
                 }),
               );
             }
           });
       }
-    });
-    // Document -> close menu
-    document.addEventListener("click", event => {
-      if (!event.target.closest(".user-controls")) {
-        closeUserControls();
-      }
-      if (
-        !event.target.closest("#main__menu") &&
-        event.target.id != "toggleMainMenu"
-      ) {
-        closeLeftMenu();
-      }
-      if (
-        !event.target.closest(".jsOffsiteToggle")
-      ) {
-        closeRightMenu();
-      }
-    });
+    }
+  });
+  // Document -> close menu
+  document.addEventListener("click", event => {
+    if (!event.target.closest(".user-controls")) {
+      closeUserControls();
+    }
+    if (
+      !event.target.closest("#main__menu") &&
+      event.target.id != "toggleMainMenu"
+    ) {
+      closeLeftMenu();
+    }
+    if (
+      !event.target.closest(".jsOffsiteToggle")
+    ) {
+      closeRightMenu();
+    }
+  });
 
-    // listen for keypress
-    document.onkeydown = e => {
-      e = e || window.event;
-      if (e.key === "Escape" || e.key === "Esc") {
-        closeUserControls();
-        closeLeftMenu();
-        closeRightMenu();
-      }
-    };
+  // listen for keypress
+  document.onkeydown = e => {
+    e = e || window.event;
+    if (e.key === "Escape" || e.key === "Esc") {
+      closeUserControls();
+      closeLeftMenu();
+      closeRightMenu();
+    }
+  };
 
-    document.querySelector("#toggleMainMenu").addEventListener("click", () => {
+  const toggleMainMenu = document.querySelector("#toggleMainMenu")
+  if (toggleMainMenu) {
+    toggleMainMenu.addEventListener("click", () => {
       let leftMenu = document.querySelector("#main__menu");
       if (leftMenu.hasAttribute("open")) {
         closeLeftMenu();
@@ -122,24 +138,25 @@ document.addEventListener("DOMContentLoaded", function() {
         leftMenu.setAttribute("open", "");
       }
     });
+  }
 
-    const rightMenus = Array.from(document.querySelectorAll("nav.jsRightMenu"));
-    rightMenus.forEach(rightMenu => {
-      const btnRightMenu = rightMenu.querySelector("li.jsOffsiteToggle");
-      btnRightMenu.addEventListener("click", () => {
-        if (rightMenu.hasAttribute("open")) {
-          closeRightMenu();
-        } else {
-          openRightMenu();
-        }
-      });
+  const rightMenus = Array.from(document.querySelectorAll("nav.jsRightMenu"));
+  rightMenus.forEach(rightMenu => {
+    const btnRightMenu = rightMenu.querySelector("li.jsOffsiteToggle");
+    btnRightMenu.addEventListener("click", () => {
+      if (rightMenu.hasAttribute("open")) {
+        closeRightMenu();
+      } else {
+        openRightMenu();
+      }
     });
+  });
 
-    Array.from(document.querySelectorAll(".jsMobileSidebarOpenButton")).forEach(
-      el => {
-        el.addEventListener("click", () => {
-          openRightMenu();
-        });
-      }
-    );
-});
+  Array.from(document.querySelectorAll(".jsMobileSidebarOpenButton")).forEach(
+    el => {
+      el.addEventListener("click", () => {
+        openRightMenu();
+      });
+    }
+  );
+});
\ No newline at end of file
diff --git a/src/scripts/register-sw.js b/src/scripts/register-sw.js
index 5b375a82..2cd921ee 100644
--- a/src/scripts/register-sw.js
+++ b/src/scripts/register-sw.js
@@ -1,11 +1,11 @@
-if('serviceWorker' in navigator) {
+if ('serviceWorker' in navigator) {
   var refreshing;
   navigator.serviceWorker.addEventListener('controllerchange', () => {
-      if (refreshing) {
-          return;
-      }
-      refreshing = true;
-      window.location.reload();
+    if (refreshing) {
+      return;
+    }
+    refreshing = true;
+    window.location.reload();
   });
   navigator.serviceWorker.register('/sw.js');
 }
\ No newline at end of file
diff --git a/src/scripts/theme-checker.js b/src/scripts/theme-checker.js
index a8ec3a14..b4a691ad 100644
--- a/src/scripts/theme-checker.js
+++ b/src/scripts/theme-checker.js
@@ -1,6 +1,5 @@
 document.addEventListener("DOMContentLoaded", () => {
-
-    if( !document.querySelector('.input-color') ) return
+    if (!document.querySelector('.input-color')) return
     const params = new URLSearchParams(window.location.search);
     const currentPrimary = getComputedStyle(document.documentElement).getPropertyValue('--color-primary')
     const defaultPrimary = params.has('p') ? "#" + params.get('p') : currentPrimary ? currentPrimary.trim() : "#FF0055";
@@ -94,4 +93,4 @@ document.addEventListener("DOMContentLoaded", () => {
         params.set('cd', String(color.toHEXA()).substr(1));
         cCd.applyColor();
     });
-});
+});
\ No newline at end of file
diff --git a/src/scripts/timeout-goeswrong.js b/src/scripts/timeout-goeswrong.js
index 53acb0fe..8df7662f 100644
--- a/src/scripts/timeout-goeswrong.js
+++ b/src/scripts/timeout-goeswrong.js
@@ -1,5 +1,11 @@
 setTimeout(() => {
-  if(document.querySelector('.loggedIn-loader').style.display != 'none') {
-    document.querySelector('#something-goes-wrong').removeAttribute('hidden')
+  const loggedinLoader = document.querySelector('.loggedIn-loader');
+  if (loggedinLoader) {
+    if (loggedinLoader.style.display != 'none') {
+      const somethingGoesWrong = document.querySelector('#something-goes-wrong');
+      if (somethingGoesWrong) {
+        somethingGoesWrong.removeAttribute('hidden');
+      }
+    }
   }
 }, 10000);
\ No newline at end of file
diff --git a/src/scripts/user-creation-form.js b/src/scripts/user-creation-form.js
index fce7ddb0..32229add 100644
--- a/src/scripts/user-creation-form.js
+++ b/src/scripts/user-creation-form.js
@@ -1,7 +1,10 @@
 document.addEventListener('DOMContentLoaded', () => {
-  document.querySelector('#user-creation-form').addEventListener('save', event => {
-    if(event.originalTarget.id == 'user-creation-form') {
-      document.querySelector("sib-auth").login();
-    }
-  });
+  const userCreationForm = document.querySelector('#user-creation-form');
+  if (userCreationForm) {
+    userCreationForm.addEventListener('save', event => {
+      if (event.originalTarget.id == 'user-creation-form') {
+        document.querySelector("sib-auth").login();
+      }
+    });
+  }
 });
\ No newline at end of file
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 3f167caa..2dd160b9 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -38,7 +38,6 @@ solid-display>div {
 @import 'content';
 @import 'about';
 @import 'members';
-@import 'profile';
 @import 'job-offers';
 @import 'chat';
 @import 'forms';
@@ -67,17 +66,21 @@ main#content {
   }
 }
 
-hubl-create + hubl-create {
-  display: none; /* Duplicate widget generation? */
+hubl-menu-create+hubl-menu-create {
+  display: none;
+  /* Duplicate widget generation? */
 }
 
-hubl-create-contact + hubl-create-contact {
-  display: none; /* Duplicate widget generation? */
+hubl-create-contact+hubl-create-contact {
+  display: none;
+  /* Duplicate widget generation? */
 }
 
-hubl-create, hubl-create-contact {
+hubl-menu-create,
+hubl-create-contact {
   solid-link {
     text-decoration: underline;
+
     &:hover {
       text-decoration: none;
     }
@@ -85,14 +88,25 @@ hubl-create, hubl-create-contact {
 }
 
 .swal2-container {
-  z-index: 50000!important;
+  z-index: 50000 !important;
+}
+
+.global-loader {
+  position: fixed;
+  width: 100%;
+  height: 100%;
+  z-index: 999999;
+  top: 0;
+  left: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 
 /* Fix on Join button in admin (circles + projects) */
 /* Styles on buttons and .children-link don't work because this input is inside too many elements. */
 /* And no I can't add that stupid icon because it'a an input. */
 .join-button {
-
   input {
     padding: 9px 20px;
     border-radius: 16.5px;
diff --git a/src/styles/profile/_index.scss b/src/styles/profile/_index.scss
deleted file mode 100644
index f43b2c99..00000000
--- a/src/styles/profile/_index.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-#profile>div:first-of-type {
-  min-height: calc(100vh - 72px);
-
-  @media (max-width: 768px) {
-    min-height: calc(100vh - 50px);
-  }
-}
diff --git a/src/views/page-admin.pug b/src/views/page-admin.pug
index 1a3d0ac9..dc4f4c4f 100644
--- a/src/views/page-admin.pug
+++ b/src/views/page-admin.pug
@@ -1,24 +1,66 @@
 .with-sidebar.whitespace-normal.bg-color-white.only-on-admin(hidden)
   .scrollbar-content.views-container.sidebar-is-closed
-    if endpoints.circles || (endpoints.get && endpoints.get.circles)
-      #admin-circles(hidden, data-view="admin-circles", no-render)
-        include partials/admin/page-admin-circles.pug
-      #circle-left(hidden, data-view="circle-left", no-render)
-        include partials/circle/page-circle-left.pug
-      #admin-circles-create(hidden, data-view="admin-circles-create", no-render)
-        include partials/admin/page-admin-circles-create.pug
-    if endpoints.projects || (endpoints.get && endpoints.get.projects)
-      #admin-projects(hidden, data-view="admin-projects", no-render)
-        include partials/admin/page-admin-projects.pug
-      #admin-projects-create(hidden, data-view="admin-projects-create", no-render)
-        include partials/admin/page-admin-projects-create.pug
-      #project-left(hidden, data-view="project-left", no-render)
-        include partials/project/page-project-left.pug
-    if (endpoints.users || (endpoints.get && endpoints.get.users))
-      #admin-communities(hidden, data-view="admin-communities")
-        include partials/admin/page-admin-communities.pug
-      #admin-users-create(hidden, data-view="admin-users-create", no-render)
-        include partials/admin/page-admin-users-create.pug
+    for component of components
+      if component.type == "circles"
+        div(
+          id=`admin-${component.route}`
+          hidden
+          data-view=`admin-${component.route}`
+          no-render
+        )
+          include partials/admin/page-admin-circles.pug
+        div(
+          id=`${component.route}-left`
+          hidden
+          data-view=`${component.route}-left`
+          no-render
+        )
+          include partials/circle/page-circle-left.pug
+        div(
+          id=`admin-${component.route}-create`
+          hidden
+          data-view=`admin-${component.route}-create`
+          no-render
+        )
+          include partials/admin/page-admin-circles-create.pug
+      if component.type == "projects"
+        div(
+          id=`admin-${component.route}`
+          hidden
+          data-view=`admin-${component.route}`
+          no-render
+        )
+          include partials/admin/page-admin-projects.pug
+        div(
+          id=`${component.route}-left`
+          hidden
+          data-view=`${component.route}-left`
+          no-render
+        )
+          include partials/project/page-project-left.pug
+        div(
+          id=`admin-${component.route}-create`
+          hidden
+          data-view=`admin-${component.route}-create`
+          no-render
+        )
+          include partials/admin/page-admin-projects-create.pug
+      if component.type == "chat" && componentSet.has('communities')
+        div(
+          id=`admin-${component.route}`
+          hidden
+          data-view=`admin-${component.route}`
+          no-render
+        )
+          include partials/admin/page-admin-chat.pug
+        div(
+          id=`admin-${component.route}-create`
+          hidden
+          data-view=`admin-${component.route}-create`
+          no-render
+        )
+          include partials/admin/page-admin-chat-create.pug
+
   nav.jsRightMenu.text-disable-selection.sidebar.whitespace-normal(role='navigation')
     .segment.whitespace-normal.text-color-heading.text-bold
       ul
@@ -27,18 +69,19 @@
           span.segment.full.text-right(hidden)
             span.icon.icon-arrow-right.icon-xsmall.margin-right-xxsmall
             a(data-trans='admin.menuRight.fold')
-        if (endpoints.users || (endpoints.get && endpoints.get.users))
-          solid-link.segment.full(next='admin-communities')
-            li.segment.full.padding-medium
-              span.icon.ci-networking.icon-xlarge.margin-right-medium
-              a(data-trans='admin.menuRight.community')
-        if endpoints.circles || (endpoints.get && endpoints.get.circles)
-          solid-link.segment.full(next='admin-circles')
-            li.segment.full.padding-medium
-              span.icon.ci-bubble-add.icon-xlarge.margin-right-medium
-              a(data-trans='admin.menuRight.circles')
-        if endpoints.projects || (endpoints.get && endpoints.get.projects)
-          solid-link.segment.full(next='admin-projects')
-            li.segment.full.padding-medium
-              span.icon.ci-add.icon-xlarge.margin-right-medium
-              a(data-trans='admin.menuRight.projects')
+        for component of components
+          if component.type == "circles"
+            solid-link.segment.full(next=`admin-${component.route}`)
+              li.segment.full.padding-medium
+                span.icon.ci-bubble-add.icon-xlarge.margin-right-medium
+                a(data-trans='admin.menuRight.circles')
+          if component.type == "projects"
+            solid-link.segment.full(next=`admin-${component.route}`)
+              li.segment.full.padding-medium
+                span.icon.ci-add.icon-xlarge.margin-right-medium
+                a(data-trans='admin.menuRight.projects')
+          if component.type == "chat"
+            solid-link.segment.full(next=`admin-${component.route}`)
+              li.segment.full.padding-medium
+                span.icon.ci-networking.icon-xlarge.margin-right-medium
+                a(data-trans='admin.menuRight.community')
diff --git a/src/views/page-circle.pug b/src/views/page-circle.pug
index 3a9e7930..1fc3060d 100644
--- a/src/views/page-circle.pug
+++ b/src/views/page-circle.pug
@@ -1,44 +1,92 @@
 .scrollbar-content.views-container.sidebar-is-closed.bg-color-white
   solid-ac-checker(permission='acl:Read', bind-resources)
-    #circle-chat(hidden, data-view="circle-chat", no-render)
+    div(
+      id=`${component.route}-chat`
+      hidden
+      data-view=`${component.route}-chat`
+      no-render
+    )
       include partials/circle/page-circle-chat.pug
-    #circle-information(hidden, data-view="circle-information", no-render)
+    div(
+      id=`${component.route}-information`
+      hidden
+      data-view=`${component.route}-information`
+      no-render
+    )
       include partials/circle/page-circle-profile.pug
-    #circle-events(hidden, data-view="circle-events", no-render)
-      include partials/circle/page-circle-events.pug
-    #circle-resources(hidden, data-view="circle-resources", no-render)
-      include partials/circle/page-circle-resources.pug
-    #circle-polls(hidden, data-view="circle-polls", no-render)
-      include partials/circle/page-circle-polls.pug
+    //- Note:
+      Instead of using flat events/resources or polls components, you
+      may you to expend the way circle work to handle events & cie.
+      Like:
+        {
+          "type": "circles",
+          ...
+          "extensions": [
+            {
+              "type": "events",
+              "endpoints": {...},
+              ...
+            }
+          ]
+        }
+    -
+      let extensions = new Set();
+      if(component.extensions) {
+        extensions = new Set(component.extensions.map(c=>c.type));
+      }
+    if extensions.has('events')
+      div(
+        id=`${component.route}-events`
+        hidden
+        data-view=`${component.route}-events`
+        no-render
+      )
+        include partials/circle/page-circle-events.pug
+    if extensions.has('resources')
+      div(
+        id=`${component.route}-resources`
+        hidden
+        data-view=`${component.route}-resources`
+        no-render
+      )
+        include partials/circle/page-circle-resources.pug
+    if extensions.has('polls')
+      div(
+        id=`${component.route}-polls`
+        hidden
+        data-view=`${component.route}-polls`
+        no-render
+      )
+        include partials/circle/page-circle-polls.pug
 
 nav.jsRightMenu.text-disable-selection.sidebar.whitespace-normal(role='navigation')
-  solid-router.segment.whitespace-normal.text-color-heading.text-bold(default-route='circle-chat')
+  solid-router.segment.whitespace-normal.text-color-heading.text-bold(default-route=`${component.route}-chat`)
     ul
       li.segment.full.padding-small.text-normal.jsOffsiteToggle
         span.icon.icon-arrow-left.icon-xsmall.margin-left-xxsmall.text-left
         span.segment.full.text-right(hidden)
           span.icon.icon-arrow-right.icon-xsmall.margin-right-xxsmall
           a(data-trans='circle.menuRight.fold')
-      solid-route.segment.full(name='circle-chat')
+      solid-route.segment.full(name=`${component.route}-chat` use-id)
         li.segment.full.padding-medium
           span.icon.ci-chat.icon-xlarge.margin-right-medium
           a(data-trans='circle.menuRight.chat')
-      solid-route.segment.full(name='circle-information')
+      solid-route.segment.full(name=`${component.route}-information` use-id)
         li.segment.full.padding-medium
           span.icon.ci-information.icon-xlarge.margin-right-medium
           a(data-trans='circle.menuRight.information')
-      if (endpoints.resources || (endpoints.get && endpoints.get.resources)) && (endpoints.resourceskeywords || (endpoints.get && endpoints.get.resourceskeywords)) && (endpoints.resourcestypes || (endpoints.get && endpoints.get.resourcestypes))
-        solid-route.segment.full(name='circle-resources' use-id)
+      if extensions.has('resources')
+        solid-route.segment.full(name=`${component.route}-resources` use-id)
           li.segment.full.padding-medium
             span.icon.ci-networking.icon-xlarge.margin-right-medium
             a(data-trans='circle.menuRight.resources')
-      if (endpoints.events || (endpoints.get && endpoints.get.events)) && (endpoints.typeevents || (endpoints.get && endpoints.get.typeevents))
-        solid-route.segment.full(name='circle-events' use-id)
+      if extensions.has('events')
+        solid-route.segment.full(name=`${component.route}-events` use-id)
           li.segment.full.padding-medium
             span.icon.ci-networking.icon-xlarge.margin-right-medium
             a(data-trans='circle.menuRight.events')
-      if endpoints.polls || (endpoints.get && endpoints.get.polls)
-        solid-route.segment.full(name='circle-polls' use-id)
+      if extensions.has('polls')
+        solid-route.segment.full(name=`${component.route}-polls` use-id)
           li.segment.full.padding-medium
             span.icon.ci-networking.icon-xlarge.margin-right-medium
             a(data-trans='circle.menuRight.polls')    
diff --git a/src/views/page-dashboard.pug b/src/views/page-dashboard.pug
index 3ed82c43..e92c4ede 100644
--- a/src/views/page-dashboard.pug
+++ b/src/views/page-dashboard.pug
@@ -1,4 +1,4 @@
 div.padding-top-xlarge.padding-right-xsmall.padding-bottom-xlarge.padding-left-xsmall.sm-padding-top-medium.bg-color-grey.whitespace-normal
   solid-dashboard(
-    data-src=`${endpoints.dashboards || endpoints.get.dashboards}`
+    data-src=`${component.endpoints.get}`
   )
diff --git a/src/views/page-directory.pug b/src/views/page-directory.pug
index 83aa0fe8..88b6448d 100644
--- a/src/views/page-directory.pug
+++ b/src/views/page-directory.pug
@@ -1,6 +1,6 @@
 div.bg-color-grey.padding-top-xlarge.padding-right-small.padding-bottom-xlarge.padding-left-small.whitespace-normal
   solid-directory(
-    data-src=`${endpoints.users || endpoints.get.users}`
-    range-skills=`${endpoints.skills || endpoints.get.skills}`
+    data-src=`${component.endpoints.get}`
+    range-skills=`${component.endpoints.skills}`
     paginate-by="30"
   )
diff --git a/src/views/page-events.pug b/src/views/page-events.pug
index 00297353..70de9683 100644
--- a/src/views/page-events.pug
+++ b/src/views/page-events.pug
@@ -1,7 +1,7 @@
 div.whitespace-normal
-  solid-event(data-src=`${endpoints.events || endpoints.get.events}`
-    range-event-type=`${endpoints.typeevents || endpoints.get.typeevents}`
-    range-event-circle=`${endpoints.circles || endpoints.get.circles}`
-    upload-dir=`${endpoints.uploads || endpoints.get.uploads}`
+  solid-event(data-src=`${component.endpoints.events}`
+    range-event-type=`${component.endpoints.typeevents}`
+    range-event-circle=`${component.endpoints.circles}`
+    upload-dir=`${component.endpoints.uploads}`
     id-prefix='default'
   )
diff --git a/src/views/page-job-board.pug b/src/views/page-job-board.pug
new file mode 100644
index 00000000..faa428df
--- /dev/null
+++ b/src/views/page-job-board.pug
@@ -0,0 +1,5 @@
+solid-job-board(
+  data-src=`${component.endpoints.get}`,
+  post-data-src=`${component.endpoints.post}`,
+  range-skills=`${component.endpoints.skills}`
+)
diff --git a/src/views/page-job-offers.pug b/src/views/page-job-offers.pug
deleted file mode 100644
index 83420770..00000000
--- a/src/views/page-job-offers.pug
+++ /dev/null
@@ -1,5 +0,0 @@
-solid-job-board(
-  data-src=`${endpoints.joboffers || endpoints.get.joboffers}`,
-  post-data-src=`${endpoints.joboffers || endpoints.post.joboffers}`,
-  range-skills=`${endpoints.skills || endpoints.get.skills}`
-)
diff --git a/src/views/page-messages.pug b/src/views/page-messages.pug
index cd77d3dc..388cc186 100644
--- a/src/views/page-messages.pug
+++ b/src/views/page-messages.pug
@@ -18,14 +18,14 @@ div.segment.full.padding-top-small.padding-right-large.padding-bottom-small.padd
 
   solid-link.icon.icon-info.icon-secondary.hover(
     bind-resources
-    next="member-profile"
+    next=`${getRoute('profileDirectory', true)}-member-profile`
   )
 
 .chat-view.segment.full.whitespace-normal
   solid-xmpp-chat(
     data-authentication='login',
     data-auto-login='true',
-    data-websocket-url=`${xmppWebsocket || 'wss://jabber.happy-dev.fr/xmpp-websocket'}`,
+    data-websocket-url=`${component.endpoints.xmpp}`,
     data-i18n='en',
     bind-resources
   )
diff --git a/src/views/page-polls.pug b/src/views/page-polls.pug
index 3b5599ee..361750ff 100644
--- a/src/views/page-polls.pug
+++ b/src/views/page-polls.pug
@@ -1,7 +1,7 @@
 .views-container
   solid-poll(
-    data-src=`${endpoints.polls || (endpoints.get && endpoints.get.polls)}`
-    range-base-polls=`${endpoints.pollRangeBase || (endpoints.get && endpoints.get.pollRangeBase)}`
-    upload-dir=`${endpoints.uploads || (endpoints.get && endpoints.get.uploads)}`
+    data-src=`${component.endpoints.get}`
+    range-base-polls=`${component.endpoints.pollRangeBase}`
+    upload-dir=`${component.endpoints.uploads}`
     id-prefix='default'
   )
\ No newline at end of file
diff --git a/src/views/page-profile.pug b/src/views/page-profile.pug
index 32d9bb69..9294ee2e 100644
--- a/src/views/page-profile.pug
+++ b/src/views/page-profile.pug
@@ -1,5 +1,5 @@
 solid-profile(
   bind-user
-  upload-src=`${endpoints.uploads || endpoints.post.uploads}`
-  range-skills=`${endpoints.skills || endpoints.get.skills}`
+  upload-src=`${getComponent('profileDirectory', true).endpoints.uploads}`
+  range-skills=`${getComponent('profileDirectory', true).endpoints.skills}`
 )
diff --git a/src/views/page-project.pug b/src/views/page-project.pug
index 281ad6c3..b79b4e9b 100644
--- a/src/views/page-project.pug
+++ b/src/views/page-project.pug
@@ -1,26 +1,41 @@
 .scrollbar-content.views-container.sidebar-is-closed.bg-color-white
   solid-ac-checker(permission='acl:Read', bind-resources)
-    #project-chat(hidden, data-view="project-chat", no-render)
+    div(
+      id=`${component.route}-chat`
+      hidden
+      data-view=`${component.route}-chat`
+      no-render
+    )
       include partials/project/page-project-chat.pug
-    #project-information(hidden, data-view="project-information", no-render)
+    div(
+      id=`${component.route}-information`
+      hidden
+      data-view=`${component.route}-information`
+      no-render
+    )
       include partials/project/page-project-profile.pug
-    #project-picture(hidden, data-view="project-picture", no-render)
+    div(
+      id=`${component.route}-picture`
+      hidden
+      data-view=`${component.route}-picture`
+      no-render
+    )
       include partials/project/page-project-picture.pug
 
 nav.jsRightMenu.text-disable-selection.sidebar.whitespace-normal(role='navigation')
-  solid-router.segment.whitespace-normal.text-color-heading.text-bold(default-route='project-chat')
+  solid-router.segment.whitespace-normal.text-color-heading.text-bold(default-route=`${component.route}-chat`)
     ul
       li.segment.full.padding-small.text-normal.jsOffsiteToggle
         span.icon.icon-arrow-left.icon-xsmall.margin-left-xxsmall.text-left
         span.segment.full.text-right(hidden)
           span.icon.icon-arrow-right.icon-xsmall.margin-right-xxsmall
           a(data-trans='project.menuRight.fold')
-      solid-route.segment.full(name='project-chat')
+      solid-route.segment.full(name=`${component.route}-chat` use-id)
         li.segment.full.padding-medium
           span.icon.ci-chat.icon-xlarge.margin-right-medium
           a(data-trans='project.menuRight.chat')
-      solid-route.segment.full(name='project-information')
+      solid-route.segment.full(name=`${component.route}-information` use-id)
         li.segment.full.padding-medium
           span.icon.ci-information.icon-xlarge.margin-right-medium
           a(data-trans='project.menuRight.information')
-      solid-route(name='project-picture' use-id)
+      solid-route(name=`${component.route}-picture` use-id)
diff --git a/src/views/page-registering.pug b/src/views/page-registering.pug
new file mode 100644
index 00000000..5f6be36c
--- /dev/null
+++ b/src/views/page-registering.pug
@@ -0,0 +1,107 @@
+#login(data-view="login", hidden).segment.full.bg-color-secondary.text-center.index-community.loggedIn
+  .segment.half.sm-full.bg-color-white.text-center
+    .segment.half.sm-full
+      div.community-logo
+        img(src=`${client.logo || '/images/logo.webp'}` style='max-width:100%;max-height:100%;')
+      p.text-xlarge.text-semibold.margin-top-xxlarge.line-xlarge(data-trans="communities.index.youKnow")
+      button.segment.full.sm-three-quarter.button.text-xsmall.text-bold.text-uppercase.color-secondary.bordered.padding-bottom.xlarge.padding-top.xlarge.community-button#loginButton(
+        data-trans="communities.index.login"
+      )
+      p.text-xlarge.text-semibold.margin-top-xxlarge.line-xlarge(data-trans="communities.index.newUser")
+      solid-widget(name='hubl-index-community-logo')
+        template ${value != "" ? `<div class="community-button-flexed"><img src="${value}" style="max-width:100%;max-height:80px" class="padding-xsmall" /></div>` : ""}
+      solid-widget(name='hubl-index-community-text')
+        template
+          .community-button-flexed-large.whitespace-normal
+            span(data-trans="communities.index.createAccount")
+            span &nbsp;
+            span ${value}
+      solid-widget(name='hubl-index-select-community')
+        template
+          solid-link.segment.full.sm-three-quarter.button.text-xsmall.text-bold.text-uppercase.color-secondary.bordered.padding-bottom.xlarge.padding-top.xlarge.margin-top-xsmall.community-button.community-button-flex-container(
+            next='join-community'
+            data-src='${src}'
+          )
+            solid-display(
+              data-src='${src}'
+              fields='logo, name'
+              widget-logo='hubl-index-community-logo'
+              widget-name='hubl-index-community-text'
+            )
+      if getComponent('registering').endpoints.get
+        div.loader#hubl-index-community-selector-loader
+          div
+          div
+          div
+          div
+        solid-display.community-flex-container(
+          data-src=`${getComponent('registering').endpoints.get}`
+          fields='action'
+          action-action='action'
+          widget-action='hubl-index-select-community'
+          loader-id='hubl-index-community-selector-loader'
+          order-asc='name'
+          empty-widget='hubl-auto-login'
+          id='hubl-index-community-selector'
+        )
+
+#join-community(data-view="join-community", hidden, no-render).segment.full.bg-color-secondary.text-center.index-community.loggedIn
+  .segment.half.sm-full.bg-color-white.text-center
+    .segment.half.sm-full
+      solid-widget(name="hubl-index-community-join-logo")
+        template
+          img(src="${value}" style="max-width:100%;max-height:100%;")
+      solid-display(
+        bind-resources
+        fields="logo"
+        widget-logo="hubl-index-community-join-logo"
+        class-logo='community-logo'
+        default-logo=`${client.logo || '/images/logo.webp'}`
+      )
+      solid-widget(name='hubl-input-type-password')
+        template
+          label ${label}
+          input(
+            type="password"
+            name="user.password"
+            required
+            data-holder
+          )
+      solid-widget(name='hubl-input-type-email')
+        template
+          label ${label}
+          input(
+            type="email"
+            name="user.email"
+            required
+            data-holder
+          )
+      solid-form.segment.full.padding-top-xlarge.padding-very-xxlarge.sm-padding-xsmall.sm-padding-top-medium.whitespace-normal.form(
+        bind-resources
+        nested-field='members'
+        fields='user.first_name, user.last_name, user.email, user.username, user.password'
+        label-user.first_name='Prénom*'
+        label-user.last_name='Nom*'
+        label-user.email='E-mail*'
+        label-user.password='Mot de passe*'
+        data-trans='label-user.password=communities.index.password;label-user.email=communities.index.email;label-user.last_name=communities.index.last_name;label-user.first_name=communities.index.first_name;submit-button=communities.index.formCreateAccount'
+        widget-user.first_name='solid-form-text-label'
+        widget-user.last_name='solid-form-text-label'
+        widget-user.email='hubl-input-type-email'
+        widget-user.password='hubl-input-type-password'
+        widget-user.username='solid-form-hidden'
+        class-user.first_name='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
+        class-user.last_name='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
+        class-user.email='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
+        class-user.password='segment margin-bottom-medium full padding-left-small sm-padding-none text-large text-left'
+        required-user.first_name
+        required-user.last_name
+        required-user.email
+        required-user.password
+        pattern-user.first_name='.+'
+        pattern-user.last_name='.+'
+        value-user.username='generate-an-username'
+        submit-button=''
+        id='user-creation-form'
+        next=getRoute('dashboard', true)
+      )
\ No newline at end of file
diff --git a/src/views/page-resources.pug b/src/views/page-resources.pug
index 7ad5e1a4..7e413c69 100644
--- a/src/views/page-resources.pug
+++ b/src/views/page-resources.pug
@@ -1,8 +1,8 @@
 .views-container
-  solid-resource(data-src=`${endpoints.resources || (endpoints.get && endpoints.get.resources)}`
-      range-resource-type=`${endpoints.resourcestypes || (endpoints.get && endpoints.get.resourcestypes)}`
-      range-resource-keyword=`${endpoints.resourceskeywords || (endpoints.get && endpoints.get.resourceskeywords)}`
-      range-resource-circle=`${endpoints.circles || (endpoints.get && endpoints.get.circles)}`
-      upload-dir=`${endpoints.uploads || (endpoints.get && endpoints.get.uploads)}`
+  solid-resource(data-src=`${component.endpoints.resources}`
+      range-resource-type=`${component.endpoints.resourcestypes}`
+      range-resource-keyword=`${component.endpoints.resourceskeywords}`
+      range-resource-circle=`${component.endpoints.circles}`
+      upload-dir=`${component.endpoints.uploads}`
       id-prefix='default'
   )
\ No newline at end of file
diff --git a/src/views/partials/admin/page-admin-users-create.pug b/src/views/partials/admin/page-admin-chat-create.pug
similarity index 75%
rename from src/views/partials/admin/page-admin-users-create.pug
rename to src/views/partials/admin/page-admin-chat-create.pug
index ecc00e55..1042fde7 100644
--- a/src/views/partials/admin/page-admin-users-create.pug
+++ b/src/views/partials/admin/page-admin-chat-create.pug
@@ -2,8 +2,7 @@ div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-p
   div.segment.half.sm-full
     h2.margin-none.text-color-heading.text-uppercase.text-xlarge.text-letter-spacing-large(data-trans='communities.title')
   div.segment.half.sm-hidden.text-right
-    solid-link(class="backlink", bind-resources, next='admin-communities' data-trans='circle.create.backlink')
-
+    solid-link(class="backlink", next=`admin-${getRoute('chat', true)}` data-trans='circle.create.backlink')
 
 div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespace-normal
   div#loader-users-title.loader.loader
@@ -18,17 +17,6 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
     div
     div
 
-  solid-widget(name='hubl-username-field')
-    template
-      label ${label}
-      input(type="text" title='' pattern="[a-zA-Z0-9]+" label="${label}" data-trans='title=user.create.labelUsernameTitle' name="username" required value="\${value}" data-holder)
-
-  solid-widget(name='hubl-email-field')
-    template
-      div.segment.margin-bottom-medium.half.sm-full.padding-left-small.sm-padding-none.text-small.text-semibold.text-uppercase.text-color-heading
-        label ${label}
-        input(type="email" label='${label}' name="email" required value="\${value}" data-holder)
-
   div.segment.margin-bottom-medium
     div.segment
       solid-display.text-color-heading.text-semibold.text-xlarge.text-letter-spacing-large(
@@ -38,7 +26,7 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
         data-trans='value-text=user.create.title'
         loader-id='loader-users-title'
       )
-  
+
   solid-form.form#selected-community(
     bind-resources
     nested-field='members'
@@ -65,7 +53,7 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
     widget-user.username='hubl-username-field'
     widget-user.email='hubl-email-field'
 
-    next='admin-communities'
+    next=`admin-${getRoute('chat', true)}`
 
     submit-button=''
     data-trans='label-user.first_name=user.create.labelFirstname;label-user.last_name=user.create.labelLastname;label-user.username=user.create.labelUsername;label-user.email=user.create.labelEmail;submit-button=user.create.buttonSubmit'
diff --git a/src/views/partials/admin/page-admin-communities.pug b/src/views/partials/admin/page-admin-chat.pug
similarity index 68%
rename from src/views/partials/admin/page-admin-communities.pug
rename to src/views/partials/admin/page-admin-chat.pug
index 85532c44..9aaf87a7 100644
--- a/src/views/partials/admin/page-admin-communities.pug
+++ b/src/views/partials/admin/page-admin-chat.pug
@@ -1,15 +1,3 @@
-solid-widget(name='hubl-action-community')
-  template
-    solid-ac-checker(data-src="${value}", nested-field="members", permission='acl:Append')
-      solid-link(
-        class='button text-small text-bold text-uppercase reversed color-secondary bordered icon icon-plus'
-        data-src="${value}"
-        next="admin-users-create"
-        data-trans='communities.linkInvite'
-      )
-    solid-ac-checker(data-src="${value}", nested-field="members", no-permission='acl:Append')
-      div.button.button-disabled(data-trans='communities.noPermission')
-
 div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-padding-bottom-small.sm-padding-left-xsmall.border-bottom.border-color-grey.whitespace-normal
   h2.margin-none.text-color-heading.text-uppercase.text-xlarge.text-letter-spacing-large(data-trans='communities.title')
 
@@ -18,17 +6,6 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
   div.segment.full.margin-bottom-xlarge
     h3.text-color-heading.text-semibold.text-letter-spacing-large(data-trans='communities.subTitle')
 
-  solid-widget(name='hubl-admin-community-counter')
-    template
-      div(style='float:right')
-        solid-display(
-          fields=''
-          data-src="${src}"
-          nested-field="community.members"
-          counter-template="\\\${counter}"
-        )
-        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
-
   solid-form-search.form.search-form(
     id="admin-community-filter"
     fields='cell1'
@@ -44,7 +21,7 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
       div.table-header.bg-color-third.text-color-heading
         div.segment.table-cell.table-cell.half(data-trans='communities.tableHeader1') 
         div.segment.table-cell.table-cell.half(data-trans='communities.tableHeader2')
-    
+
       solid-display(
         class='table-body'
         filtered-by='admin-community-filter'
diff --git a/src/views/partials/admin/page-admin-circles-create.pug b/src/views/partials/admin/page-admin-circles-create.pug
index 0b4864dc..8e55e0a1 100644
--- a/src/views/partials/admin/page-admin-circles-create.pug
+++ b/src/views/partials/admin/page-admin-circles-create.pug
@@ -2,23 +2,23 @@ div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-p
   div.segment.half.sm-full  
     h2.margin-none.text-color-heading.text-uppercase.text-xlarge.text-letter-spacing-large(data-trans='circle.create.title')
   div.segment.half.sm-hidden.text-right
-    solid-link(class="backlink", bind-resources, next='admin-circles' data-trans='circle.create.backlink')
+    solid-link(class="backlink", next=`admin-${getRoute('circles', true)}` data-trans='circle.create.backlink')
 
 div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespace-normal
-  div#loader-circles-create.loader.loader-top
+  div.loader.loader-top(id=`loader-admin-${getComponent('circles').uniq}`)
     div
     div
     div
     div
 
   solid-form.form(
-    data-src=`${endpoints.circles || endpoints.post.circles}`
+    data-src=`${getComponent('circles').endpoints.post}`
 
     fields='status, linebreak, name, subtitle, description, help'
     required-status
     required-name
     required-subtitle
-    loader-id='loader-circles-create'
+    loader-id=`loader-admin-${getComponent('circles').uniq}`
 
     class-status='segment margin-bottom-medium half sm-full padding-right-small sm-padding-none text-small text-semibold text-uppercase text-color-heading whitespace-normal'
     class-linebreak='segment half sm-hidden'
@@ -36,13 +36,13 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
 
     widget-status='hubl-status'
     widget-linebreak='solid-form-hidden'
-    
+
     widget-description='solid-form-richtext-label'
     widget-help='solid-form-hidden-label'
 
-    next='circle'
+    next=getRoute('circles', true)
 
     submit-button=''
-    
+
     data-trans='label-status=circle.create.labelStatus;label-name=circle.create.labelName;label-description=circle.create.labelDescription;submit-button=circle.create.buttonSubmit;label-subtitle=circle.create.labelSubtitle;label-help=circle.create.descriptionHelp'
   )
diff --git a/src/views/partials/admin/page-admin-circles.pug b/src/views/partials/admin/page-admin-circles.pug
index 4ad7571c..743a4671 100644
--- a/src/views/partials/admin/page-admin-circles.pug
+++ b/src/views/partials/admin/page-admin-circles.pug
@@ -1,22 +1,3 @@
-solid-widget(name='hubl-circle-owner')
-  template
-    solid-display.segment.block.margin-top-xxsmall.margin-bottom-xxsmall.labelled-avatar.two-lines(
-      data-src='${await value}'
-      fields='segment1(account.picture), segment2(line1(name), line2(at, username))'
-
-      class-segment1='segment'
-      class-account.picture='avatar'
-
-      class-segment2='segment three-quarter margin-left-xsmall'
-      class-line1='segment block'
-      class-name='text-small text-semibold text-color-heading text-sub'
-      class-line2='segment block text-xsmall'
-
-      widget-account.picture='hubl-user-avatar'
-
-      value-at='@'
-    )
-
 div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-padding-bottom-small.sm-padding-left-xsmall.border-bottom.border-color-grey.whitespace-normal
   h2.margin-none.text-color-heading.text-uppercase.text-xlarge.text-letter-spacing-large(data-trans='circle.list.title')
 
@@ -32,57 +13,13 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-normal.whitespac
     div.segment.half.sm-full
       h3.text-color-heading.text-semibold.text-letter-spacing-large(data-trans='circle.list.subTitle')
     div.segment.half.sm-full.text-right
-      solid-ac-checker(data-src=`${endpoints.circles || (endpoints.post && endpoints.post.circles)}`, permission='acl:Append')
+      solid-ac-checker(data-src=`${getComponent('circles').endpoints.post}`, permission='acl:Append')
         solid-link(
           class='segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-plus'
-          next='admin-circles-create'
+          next=`admin-${getRoute('circles', true)}-create`
           data-trans='circle.list.buttonCreate'
         )
 
-  solid-widget(name='hubl-admin-circle-counter')
-    template
-      div(style='float:right')
-        solid-display(
-          fields=''
-          data-src="${src}"
-          nested-field="members"
-          counter-template="\\\${counter}"
-        )
-        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
-
-  solid-widget(name='hubl-admin-circle-counter-alternate')
-    template
-      div(style='float:right')
-        solid-display(
-          fields=''
-          data-src="${src}"
-          nested-field="circle.members"
-          counter-template="\\\${counter}"
-        )
-        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
-
-  solid-widget(name='admin-circle-link')
-    template
-      solid-link(
-        data-src='${src}'
-        next='circle-information'
-      )
-        solid-display(
-          data-src='${src}'
-          fields='name'
-        )
-
-  solid-widget(name='admin-circle-link-alternate')
-    template
-      solid-display(
-        data-src='${src}'
-        nested-field='circle'
-        fields='name'
-        class-name='segment block margin-bottom-xxsmall text-xlarge text-color-heading text-semibold text-letter-spacing-large text-underline text-ellipsis admin-name-ellipsis'
-        action-name='name'
-        widget-name='admin-circle-link'
-      )
-
   solid-form-search.form.search-form(
     id="admin-circle-filter"
     fields='name'
@@ -101,16 +38,15 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-normal.whitespac
         div.segment.table-cell.third(data-trans='circle.list.tableHeader2')
         div.segment.table-cell.third(data-trans='circle.list.tableHeader3')
 
-      solid-widget(name="leave-circle-reactivity")
+      solid-widget(name=`leave-circle-reactivity-${component.uniq}`)
         template
-          hubl-reactivity(data-src=`${endpoints.get.circles}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.get.circles}joinable/` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.circles}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.circles}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.get}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.get}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.post}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.post}joinable/` target-src='${value}')
           hubl-reactivity(bind-user nested-field="circles" target-src='${value}')
 
-
-      solid-widget(name='hubl-admin-circle-leave-button')
+      solid-widget(name=`hubl-admin-circle-leave-button-${component.uniq}`)
         template
           solid-delete(
             class='segment text-xsmall children-link-button children-link-text-bold children-link-text-uppercase children-link-color-secondary bordered'
@@ -118,15 +54,15 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-normal.whitespac
             data-label=''
             data-trans='data-label=circle.list.buttonQuit'
           )
-          hubl-reactivity(data-src=`${endpoints.get.circles}` target-src='${src}')
-          hubl-reactivity(data-src=`${endpoints.get.circles}joinable/` target-src='${src}')
-          hubl-reactivity(data-src=`${endpoints.post.circles}` target-src='${src}')
-          hubl-reactivity(data-src=`${endpoints.post.circles}joinable/` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.get}` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.get}joinable/` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.post}` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.post}joinable/` target-src='${src}')
           hubl-reactivity(bind-user nested-field="circles" target-src='${src}')
           solid-display(
             data-src="${src}"
             fields="circle"
-            widget-circle='leave-circle-reactivity'
+            widget-circle=`leave-circle-reactivity-${component.uniq}`
             hidden
           )
 
@@ -143,11 +79,11 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-normal.whitespac
         class-cell3='segment table-cell third text-center'
 
         action-circle.name='circle.name'
-        widget-circle.name='admin-circle-link-alternate'
+        widget-circle.name='hubl-admin-circle-link-alternate'
         class-circle.subtitle='segment full text-ellipsis'
 
         action-leaveButton="joinButton"
-        widget-leaveButton="hubl-admin-circle-leave-button"
+        widget-leaveButton=`hubl-admin-circle-leave-button-${component.uniq}`
         widget-circle.owner='hubl-circle-owner'
         action-counter="counter"
         widget-counter="hubl-admin-circle-counter-alternate"
@@ -155,7 +91,7 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-normal.whitespac
         order-by="circle.name"
       )
 
-      solid-widget(name='hubl-admin-circle-join-button')
+      solid-widget(name=`hubl-admin-circle-join-button-${component.uniq}`)
         template
           solid-form(
             class='join-button text-xsmall'
@@ -168,17 +104,17 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-normal.whitespac
             submit-button=''
             data-trans='submit-button=circle.list.buttonJoin'
           )
-          hubl-reactivity(data-src=`${endpoints.get.circles}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.get.circles}joinable/` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.circles}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.circles}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.get}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.get}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.post}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('circles').endpoints.post}joinable/` target-src='${value}')
           hubl-reactivity(bind-user nested-field="circles" target-src='${value}')
 
       solid-display(
         class='table-body'
         filtered-by="admin-circle-filter"
 
-        data-src=`${endpoints.circles || endpoints.get.circles}joinable/`
+        data-src=`${getComponent('circles').endpoints.get}joinable/`
         fields='cell1(name, counter, subtitle), cell2(owner), cell3(members)'
         loader-id='loader-admin-circles'
 
@@ -188,11 +124,11 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-normal.whitespac
 
         class-name='segment block margin-bottom-xxsmall text-xlarge text-color-heading text-semibold text-letter-spacing-large text-underline text-ellipsis admin-name-ellipsis'
         action-name='name'
-        widget-name='admin-circle-link'
+        widget-name='hubl-admin-circle-link'
         class-subtitle='segment full text-ellipsis'
 
         widget-owner='hubl-circle-owner'
-        widget-members="hubl-admin-circle-join-button"
+        widget-members=`hubl-admin-circle-join-button-${component.uniq}`
         action-counter="counter"
         widget-counter="hubl-admin-circle-counter"
 
diff --git a/src/views/partials/admin/page-admin-projects-create.pug b/src/views/partials/admin/page-admin-projects-create.pug
index 0037d9ba..95d1646b 100644
--- a/src/views/partials/admin/page-admin-projects-create.pug
+++ b/src/views/partials/admin/page-admin-projects-create.pug
@@ -2,26 +2,26 @@ div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-p
   div.segment.half.sm-full
     h2.margin-none.text-color-heading.text-uppercase.text-xlarge.text-letter-spacing-large(data-trans='project.create.title')
   div.segment.half.sm-hidden.text-right
-    solid-link(class="backlink right", next='admin-projects' data-trans='project.create.backlink')
+    solid-link(class="backlink", next=`admin-${getRoute('projects', true)}` data-trans='project.create.backlink')
 
 div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespace-normal
-  div#loader-projects-create.loader.loader-top
+  div.loader.loader-top(id=`loader-admin-${getComponent('circles').uniq}`)
     div
     div
     div
     div
 
   solid-form.form(
-    data-src=`${endpoints.projects || endpoints.post.projects}`
+    data-src=`${getComponent('projects').endpoints.post}`
 
     fields='status, customer.name, name, description, help, captain, linebreak'
-    range-captain=`${endpoints.users || endpoints.get.users}`
+    range-captain=`${getComponent('projects').endpoints.captains}`
     
     required-status
     required-customer.name
     required-name
     required-captain
-    loader-id='loader-projects-create'
+    loader-id=`loader-admin-${getComponent('circles').uniq}`
 
     label-status=''
     label-customer.name=''
@@ -45,7 +45,7 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
     widget-linebreak='solid-form-hidden'
 
     submit-button=''
-    next='project'
+    next=getRoute('projects', true)
 
     data-trans='label-status=project.create.labelStatus;label-customer.name=project.create.labelCustomer;label-name=project.create.labelName;label-description=project.create.labelDescription;label-captain=project.create.labelCaptain;label-help=project.create.descriptionHelp;submit-button=project.create.buttonSubmit'
   )
diff --git a/src/views/partials/admin/page-admin-projects.pug b/src/views/partials/admin/page-admin-projects.pug
index c3b73e75..c900c3e9 100644
--- a/src/views/partials/admin/page-admin-projects.pug
+++ b/src/views/partials/admin/page-admin-projects.pug
@@ -7,57 +7,13 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
     div.segment.half.sm-full
       h3.text-color-heading.text-semibold.text-letter-spacing-large(data-trans='project.list.subTitle')
     div.segment.half.sm-full.text-right
-      solid-ac-checker(data-src=`${endpoints.projects || (endpoints.post && endpoints.post.projects)}`, permission='acl:Append')
+      solid-ac-checker(data-src=`${getComponent('projects').endpoints.post}`, permission='acl:Append')
         solid-link(
           class='segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-plus'
           next='admin-projects-create'
           data-trans='project.list.buttonCreate'
         )
 
-  solid-widget(name='hubl-admin-project-counter')
-    template
-      div(style='float:right')
-        solid-display(
-          fields=''
-          data-src="${src}"
-          nested-field="members"
-          counter-template="\\\${counter}"
-        )
-        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
-
-  solid-widget(name='hubl-admin-project-counter-alternate')
-    template
-      div(style='float:right')
-        solid-display(
-          fields=''
-          data-src="${src}"
-          nested-field="project.members"
-          counter-template="\\\${counter}"
-        )
-        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
-
-  solid-widget(name='admin-project-link')
-    template
-      solid-link(
-        data-src='${src}'
-        next='project-information'
-      )
-        solid-display(
-          data-src='${src}'
-          fields='customer.name'
-        )
-
-  solid-widget(name='admin-project-link-alternate')
-    template
-      solid-display(
-        data-src='${src}'
-        nested-field='project'
-        fields='name'
-        class-name='segment block margin-bottom-xxsmall text-xlarge text-color-heading text-semibold text-letter-spacing-large text-underline text-ellipsis admin-name-ellipsis'
-        action-name='name'
-        widget-name='admin-project-link'
-      )
-
   solid-form-search.form.search-form(
     id="admin-project-filter"
     fields='cell1'
@@ -77,15 +33,15 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
         div.segment.table-cell.quarter(data-trans='project.list.tableHeader3')
         div.segment.table-cell.quarter(data-trans='project.list.tableHeader4')
 
-      solid-widget(name="leave-project-reactivity")
+      solid-widget(name=`leave-project-reactivity-${component.uniq}`)
         template
-          hubl-reactivity(data-src=`${endpoints.get.projects}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.get.projects}joinable/` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.projects}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.projects}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.get}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.get}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.post}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.post}joinable/` target-src='${value}')
           hubl-reactivity(bind-user nested-field="projects" target-src='${value}')
 
-      solid-widget(name="hubl-admin-project-leave-button")
+      solid-widget(name=`hubl-admin-project-leave-button-${component.uniq}`)
         template
           solid-delete(
             class='segment text-xsmall children-link-button children-link-text-bold children-link-text-uppercase children-link-color-secondary bordered'
@@ -93,37 +49,18 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
             data-label=''
             data-trans='data-label=project.list.buttonQuit'
           )
-          hubl-reactivity(data-src=`${endpoints.get.projects}` target-src='${src}')
-          hubl-reactivity(data-src=`${endpoints.get.projects}joinable/` target-src='${src}')
-          hubl-reactivity(data-src=`${endpoints.post.projects}` target-src='${src}')
-          hubl-reactivity(data-src=`${endpoints.post.projects}joinable/` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.get}` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.get}joinable/` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.post}` target-src='${src}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.post}joinable/` target-src='${src}')
           hubl-reactivity(bind-user nested-field="projects" target-src='${src}')
           solid-display(
             data-src="${src}"
             fields="project"
-            widget-project='leave-project-reactivity'
+            widget-project=`leave-project-reactivity-${component.uniq}`
             hidden
           )
 
-      solid-widget(name='hubl-project-captain')
-        template
-          solid-display.segment.margin-top-xxsmall.margin-bottom-xxsmall.labelled-avatar.two-lines.block(
-            data-src='${await value}'
-            fields='segment1(account.picture), segment2(line1(name), line2(at, username))'
-
-            class-segment1='segment'
-            class-account.picture='avatar'
-
-            class-segment2='segment three-quarter margin-left-xsmall'
-            class-line1='segment block'
-            class-name='text-small text-semibold text-color-heading text-sub'
-            class-line2='segment block text-xsmall'
-
-            widget-account.picture='hubl-user-avatar'
-
-            value-at='@'
-          )
-
       solid-form-search(
         id="hubl_project_is_admin"
         fields="is_admin"
@@ -132,15 +69,6 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
         hidden
       )
 
-      solid-widget(name='hubl-project-admins')
-        template
-          solid-display(
-            data-src='${value}'
-            fields='user'
-            filtered-by='hubl_project_is_admin'
-            widget-user='hubl-project-captain'
-          )
-
       solid-display(
         class='table-body'
         filtered-by="admin-project-filter"
@@ -156,11 +84,11 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
         class-cell4='segment table-cell quarter text-center'
 
         action-project.customer.name='project.customer.name'
-        widget-project.customer.name='admin-project-link-alternate'
+        widget-project.customer.name='hubl-admin-project-link-alternate'
         class-project.name='segment full'
 
         action-leaveButton="joinButton"
-        widget-leaveButton="hubl-admin-project-leave-button"
+        widget-leaveButton=`hubl-admin-project-leave-button-${component.uniq}`
 
         widget-project.captain='hubl-project-captain'
         widget-project.members='hubl-project-admins'
@@ -170,7 +98,7 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
         order-by="project.name"
       )
 
-      solid-widget(name='hubl-admin-project-join-button')
+      solid-widget(name=`hubl-admin-project-join-button-${component.uniq}`)
         template
           solid-form(
             class='button text-xsmall text-bold text-uppercase reversed color-secondary bordered icon icon-arrow-right-circle'
@@ -184,17 +112,17 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
             submit-button=''
             data-trans='submit-button=project.list.buttonJoin'
           )
-          hubl-reactivity(data-src=`${endpoints.get.projects}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.get.projects}joinable/` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.projects}` target-src='${value}')
-          hubl-reactivity(data-src=`${endpoints.post.projects}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.get}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.get}joinable/` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.post}` target-src='${value}')
+          hubl-reactivity(data-src=`${getComponent('projects').endpoints.post}joinable/` target-src='${value}')
           hubl-reactivity(bind-user nested-field="projects" target-src='${value}')
 
       solid-display(
         class='table-body'
         filtered-by="admin-project-filter"
 
-        data-src=`${endpoints.projects || endpoints.get.projects}joinable/`
+        data-src=`${getComponent('projects').endpoints.get}joinable/`
         fields='cell1(customer.name, counter, name), cell2(members), cell3(captain), cell4(joinButton)'
         loader-id='loader-admin-projects'
 
@@ -204,11 +132,11 @@ div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-medium.whitespac
         class-cell4='segment table-cell quarter text-center'
 
         action-project.customer.name='project.customer.name'
-        widget-project.customer.name='admin-project-link'
+        widget-project.customer.name='hubl-admin-project-link'
         class-name='segment full'
 
         action-joinButton="joinButton"
-        widget-joinButton="hubl-admin-project-join-button"
+        widget-joinButton=`hubl-admin-project-join-button-${component.uniq}`
 
         widget-captain='hubl-project-captain'
         widget-members='hubl-project-admins'
diff --git a/src/views/partials/circle/page-circle-chat.pug b/src/views/partials/circle/page-circle-chat.pug
index f902b3ae..589eb09f 100644
--- a/src/views/partials/circle/page-circle-chat.pug
+++ b/src/views/partials/circle/page-circle-chat.pug
@@ -13,7 +13,7 @@ div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-p
   solid-xmpp-chat(
     data-authentication='login',
     data-auto-login='true',
-    data-websocket-url=`${xmppWebsocket || 'wss://jabber.happy-dev.fr/xmpp-websocket'}`,
+    data-websocket-url=`${component.endpoints.xmpp}`,
     data-i18n='en',
     bind-resources
   )
diff --git a/src/views/partials/circle/page-circle-edit.pug b/src/views/partials/circle/page-circle-edit.pug
index c4490d2e..01bc9b36 100644
--- a/src/views/partials/circle/page-circle-edit.pug
+++ b/src/views/partials/circle/page-circle-edit.pug
@@ -11,25 +11,12 @@ solid-ac-checker(permission='acl:Read', bind-resources)
         class-dash='text-color-heading text-bold'          
       )
     div.segment.half.sm-hidden.text-right
-      solid-link(class="backlink", bind-resources, next='circle-profile' data-trans='circle.edit.backlink')
+      solid-link(class="backlink", bind-resources, next=`${component.route}-profile` data-trans='circle.edit.backlink')
 
 div.segment.full.padding-large.whitespace-normal
 
-  solid-widget(name="circle-edit-members-delete")
-    template
-      solid-ac-checker(permission="acl:Delete", data-src="${src}")
-        solid-delete(
-          class='segment text-xsmall children-link-button children-link-text-bold children-link-text-uppercase children-link-color-secondary bordered'
-          data-src="${src}"
-          data-label=''
-          data-trans='data-label=circle.edit.buttonDelete'
-        )
-
-  solid-widget(name='hubl-circle-edit-admin')
-    template ${value == "true" ? "Administrateur" : ""}
-
   solid-ac-checker(permission='acl:Write', bind-resources)
-    div#loader-circle-edit.loader.loader-top
+    div.loader.loader-top(id=`loader-${component.route}-edit`)
       div
       div
       div
@@ -43,7 +30,7 @@ div.segment.full.padding-large.whitespace-normal
       required-name
       required-owner
       required-subtitle
-      range-owner=`${endpoints.users || endpoints.get.users}`
+      range-owner=`${component.endpoints.owners}`
 
       label-name=''
       label-owner=''
@@ -67,7 +54,7 @@ div.segment.full.padding-large.whitespace-normal
       partial=''
 
       submit-button='Enregistrer'
-      next='circle-information'
+      next=`${component.route}-information`
 
       data-trans='label-status=circle.edit.labelStatus;label-name=circle.edit.labelName;label-owner=circle.edit.labelOwner;label-description=circle.edit.labelDescription;submit-button=circle.edit.buttonSubmit;label-subtitle=circle.edit.labelSubtitle;label-help=circle.edit.descriptionHelp'
     )
@@ -79,7 +66,7 @@ div.segment.full.padding-large.whitespace-normal
       bind-resources 
       nested-field='members'
       fields='user'
-      range-user=`${endpoints.users || endpoints.get.users}`
+      range-user=`${component.endpoints.users}`
 
       class-user='add-member'
       widget-user='solid-form-dropdown-autocompletion'
@@ -99,7 +86,7 @@ div.segment.full.padding-large.whitespace-normal
         bind-resources
         nested-field='members'
         fields='cell(segment1(user.account.picture), segment2(line1(user.name, is_admin), line2(atom, user.communities))), self'
-        loader-id='loader-circle-edit'
+        loader-id=`loader-${component.route}-edit`
 
         class-cell='segment table-cell half labelled-avatar two-lines text-left'
         class-self='segment table-cell half text-center'
@@ -122,7 +109,7 @@ div.segment.full.padding-large.whitespace-normal
         widget-is_admin='hubl-circle-edit-admin'
 
         action-self='self'
-        widget-self='circle-edit-members-delete'
+        widget-self='hubl-circle-edit-members-delete'
       )
 
       //- Only to show the table grid
diff --git a/src/views/partials/circle/page-circle-events.pug b/src/views/partials/circle/page-circle-events.pug
index 5ecad213..b01489d1 100644
--- a/src/views/partials/circle/page-circle-events.pug
+++ b/src/views/partials/circle/page-circle-events.pug
@@ -1,10 +1,9 @@
-#circle-listevents
-    solid-event(
-        class='w700'
-        bind-resources
-        nested-field="events"
-        range-event-type=`${endpoints.typeevents || (endpoints.get && endpoints.get.typeevents)}`
-        range-event-circle=`${endpoints.circles || (endpoints.get && endpoints.get.circles)}`
-        upload-dir=`${endpoints.uploads || (endpoints.get && endpoints.get.uploads)}`
-        id-prefix='circles'
-  )
\ No newline at end of file
+solid-event(
+  class='w700'
+  bind-resources
+  nested-field="events"
+  range-event-type=`${component.get('events').endpoints.typeevents}`
+  range-event-circle=`${component.endpoints.get}`
+  upload-dir=`${component.get('events').endpoints.uploads}`
+  id-prefix='circles'
+)
\ No newline at end of file
diff --git a/src/views/partials/circle/page-circle-left.pug b/src/views/partials/circle/page-circle-left.pug
index 55b04ecd..f8ad849b 100644
--- a/src/views/partials/circle/page-circle-left.pug
+++ b/src/views/partials/circle/page-circle-left.pug
@@ -1,11 +1,10 @@
 div.text-center
   div.segment.margin-top-small
     div.segment.shadow.padding-xlarge.text-xlarge.text-left.whitespace-normal
-
       p(data-trans='circle.left.paragraphQuit')
       p
         span(data-trans='circle.left.paragraphJoin')
         span &nbsp;
-        solid-link.link(next="admin-circles" data-trans='circle.left.admin')
+        solid-link.link(next=`admin-${getRoute('circles', true)}` data-trans='circle.left.admin')
         span &nbsp;
         span(data-trans='circle.left.paragraphContact')
diff --git a/src/views/partials/circle/page-circle-polls.pug b/src/views/partials/circle/page-circle-polls.pug
index 59fbe37a..5223149b 100644
--- a/src/views/partials/circle/page-circle-polls.pug
+++ b/src/views/partials/circle/page-circle-polls.pug
@@ -1,9 +1,8 @@
-#circle-polls
-    solid-poll(
-        class='w700'
-        id-prefix='circles'
-        bind-resources
-        nested-field="polls"
-        range-base-polls=`${endpoints.pollRangeBase || (endpoints.get && endpoints.get.pollRangeBase)}`
-        upload-dir=`${endpoints.uploads || (endpoints.get && endpoints.get.uploads)}`
-    )
\ No newline at end of file
+solid-poll(
+  class='w700'
+  id-prefix='circles'
+  bind-resources
+  nested-field="polls"
+  range-base-polls=`${component.get('polls').endpoints.pollRangeBase}`
+  upload-dir=`${component.get('polls').endpoints.uploads}`
+)
\ No newline at end of file
diff --git a/src/views/partials/circle/page-circle-profile.pug b/src/views/partials/circle/page-circle-profile.pug
index 619ff4e8..3a2f09b3 100644
--- a/src/views/partials/circle/page-circle-profile.pug
+++ b/src/views/partials/circle/page-circle-profile.pug
@@ -1,8 +1,12 @@
-solid-router(default-route='circle-profile', hidden)
-  solid-route(name='circle-profile')
-  solid-route(name='circle-edit')
-
-#circle-profile(hidden, data-view="circle-profile")
+solid-router(default-route=`${component.route}-profile`, hidden)
+  solid-route(name=`${component.route}-profile`)
+  solid-route(name=`${component.route}-edit`)
+
+div(
+  id=`${component.route}-profile`
+  hidden
+  data-view=`${component.route}-profile`
+)
   solid-ac-checker.segment.block(permission='acl:Read', bind-resources)
     div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-padding-bottom-small.sm-padding-left-xsmall.border-bottom.border-color-grey.whitespace-normal
       solid-display.text-xxlarge.text-letter-spacing-large(
@@ -14,39 +18,9 @@ solid-router(default-route='circle-profile', hidden)
         class-name='text-color-heading text-bold'
         class-dash='text-color-heading text-bold'          
       )
-
-  solid-widget(name='hubl-circle-team-contact')
-    template 
-      solid-link.icon.icon-secondary.hover.icon-speech.margin-left-xsmall.margin-right-medium(data-src='\${value}', next='messages')
-
-  solid-widget(name='hubl-circle-leave-button')
-    template
-      solid-ac-checker(no-permission='acl:Delete', data-src="${src}", nested-field="circle")
-        solid-delete(
-          class='button text-xsmall text-bold text-uppercase color-secondary bordered'
-          data-src="${src}"
-          data-label=''
-          data-trans='data-label=circle.profile.buttonQuit'
-          next='circle-left'
-        )
-
-  solid-widget(name='hubl-circle-join-button')
-    template
-      button.button.text-xsmall.text-bold.text-uppercase.reversed.color-secondary.bordered.icon.icon-arrow-right-circle
-        solid-form(
-          bind-resource
-          nested-field='members'
-
-          fields='user.username'
-          value-user.username='hubl-workaround-493'
-          widget-user.username='solid-form-hidden'
-
-          submit-button=''
-          data-trans='submit-button=circle.profile.buttonJoin'
-        )
   
   div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-xlarge
-    div#loader-circle-profile.loader
+    div.loader(id=`loader-${component.route}-profile-1`)
       div
       div
       div
@@ -56,7 +30,7 @@ solid-router(default-route='circle-profile', hidden)
       solid-display.segment.half.sm-full.sm-margin-bottom-medium(
         bind-resources
         fields='creationDateSet(title, creationDate)'
-        loader-id='loader-circle-profile'
+        loader-id=`loader-${component.route}-profile-1`
 
         value-title=''
         data-trans='value-title=circle.profile.creationDate'
@@ -67,9 +41,20 @@ solid-router(default-route='circle-profile', hidden)
       .segment.half.sm-full.text-right.margin-bottom-medium.sm-margin-bottom-small
         solid-ac-checker(permission='acl:Append', bind-resources, nested-field='members')
           solid-ac-checker(permission='acl:Delete', bind-resources)
-            solid-link(class='segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next='circle-edit' bind-resources data-trans='circle.profile.buttonModify')
+            solid-link(class='segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next=`${component.route}-edit` bind-resources data-trans='circle.profile.buttonModify')
           solid-ac-checker(no-permission='acl:Delete', bind-resources)
-            solid-link(class='segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next='circle-edit' bind-resources data-trans='circle.profile.buttonAdd')
+            solid-link(class='segment sm-full button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next=`${component.route}-edit` bind-resources data-trans='circle.profile.buttonAdd')
+
+      solid-widget(name=`hubl-circle-leave-button-${uniq}`)
+        template
+          solid-ac-checker(no-permission='acl:Delete', data-src="${src}", nested-field="circle")
+            solid-delete(
+              class='button text-xsmall text-bold text-uppercase color-secondary bordered'
+              data-src="${src}"
+              data-label=''
+              data-trans='data-label=circle.profile.buttonQuit'
+              next=`${component.route}-left`
+            )
 
       .segment.full.text-right.margin-bottom-large.sm-margin-bottom-medium
         solid-display.segment(
@@ -77,7 +62,7 @@ solid-router(default-route='circle-profile', hidden)
           nested-field='members'
           fields='relation'
           action-relation='relation'
-          widget-relation='hubl-circle-leave-button'
+          widget-relation=`hubl-circle-leave-button-${uniq}`
           search-fields='user'
           search-widget-user='solid-form-hidden'
           search-value-user="store://user.@id"
@@ -89,7 +74,7 @@ solid-router(default-route='circle-profile', hidden)
             bind-resources
             data-label=''
             data-trans='data-label=circle.profile.buttonDelete'
-            next='admin-circles'
+            next=`admin-${component.route}`
           )
     
     h3.text-color-heading.text-bold.text-letter-spacing-large(data-trans='circle.profile.description')
@@ -102,13 +87,16 @@ solid-router(default-route='circle-profile', hidden)
 
     h3.text-color-heading.text-bold.text-letter-spacing-large(data-trans='circle.profile.subTitle')
 
-    solid-widget(name='hubl-circle-user-admin')
-      template ${value == "true" ? "Administrateur" : ""}
+    div.loader(id=`loader-${component.route}-profile-2`)
+      div
+      div
+      div
+      div
 
     solid-display.segment.full.labelled-avatar.two-lines.whitespace-normal.children.children-full.sm-children-full.children-margin-bottom-medium(
       bind-resources
       nested-field='members'
-      loader-id='loader-circle-profile'
+      loader-id=`loader-${component.route}-profile-2`
       fields='segment1(user.account.picture), segment2(line1(user.name, user, is_admin), line2(atom, user.communities))'
 
       class-segment1='segment'
@@ -131,5 +119,9 @@ solid-router(default-route='circle-profile', hidden)
       widget-is_admin='hubl-circle-user-admin'
     )
 
-#circle-edit(hidden, data-view="circle-edit")
+div(
+  id=`${component.route}-edit`
+  hidden
+  data-view=`${component.route}-edit`
+)
   include page-circle-edit.pug
diff --git a/src/views/partials/circle/page-circle-resources.pug b/src/views/partials/circle/page-circle-resources.pug
index cfb9159a..4e4cba92 100644
--- a/src/views/partials/circle/page-circle-resources.pug
+++ b/src/views/partials/circle/page-circle-resources.pug
@@ -1,11 +1,10 @@
-#circle-listresources
-    solid-resource(
-        class='w700'
-        bind-resources
-        nested-field="resources"
-        range-resource-type=`${endpoints.resourcestypes || (endpoints.get && endpoints.get.resourcestypes)}`
-        range-resource-keyword=`${endpoints.resourceskeywords || (endpoints.get && endpoints.get.resourceskeywords)}`
-        range-resource-circle=`${endpoints.circles || (endpoints.get && endpoints.get.circles)}`
-        upload-dir=`${endpoints.uploads || (endpoints.get && endpoints.get.uploads)}`
-        id-prefix='circles'
-  )
\ No newline at end of file
+solid-resource(
+  class='w700'
+  bind-resources
+  nested-field="resources"
+  range-resource-type=`${component.get('resources').endpoints.resourcestypes}`
+  range-resource-keyword=`${component.get('resources').endpoints.resourceskeywords}`
+  range-resource-circle=`${component.endpoints.get}`
+  upload-dir=`${component.get('resources').endpoints.uploads}`
+  id-prefix='circles'
+)
\ No newline at end of file
diff --git a/src/views/partials/header.pug b/src/views/partials/header.pug
index cea78f04..1cfe55cb 100644
--- a/src/views/partials/header.pug
+++ b/src/views/partials/header.pug
@@ -1,15 +1,13 @@
-
 div
 
-  solid-link.segment.sm-hidden(next='dashboard')
-    img.logo(src=`${clientLogo || '/images/logo.webp'}`)
+  solid-link.segment.sm-hidden(next=getRoute('dashboard', true))
+    img.logo(src=`${client.logo || '/images/logo.webp'}`)
   button.segment.lg-hidden.icon-menu#toggleMainMenu
 
-
   span.tag.reversed.text-semibold(data-trans='header.beta')
 
   div
-    if themeChecker
+    if componentSet.has("themeChecker")
       div.selector.text-center
         each val, index in ['primary', 'secondary', 'third', 'heading']
           label.segment.margin-right-medium.margin-top-xsmall= 'Couleur ' + (index+1)
@@ -18,102 +16,108 @@ div
               type="text"
             )
 
-    solid-notifications.segment.sm-margin-right-xlarge(
-      nested-field="inbox"
-      bind-user
-    )
+    if componentSet.has("notification")
+      solid-notifications.segment.sm-margin-right-xlarge(
+        nested-field="inbox"
+        bind-user
+      )
 
-    //- User menu visible on large screens
-    details.segment.sm-hidden.user-controls
-      summary.text-right
-        solid-display.labelled-avatar.padding-top-xsmall(
-          fields='segment1(account.picture), segment2(first_name), segment3(button)'
-          class-segment1='segment'
-          class-segment2='segment margin-left-small'
-          class-segment3='segment margin-left-xxsmall'
-          class-account.picture="avatar"
-          class-first_name="text-semibold text-color-heading"
-          class-button='icon icon-arrow-down'
-          widget-account.picture='hubl-user-avatar'
-          bind-user
-        )
-      div.panel
-        nav.bg-color-white.text-semibold.text-color-heading
-          ul
-            if (endpoints.uploads || (endpoints.get && endpoints.get.uploads)) && (endpoints.skills || (endpoints.get && endpoints.get.skills)) && (endpoints.users || (endpoints.get && endpoints.get.users))
-              li.border-bottom.border-color-grey
-                solid-link.segment.padding-small.text-hover(next='profile' data-trans='header.myProfile')
-            li.segment.padding-small.border-bottom.border-color-grey
-              div(data-trans='header.admin')
-              ul.text-normal
-                if endpoints.get.users
-                  solid-link.text-hover(next='admin-communities')
-                    li.segment.padding-top-small
-                      a.icon.icon-people.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.community')
-                if endpoints.get.circles
-                  solid-link.text-hover(next='admin-circles')
-                    li.segment.padding-top-small
-                      a.icon.icon-globe.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.circles')
-                if endpoints.get.projects
-                  solid-link.text-hover(next='admin-projects')
-                    li.segment.padding-top-small
-                      a.icon.icon-folder-alt.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.projects')
-            li.border-bottom.border-color-grey
-              solid-link.segment.padding-small.text-hover(next='about' data-trans='header.about')
-            li
-              button.segment.padding-small.text-hover.text-semibold.text-color-heading(role='log out' onclick="document.querySelector('sib-auth').logout();" data-trans='header.logOut')
+    if componentSet.has("autoLogin") || componentSet.has("registering")
+      //- User menu visible on large screens
+      details.segment.sm-hidden.user-controls
+        summary.text-right
+          solid-display.labelled-avatar.padding-top-xsmall(
+            fields='segment1(account.picture), segment2(first_name), segment3(button)'
+            class-segment1='segment'
+            class-segment2='segment margin-left-small'
+            class-segment3='segment margin-left-xxsmall'
+            class-account.picture="avatar"
+            class-first_name="text-semibold text-color-heading"
+            class-button='icon icon-arrow-down'
+            widget-account.picture='hubl-user-avatar'
+            bind-user
+          )
+        div.panel
+          nav.bg-color-white.text-semibold.text-color-heading
+            ul
+              if componentSet.has("profileDirectory")
+                li.border-bottom.border-color-grey
+                  solid-link.segment.padding-small.text-hover(next=`${getRoute("profileDirectory", true)}-profile` data-trans='header.myProfile')
+              if componentSet.has("admin")
+                li.segment.padding-small.border-bottom.border-color-grey
+                  div(data-trans='header.admin')
+                  ul.text-normal
+                    if componentSet.has("communities")
+                      solid-link.text-hover(next=`admin-${getRoute("chat", true)}`)
+                        li.segment.padding-top-small
+                          a.icon.icon-people.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.community')
+                    if componentSet.has("circles")
+                      solid-link.text-hover(next=`admin-${getRoute("circles", true)}`)
+                        li.segment.padding-top-small
+                          a.icon.icon-globe.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.circles')
+                    if componentSet.has("projects")
+                      solid-link.text-hover(next=`admin-${getRoute("projects", true)}`)
+                        li.segment.padding-top-small
+                          a.icon.icon-folder-alt.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.projects')
+              if componentSet.has("about")
+                li.border-bottom.border-color-grey
+                  solid-link.segment.padding-small.text-hover(next=getRoute('about', true) data-trans='header.about')
+              li
+                button.segment.padding-small.text-hover.text-semibold.text-color-heading(role='log out' onclick="document.querySelector('sib-auth').logout();" data-trans='header.logOut')
 
-      button.segment.lg-hidden.icon-menu#toggleMainMenu
+        button.segment.lg-hidden.icon-menu#toggleMainMenu
 
-    //- User menu visible on small screens
-    details.user-menu.segment.lg-hidden.user-controls
-      summary
-        solid-display.labelled-avatar(
-          fields='segment1(account.picture), segment3(button)'
-          class-segment1='segment'
-          class-segment3='segment sm-arrow-down'
-          class-account.picture="avatar"
-          class-button='icon icon-arrow-down'
-          widget-account.picture='hubl-user-avatar'
-          bind-user
-        )
-        solid-display.user-firstname(
-          fields='segment1(account.picture), segment2(first_name), segment3(button)'
-          class-segment1='segment'
-          class-segment2='segment margin-left-small'
-          class-segment3='segment'
-          class-account.picture="avatar"
-          class-first_name="text-semibold text-color-heading"
-          class-button='icon icon-arrow-down'
-          widget-account.picture='hubl-user-avatar'
-          bind-user
-        )
-      div.panel
-        nav.bg-color-white.text-semibold.text-color-heading
-          ul
-            if (endpoints.uploads || (endpoints.get && endpoints.get.uploads)) && (endpoints.skills || (endpoints.get && endpoints.get.skills)) && (endpoints.users || (endpoints.get && endpoints.get.users))
-              li.border-bottom.border-color-grey
-                solid-link.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.text-hover(next='profile' data-trans='header.myProfile')
-            li.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.border-bottom.border-color-grey
-              div(data-trans='header.admin')
-              ul.text-normal
-                if endpoints.get.users
-                  solid-link.text-hover(next='admin-communities')
-                    li.segment.padding-top-small.sm-padding-top-medium
-                      a.icon.icon-people.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.community')
-                if endpoints.get.circles
-                  solid-link.text-hover(next='admin-circles')
-                    li.segment.padding-top-small.sm-padding-top-medium
-                      a.icon.icon-globe.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.circles')
-                if endpoints.get.projects
-                  solid-link.text-hover(next='admin-projects')
-                    li.segment.padding-top-small.sm-padding-top-medium
-                      a.icon.icon-folder-alt.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.projects')
-            li.border-bottom.border-color-grey
-              solid-link.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.text-hover(next='about' data-trans='header.about')
-            li
-              button.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.text-hover.text-bold.text-color-heading(role='log out' onclick="document.querySelector('sib-auth').logout();" data-trans='header.logOut')
+      //- User menu visible on small screens
+      details.user-menu.segment.lg-hidden.user-controls
+        summary
+          solid-display.labelled-avatar(
+            fields='segment1(account.picture), segment3(button)'
+            class-segment1='segment'
+            class-segment3='segment sm-arrow-down'
+            class-account.picture="avatar"
+            class-button='icon icon-arrow-down'
+            widget-account.picture='hubl-user-avatar'
+            bind-user
+          )
+          solid-display.user-firstname(
+            fields='segment1(account.picture), segment2(first_name), segment3(button)'
+            class-segment1='segment'
+            class-segment2='segment margin-left-small'
+            class-segment3='segment'
+            class-account.picture="avatar"
+            class-first_name="text-semibold text-color-heading"
+            class-button='icon icon-arrow-down'
+            widget-account.picture='hubl-user-avatar'
+            bind-user
+          )
+        div.panel
+          nav.bg-color-white.text-semibold.text-color-heading
+            ul
+              if componentSet.has("profileDirectory")
+                li.border-bottom.border-color-grey
+                  solid-link.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.text-hover(next=`${getRoute("profileDirectory", true)}-profile` data-trans='header.myProfile')
+              if componentSet.has("admin")
+                li.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.border-bottom.border-color-grey
+                  div(data-trans='header.admin')
+                  ul.text-normal
+                    if componentSet.has("communities")
+                      solid-link.text-hover(next=`admin-${getRoute("chat", true)}`)
+                        li.segment.padding-top-small.sm-padding-top-medium
+                          a.icon.icon-people.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.community')
+                    if componentSet.has("circles")
+                      solid-link.text-hover(next=`admin-${getRoute("circles", true)}`)
+                        li.segment.padding-top-small.sm-padding-top-medium
+                          a.icon.icon-globe.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.circles')
+                    if componentSet.has("projects")
+                      solid-link.text-hover(next=`admin-${getRoute("projects", true)}`)
+                        li.segment.padding-top-small.sm-padding-top-medium
+                          a.icon.icon-folder-alt.icon-third.icon-small.icon-margin-right-xsmall(data-trans='admin.menuRight.projects')
+              if componentSet.has("about")
+                li.border-bottom.border-color-grey
+                  solid-link.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.text-hover(next=getRoute('about', true) data-trans='header.about')
+              li
+                button.segment.padding-small.sm-padding-medium.sm-padding-left-xlarge.text-hover.text-bold.text-color-heading(role='log out' onclick="document.querySelector('sib-auth').logout();" data-trans='header.logOut')
 
       button.segment.lg-hidden.icon-menu#toggleMainMenu
- 
+
 
diff --git a/src/views/partials/menu-left.pug b/src/views/partials/menu-left.pug
index 79f4053b..600d8238 100644
--- a/src/views/partials/menu-left.pug
+++ b/src/views/partials/menu-left.pug
@@ -1,232 +1,151 @@
-solid-widget(name='hubl-counter')
-  template
-    solid-badge(data-src="${value == 'badge' ? src : value}")
-
-solid-widget(name='hubl-menu-jabberid')
-  template
-    div.hidden(
-      data-jabberID="${value}"
-    )
-
-solid-widget(name='hubl-menu-publicprivate')
-  template
-    div(
-      class="${value == 'Public' ? 'text-simple-line-icons text-large': 'text-simple-line-icons text-xsmall'}"
-    ) ${value == 'Public' ? '#' : ''}
-
-solid-widget(name='hubl-create-contact')
-  template
-    p.segment.full.create.text-color-white.whitespace-normal(style='display:block!important')
-      span(data-trans="menuLeft.contact.create")
-      span &nbsp;
-      solid-link(next="members" data-trans="menuLeft.contact.profileDir")
-      span &nbsp;
-      span(data-trans="menuLeft.contact.create2")
-
-solid-widget(name='hubl-create')
-  template
-    p.segment.full.create.text-color-white.whitespace-normal(style='display:block!important')
-      span(data-trans="menuLeft.emptyCircleProject.notPartOf")
-      span &nbsp;${value}.
-      span(data-trans="menuLeft.emptyCircleProject.createNew")
-      span &nbsp;
-      solid-link(next="${value.startsWith('proj') ? 'admin-projects' : 'admin-circles'}", data-trans="menuLeft.emptyCircleProject.adminPanel")
-
-solid-widget(name='hubl-menu-fix-url-contact')
-  template
-    solid-link.segment.full(data-src="${value}" next="messages")
-      solid-display.segment.full.text-color-white.heading-active.bg-color-heading.hover.active(
-        data-src='${value}'
-        fields='segment(message(name, chatProfile.jabberID), badge)'
-        
-        class-segment="segment full padding-top-xxsmall padding-bottom-xxsmall padding-right-small padding-left-medium"
-        class-message='segment three-quarter sub-menu-name'
-        class-badge='segment badge'
-
-        value-badge='${value}'
-        widget-badge='hubl-counter'
-        widget-chatProfile.jabberID='hubl-menu-jabberid'
-        widget-name='solid-display-div'
-        order-asc='username'
-      )
-
-solid-widget(name='hubl-menu-fix-url-circle')
-  template
-    solid-link.segment.full(data-src="${value}" next="circle")
-      solid-display.segment.full.text-color-white.heading-active.bg-color-heading.hover.active(
-        data-src='${value}'
-        fields='segment(status, circle(name, jabberID), badge)'
-        class-segment="segment full padding-top-xxsmall padding-bottom-xxsmall padding-right-small padding-left-medium"
-
-        class-status='segment text-top sub-menu-icon'
-
-        class-circle='segment three-quarter sub-menu-name'
-
-        class-name='ellipsis-content'
-
-        class-badge='segment badge'
-
-        value-badge='${value}'
-        widget-status='hubl-menu-publicprivate'
-        widget-badge='hubl-counter'
-        widget-jabberID='hubl-menu-jabberid'
-        widget-name='solid-display-div'
-        order-asc="name"
-      )
-
-solid-widget(name='hubl-menu-fix-url-project')
-  template
-    solid-link.segment.full(data-src="${value}" next="project")
-      solid-display.segment.full.text-color-white.heading-active.bg-color-heading.hover.active(
-        data-src='${value}'
-        fields='segment(status, project(customer.name, name, jabberID), badge)'
-        class-segment="segment full padding-top-xxsmall padding-bottom-xxsmall padding-right-small padding-left-medium"
-
-        class-status='segment text-top sub-menu-icon'
-
-        class-project='segment three-quarter sub-menu-name'
-
-        class-customer.name='ellipsis-content'
-        class-name='ellipsis-content'
-
-        class-badge='segment badge text-top'
-
-        value-badge='${value}'
-        widget-status='hubl-menu-publicprivate'
-        widget-jabberID='hubl-menu-jabberid'
-        widget-badge='hubl-counter'
-        widget-name='solid-display-div'
-        order-asc="customer.name"
-      )
-
-
 solid-router#navbar-router(default-route='dashboard')
-  if endpoints.get.dashboards
-    solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='dashboard')
-      div.segment.margin-right-xxsmall
-        div.icon.icon-small.icon-home
-      div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.dashboard")
-    div.divider
-  if publicDirectory && endpoints.get.users
-    solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='members')
-      div.segment.margin-right-xxsmall
-        div.icon.icon-small.icon-people
-      div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.profileDirectory")
-    div.divider
-  if endpoints.get.joboffers
-    solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='job-offers', rdf-type='hd:joboffer')
-      div.segment.margin-right-xxsmall
-        div.segment.icon.icon-small.icon-briefcase
-      div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.jobBoard")
-    div.divider
-  if endpoints.get.resources
-    solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='resources')
-      div.segment.margin-right-xxsmall
-        div.segment.icon.icon-small.icon-docs
-      div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.resources")
-    div.divider
-  if endpoints.get.polls
-    solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='polls')
-      div.segment.margin-right-xxsmall
-        div.segment.icon.icon-small.icon-bubbles
-      div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.gov")
-    div.divider
-  if endpoints.get.events
-    solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='events')
-      div.segment.margin-right-xxsmall
-        div.segment.icon.icon-small.icon-calendar
-      div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.events")
-    div.divider
-  if endpoints.get.projects
-    div.menu-wrapper
-      solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='admin-projects')
-        div.segment.margin-right-xxsmall
-          div.segment.icon.icon-small.icon-folder-alt
-        div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.projects")
-        div.menu-chevron.segment
-          div.icon-arrow-right-circle
-      solid-route(name='project', rdf-type='hd:project', use-id='', hidden)
-      solid-route(name='admin-projects-create', hidden)
-      solid-route(name='project-left', hidden)
-      div.sub-menu.menu-notification
-        div#loader-projects.loader.loader-menu
-          div
-          div
-          div
-          div
-        solid-display.ellipsis(
-          bind-user
-          nested-field='projects'
-          fields='project'
-          loader-id='loader-projects'
-          empty-widget='hubl-create'
-          empty-value=''
-          data-trans="empty-value=menuLeft.emptyCircleProject.project"
-          widget-project='hubl-menu-fix-url-project'
-          order-asc="project.customer.name"
-        )
-    div.divider
-  if endpoints.get.circles
-    div.menu-wrapper
-      solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='admin-circles')
-        div.segment.margin-right-xxsmall
-          div.segment.icon.icon-small.icon-folder-alt
-        div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.circles")
-        div.menu-chevron.segment
-          div.menu-icon.icon-arrow-right-circle
-      solid-route(name='circle', rdf-type='hd:circle', use-id='', hidden)
-      solid-route(name='admin-circles-create')
-      solid-route(name='circle-left')
-      div.sub-menu.menu-notification
-        div#loader-circles.loader.loader-menu
-          div
-          div
-          div
-          div
-        solid-display.ellipsis(
-          bind-user
-          nested-field='circles'
-          fields='circle'
-          loader-id='loader-circles'
-          empty-widget='hubl-create'
-          empty-value=''
-          data-trans="empty-value=menuLeft.emptyCircleProject.circle"
-          widget-circle='hubl-menu-fix-url-circle'
-          order-asc="circle.name"
-        )
-    div.divider
-    div.menu-wrapper
-      solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name='admin-communities')
-        div.segment.margin-right-xxsmall
-          div.segment.icon.icon-small.icon-folder-alt
-        div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.messages")
-        div.menu-chevron.segment
-          div.menu-icon.icon-arrow-right-circle
-    solid-route(name='admin-users-create', use-id='', hidden)
-    solid-route(name='messages', rdf-type='foaf:user', use-id='', hidden)
-    div.sub-menu.menu-notification
-      div#loader-messages.loader.loader-menu
-        div
-        div
-        div
-        div
-        //- search-fields="contact.name"
-        //- search-label-contact.name=""
-        //- data-trans="search-label-contact.name=menuLeft.search"
-        //- search-widget-contact.name="hubl-search-users"
-      solid-display.segment.full.whitespace-normal(
-        bind-user
-        nested-field='contacts'
-        fields='contact'
-        loader-id='loader-messages'
-        empty-widget='hubl-create-contact'
-        empty-value=''
-        widget-contact='hubl-menu-fix-url-contact'
-        order-asc="contact.username"
-      )
-  div.divider
-  
-  solid-route.menu(name='profile', hidden)
-  solid-route(name='about', hidden)
-  solid-route(name='join-community', use-id, hidden)
-  solid-route(name='login', hidden)
+  for component of components
+    if component.route
+      if component.type == "about"
+        solid-route(name=component.route, hidden)
+      if component.type == "dashboard"
+        solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=component.route)
+          div.segment.margin-right-xxsmall
+            div.icon.icon-small.icon-home
+          div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.dashboard")
+        div.divider
+      if component.type == "circles"
+        div.menu-wrapper
+          if componentSet.has("admin")
+            solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=`admin-${component.route}`)
+              div.segment.margin-right-xxsmall
+                div.segment.icon.icon-small.icon-folder-alt
+              div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.circles")
+              div.menu-chevron.segment
+                div.menu-icon.icon-arrow-right-circle
+            solid-route(name=`admin-${component.route}-create`)
+          else
+            div.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading
+              div.segment.margin-right-xxsmall
+                div.segment.icon.icon-small.icon-folder-alt
+              div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.circles")
+          solid-route(name=component.route, rdf-type='hd:circle', use-id='', hidden)
+          solid-route(name=`${component.route}-left`)
+          div.sub-menu.menu-notification
+            div.loader.loader-menu(id=`loader-${component.route}`)
+              div
+              div
+              div
+              div
+            solid-display.ellipsis(
+              bind-user
+              nested-field='circles'
+              fields='circle'
+              loader-id=`loader-${component.route}`
+              empty-widget='hubl-menu-create'
+              empty-value=''
+              data-trans="empty-value=menuLeft.emptyCircleProject.circle"
+              widget-circle='hubl-menu-fix-url-circle'
+              order-asc="circle.name"
+            )
+        div.divider
+      if component.type == "chat"
+        div.menu-wrapper
+          if componentSet.has("admin")
+            solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=`admin-${component.route}`)
+              div.segment.margin-right-xxsmall
+                div.segment.icon.icon-small.icon-folder-alt
+              div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.messages")
+              div.menu-chevron.segment
+                div.menu-icon.icon-arrow-right-circle
+            solid-route(name=`admin-${component.route}-create`, use-id='', hidden)
+          else
+            div.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading
+              div.segment.margin-right-xxsmall
+                div.segment.icon.icon-small.icon-folder-alt
+              div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.messages")
+        solid-route(name=component.route, rdf-type='foaf:user', use-id='', hidden)
+        div.sub-menu.menu-notification
+          div.loader.loader-menu(id=`loader-${component.route}`)
+            div
+            div
+            div
+            div
+            //- search-fields="contact.name"
+            //- search-label-contact.name=""
+            //- data-trans="search-label-contact.name=menuLeft.search"
+            //- search-widget-contact.name="hubl-search-users"
+          solid-display.segment.full.whitespace-normal(
+            bind-user
+            nested-field='contacts'
+            fields='contact'
+            loader-id=`loader-${component.route}`
+            empty-widget='hubl-create-contact'
+            empty-value=''
+            widget-contact='hubl-menu-fix-url-contact'
+            order-asc="contact.username"
+          )
+      if component.type == "projects"
+        div.menu-wrapper
+          if componentSet.has("admin")
+            solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=`admin-${component.route}`)
+              div.segment.margin-right-xxsmall
+                div.segment.icon.icon-small.icon-folder-alt
+              div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.projects")
+              div.menu-chevron.segment
+                div.icon-arrow-right-circle
+            solid-route(name=`admin-${component.route}-create`, hidden)
+          else
+            div.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading
+              div.segment.margin-right-xxsmall
+                div.segment.icon.icon-small.icon-folder-alt
+              div.segment.three-quarter.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.projects")
+          solid-route(name=component.route, rdf-type='hd:project', use-id='', hidden)
+          solid-route(name=`${component.route}-left`, hidden)
+          div.sub-menu.menu-notification
+            div.loader.loader-menu(id=`loader-${component.route}`)
+              div
+              div
+              div
+              div
+            solid-display.ellipsis(
+              bind-user
+              nested-field='projects'
+              fields='project'
+              loader-id=`loader-${component.route}`
+              empty-widget='hubl-menu-create'
+              empty-value=''
+              data-trans="empty-value=menuLeft.emptyCircleProject.project"
+              widget-project='hubl-menu-fix-url-project'
+              order-asc="project.customer.name"
+            )
+        div.divider
+      if component.type == "profileDirectory"
+        solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=component.route)
+          div.segment.margin-right-xxsmall
+            div.icon.icon-small.icon-people
+          div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.profileDirectory")
+        solid-route.menu(name=`${component.route}-profile`, hidden)
+        div.divider
+      if component.type == "jobBoard"
+        solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=component.route, rdf-type='hd:joboffer')
+          div.segment.margin-right-xxsmall
+            div.segment.icon.icon-small.icon-briefcase
+          div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.jobBoard")
+        div.divider
+      if component.type == "resources"
+        solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=component.route)
+          div.segment.margin-right-xxsmall
+            div.segment.icon.icon-small.icon-docs
+          div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.resources")
+        div.divider
+      if component.type == "polls"
+        solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=component.route)
+          div.segment.margin-right-xxsmall
+            div.segment.icon.icon-small.icon-bubbles
+          div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.gov")
+        div.divider
+      if component.type == "events"
+        solid-route.menu.segment.full.padding-small.text-semibold.text-color-white.heading-active.bg-color-heading.hover.active(name=component.route)
+          div.segment.margin-right-xxsmall
+            div.segment.icon.icon-small.icon-calendar
+          div.segment.text-uppercase.text-letter-spacing-large(data-trans="menuLeft.events")
+        div.divider
+  if componentSet.has('registering')
+    solid-route(name='join-community', use-id, hidden)
+    solid-route(name='login', hidden)
diff --git a/src/views/partials/project/page-project-chat.pug b/src/views/partials/project/page-project-chat.pug
index 96f1aa41..46ff2f37 100644
--- a/src/views/partials/project/page-project-chat.pug
+++ b/src/views/partials/project/page-project-chat.pug
@@ -17,7 +17,7 @@ div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-p
   solid-xmpp-chat(
     data-authentication='login',
     data-auto-login='true',
-    data-websocket-url=`${xmppWebsocket || 'wss://jabber.happy-dev.fr/xmpp-websocket'}`,
+    data-websocket-url=`${component.endpoints.xmpp}`,
     data-i18n='en',
     bind-resources
   )
diff --git a/src/views/partials/project/page-project-edit.pug b/src/views/partials/project/page-project-edit.pug
index a6789cfd..894ba30b 100644
--- a/src/views/partials/project/page-project-edit.pug
+++ b/src/views/partials/project/page-project-edit.pug
@@ -15,25 +15,12 @@ solid-ac-checker(permission='acl:Read', bind-resources)
         value-dash=' - '
       )
     div.segment.half.sm-hidden.text-right
-      solid-link(class='backlink', bind-resources, next='project-profile' data-trans='project.edit.backlink')
+      solid-link(class='backlink', bind-resources, next=`${component.route}-profile` data-trans='project.edit.backlink')
 
 div.segment.full.padding-large.whitespace-normal
 
-  solid-widget(name="project-edit-members-delete")
-    template
-      solid-ac-checker(permission="acl:Delete", data-src="${src}")
-        solid-delete(
-          class='segment text-xsmall children-link-text-bold children-link-text-uppercase children-link-button children-link-color-secondary bordered'
-          data-src="${src}"
-          data-label=''
-          data-trans='data-label=project.edit.buttonDelete'
-        )
-
-  solid-widget(name='hubl-project-edit-admin')
-      template ${value == "true" ? "Administrateur" : ""}
-
   solid-ac-checker(permission='acl:Write', bind-resources)
-    div#loader-project-edit.loader.loader-top
+    div.loader.loader-top(id=`loader-${component.route}-edit`)
       div
       div
       div
@@ -42,12 +29,12 @@ div.segment.full.padding-large.whitespace-normal
     //- Add translation for description and captain in the translate file
     solid-form.form(
       bind-resources
-    
+
       fields='customer.name, name, description, help, captain, linebreak'
       required-customer.name
       required-name
       required-captain
-      range-captain=`${endpoints.users || endpoints.get.users}`
+      range-captain=`${component.endpoints.captains}`
 
       label-name=''
       label-customer.name=''
@@ -66,12 +53,12 @@ div.segment.full.padding-large.whitespace-normal
       widget-captain='solid-form-dropdown-autocompletion-label'
       widget-linebreak='solid-form-hidden'
       widget-help='solid-form-hidden-label'
-      
+
       partial=""
 
       submit-button='Enregistrer'
-      next='project-information'
-      
+      next=`${component.route}-information`
+
       data-trans='label-name=project.edit.labelName;label-captain=project.edit.labelCaptain;label-customer.name=project.edit.labelCustomer;label-description=project.edit.labelDescription;label-help=project.edit.descriptionHelp;submit-button=project.edit.buttonSubmit'
     )
 
@@ -82,7 +69,7 @@ div.segment.full.padding-large.whitespace-normal
       bind-resources 
       nested-field='members'
       fields='user'
-      range-user=`${endpoints.users || endpoints.get.users}`
+      range-user=`${component.endpoints.users}`
 
       class-user='add-member whitespace-normal'
       label-user=''
@@ -98,13 +85,12 @@ div.segment.full.padding-large.whitespace-normal
         div.segment.table-cell.half(data-trans='project.edit.tableHeader2')
         div.segment.table-cell.half(data-trans='project.edit.tableHeader1')
 
-      //-class='table-body'
       solid-display(
         class='table-body'
         bind-resources
         nested-field='members'
         fields='cell(segment1(user.account.picture), segment2(line1(user.name, is_admin), line2(atom, user.communities))), self'
-        loader-id='loader-project-edit'
+        loader-id=`loader-${component.route}-edit`
 
         class-cell='segment table-cell half labelled-avatar two-lines text-left'
         class-self='segment table-cell half text-center'
@@ -119,7 +105,7 @@ div.segment.full.padding-large.whitespace-normal
         class-line2='segment block'
         class-atom='icon icon-large icon-third mdi-atom margin-right-xxsmall'
         class-user.communities='full'
-        
+
         multiple-user.communities
         multiple-user.communities-fields="community.name"
 
@@ -127,5 +113,5 @@ div.segment.full.padding-large.whitespace-normal
         widget-is_admin='hubl-project-edit-admin'
 
         action-self='self'
-        widget-self='project-edit-members-delete'
+        widget-self='hubl-project-edit-members-delete'
       )
diff --git a/src/views/partials/project/page-project-left.pug b/src/views/partials/project/page-project-left.pug
index 39476483..2c556c95 100644
--- a/src/views/partials/project/page-project-left.pug
+++ b/src/views/partials/project/page-project-left.pug
@@ -1,12 +1,10 @@
-#project-left
-  div.text-center
-    div.segment.margin-top-small
-      div.segment.shadow.padding-xlarge.text-xlarge.text-left.whitespace-normal
-
-        p(data-trans='circle.left.paragraphQuit')
-        p
-          span(data-trans='project.left.paragraphJoin')
-          span &nbsp;
-          solid-link.link(next="admin-projects" data-trans='project.left.admin')
-          span &nbsp;
-          span(data-trans='project.left.paragraphContact')
+div.text-center
+  div.segment.margin-top-small
+    div.segment.shadow.padding-xlarge.text-xlarge.text-left.whitespace-normal
+      p(data-trans='circle.left.paragraphQuit')
+      p
+        span(data-trans='project.left.paragraphJoin')
+        span &nbsp;
+        solid-link.link(next=`admin-${getRoute('projects', true)}` data-trans='project.left.admin')
+        span &nbsp;
+        span(data-trans='project.left.paragraphContact')
diff --git a/src/views/partials/project/page-project-picture.pug b/src/views/partials/project/page-project-picture.pug
index e04a3422..e39a10d6 100644
--- a/src/views/partials/project/page-project-picture.pug
+++ b/src/views/partials/project/page-project-picture.pug
@@ -1,15 +1,15 @@
-div.content-box__info
-			
-  solid-link(class='backlink', bind-resources, next='project-edit' data-trans='project.modifyPicture.backlink')
+//- div.content-box__info
 
-  h1(data-trans='project.modifyPicture.title')
-  
-  solid-picture.project-edit-picture(
-    bind-resources
-    upload-src=`${endpoints.uploads || endpoints.post.uploads}`
-    upload-id="solid-project-edit-picture"
-    nested-fields='customer'
-    fields='logo'
-    next='project-edit'
-    additional='name'
-  )
+//-   solid-link(class='backlink', bind-resources, next=`${component.route}-edit` data-trans='project.modifyPicture.backlink')
+
+//-   h1(data-trans='project.modifyPicture.title')
+
+//-   solid-picture.project-edit-picture(
+//-     bind-resources
+//-     upload-src=`${component.endpoints.uploads}`
+//-     upload-id="solid-project-edit-picture"
+//-     nested-fields='customer'
+//-     fields='logo'
+//-     next=`${component.route}-edit`
+//-     additional='name'
+//-   )
diff --git a/src/views/partials/project/page-project-profile.pug b/src/views/partials/project/page-project-profile.pug
index 895cc279..9620c6d0 100644
--- a/src/views/partials/project/page-project-profile.pug
+++ b/src/views/partials/project/page-project-profile.pug
@@ -1,8 +1,12 @@
-solid-router(default-route='project-profile', hidden)
-  solid-route(name='project-profile')
-  solid-route(name='project-edit')
-
-#project-profile(hidden, data-view="project-profile")
+solid-router(default-route=`${component.route}-profile`, hidden)
+  solid-route(name=`${component.route}-profile`)
+  solid-route(name=`${component.route}-edit`)
+
+div(
+  id=`${component.route}-profile`
+  hidden
+  data-view=`${component.route}-profile`
+)
   solid-ac-checker.segment.block(permission='acl:Read', bind-resources)
     div.segment.full.padding-large.sm-padding-top-small.sm-padding-right-xsmall.sm-padding-bottom-small.sm-padding-left-xsmall.border-bottom.border-color-grey.whitespace-normal
       solid-display.text-xxlarge.text-letter-spacing-large(
@@ -14,27 +18,23 @@ solid-router(default-route='project-profile', hidden)
         class-customer.name='text-color-heading text-bold text-uppercase'
         class-dash='text-color-heading text-bold text-xlarge'
         class-name=''
-  
+
         value-const-title1='N°'
         value-dash=' - '
       )
 
-  solid-widget(name='hubl-project-team-contact')
-    template 
-      solid-link.icon.icon-secondary.hover.icon-speech.margin-left-xsmall.margin-right-medium(data-src='\${value}', next='messages')
-
   div.segment.full.padding-large.sm-padding-xsmall.sm-padding-top-xlarge
-    div#loader-project-profile.loader
+    div.loader(id=`loader-${component.route}-profile`)
       div
       div
       div
       div
-  
+
     div.whitespace-normal
       solid-display.segment.half.sm-full.sm-margin-bottom-medium(
         bind-resources
         fields='creationDateSet(title, creationDate)'
-        loader-id='loader-project-profile'
+        loader-id=`loader-${component.route}-profile`
 
         class-title='word-spacing-right'
 
@@ -43,30 +43,30 @@ solid-router(default-route='project-profile', hidden)
 
         widget-creationDate='solid-display-value-date'
       )
-      
+
       solid-ac-checker.segment.half.sm-full.text-right(permission='acl:Append', bind-resources, nested-field='members')
         solid-ac-checker(permission='acl:Delete', bind-resources)
-          solid-link(class='segment sm-full margin-bottom-large sm-margin-bottom-medium button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next='project-edit' bind-resources data-trans='project.profile.buttonModify')
+          solid-link(class='segment sm-full margin-bottom-large sm-margin-bottom-medium button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next=`${component.route}-edit` bind-resources data-trans='project.profile.buttonModify')
         solid-ac-checker(no-permission='acl:Delete', bind-resources)
-          solid-link(class='segment sm-full margin-bottom-large sm-margin-bottom-medium button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next='project-edit' bind-resources data-trans='project.profile.buttonAdd')
-      
+          solid-link(class='segment sm-full margin-bottom-large sm-margin-bottom-medium button text-xsmall text-bold text-uppercase text-center reversed color-secondary bordered icon icon-pencil' next=`${component.route}-edit` bind-resources data-trans='project.profile.buttonAdd')
+
       solid-ac-checker.segment.full.text-right.margin-bottom-large.sm-margin-bottom-medium(permission='acl:Delete', bind-resources)
         solid-delete(
           class='segment sm-full children-link-button text-xsmall text-center children-link-text-bold children-link-text-uppercase children-link-color-secondary bordered'
           bind-resources
           data-label=''
           data-trans='data-label=project.profile.buttonDelete'
-          next='admin-projects'
+          next=`admin-${component.route}`
         )
 
-      solid-widget(name='hubl-project-leave-button')
+      solid-widget(name=`hubl-project-leave-button-${component.uniq}`)
         template
           solid-delete(
             class='button text-xsmall text-bold text-uppercase color-secondary bordered'
             data-src="${src}"
             data-label=''
             data-trans='data-label=project.profile.buttonQuit'
-            next='project-left'
+            next=`${component.route}-left`
           )
 
       solid-ac-checker.segment.full.text-right.margin-bottom-large.sm-margin-bottom-medium(no-permission='acl:Delete', bind-resources)
@@ -76,13 +76,13 @@ solid-router(default-route='project-profile', hidden)
           fields='relation'
 
           action-relation='relation'
-          widget-relation='hubl-project-leave-button'
+          widget-relation=`hubl-project-leave-button-${component.uniq}`
 
           search-fields='user'
           search-widget-user='solid-form-hidden'
           search-value-user="store://user.@id"
         )
-  
+
     h3.text-color-heading.text-bold.text-letter-spacing-large(data-trans='project.profile.captain')
 
     solid-display(
@@ -92,7 +92,7 @@ solid-router(default-route='project-profile', hidden)
     )
 
     h3.text-color-heading.text-bold.text-letter-spacing-large(data-trans='project.profile.description')
-    
+
     solid-display.segment.block.sm-hidden.whitespace-normal(
       bind-resources
       fields='description'
@@ -124,5 +124,9 @@ solid-router(default-route='project-profile', hidden)
       widget-user='hubl-project-team-contact'
     )
 
-#project-edit(hidden, data-view="project-edit")
+div(
+  id=`${component.route}-edit`
+  hidden
+  data-view=`${component.route}-edit`
+)
   include page-project-edit.pug
diff --git a/src/views/partials/widgets.pug b/src/views/partials/widgets.pug
index 021e69a0..e9be69bb 100644
--- a/src/views/partials/widgets.pug
+++ b/src/views/partials/widgets.pug
@@ -1,4 +1,35 @@
 //- Import your widgets from the `widget`folder here
 
+include widgets/hubl-action-community.pug
+include widgets/hubl-admin-circle-counter-alternate.pug
+include widgets/hubl-admin-circle-counter.pug
+include widgets/hubl-admin-circle-link-alternate.pug
+include widgets/hubl-admin-circle-link.pug
+include widgets/hubl-admin-community-counter.pug
+include widgets/hubl-admin-project-counter-alternate.pug
+include widgets/hubl-admin-project-counter.pug
+include widgets/hubl-admin-project-link-alternate.pug
+include widgets/hubl-admin-project-link.pug
 include widgets/hubl-captain.pug
-include widgets/hubl-user-avatar.pug
\ No newline at end of file
+include widgets/hubl-circle-edit-admin.pug
+include widgets/hubl-circle-edit-members-delete.pug
+include widgets/hubl-circle-join-button.pug
+include widgets/hubl-circle-owner.pug
+include widgets/hubl-circle-team-contact.pug
+include widgets/hubl-circle-user-admin.pug
+include widgets/hubl-counter.pug
+include widgets/hubl-create-contact.pug
+include widgets/hubl-email-field.pug
+include widgets/hubl-menu-create.pug
+include widgets/hubl-menu-fix-url-circle.pug
+include widgets/hubl-menu-fix-url-contact.pug
+include widgets/hubl-menu-fix-url-project.pug
+include widgets/hubl-menu-jabberid.pug
+include widgets/hubl-menu-publicprivate.pug
+include widgets/hubl-project-admins.pug
+include widgets/hubl-project-captain.pug
+include widgets/hubl-project-edit-admin.pug
+include widgets/hubl-project-edit-members-delete.pug
+include widgets/hubl-project-team-contact.pug
+include widgets/hubl-user-avatar.pug
+include widgets/hubl-username-field.pug
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-action-community.pug b/src/views/partials/widgets/hubl-action-community.pug
new file mode 100644
index 00000000..3d731b33
--- /dev/null
+++ b/src/views/partials/widgets/hubl-action-community.pug
@@ -0,0 +1,12 @@
+if componentSet.has('admin') && componentSet.has('chat')
+  solid-widget(name='hubl-action-community')
+    template
+      solid-ac-checker(data-src="${value}", nested-field="members", permission='acl:Append')
+        solid-link(
+          class='button text-small text-bold text-uppercase reversed color-secondary bordered icon icon-plus'
+          data-src="${value}"
+          next=`admin-${getRoute("chat", true)}-create`
+          data-trans='communities.linkInvite'
+        )
+      solid-ac-checker(data-src="${value}", nested-field="members", no-permission='acl:Append')
+        div.button.button-disabled(data-trans='communities.noPermission')
diff --git a/src/views/partials/widgets/hubl-admin-circle-counter-alternate.pug b/src/views/partials/widgets/hubl-admin-circle-counter-alternate.pug
new file mode 100644
index 00000000..d7c9ae19
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-circle-counter-alternate.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('circles')
+  solid-widget(name='hubl-admin-circle-counter-alternate')
+    template
+      div(style='float:right')
+        solid-display(
+          fields=''
+          data-src="${src}"
+          nested-field="circle.members"
+          counter-template="\\\${counter}"
+        )
+        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
diff --git a/src/views/partials/widgets/hubl-admin-circle-counter.pug b/src/views/partials/widgets/hubl-admin-circle-counter.pug
new file mode 100644
index 00000000..7feaf9ca
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-circle-counter.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('circles')
+  solid-widget(name='hubl-admin-circle-counter')
+    template
+      div(style='float:right')
+        solid-display(
+          fields=''
+          data-src="${src}"
+          nested-field="members"
+          counter-template="\\\${counter}"
+        )
+        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
diff --git a/src/views/partials/widgets/hubl-admin-circle-link-alternate.pug b/src/views/partials/widgets/hubl-admin-circle-link-alternate.pug
new file mode 100644
index 00000000..33965e16
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-circle-link-alternate.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('circles')
+  solid-widget(name='hubl-admin-circle-link-alternate')
+    template
+      solid-display(
+        data-src='${src}'
+        nested-field='circle'
+        fields='name'
+        class-name='segment block margin-bottom-xxsmall text-xlarge text-color-heading text-semibold text-letter-spacing-large text-underline text-ellipsis admin-name-ellipsis'
+        action-name='name'
+        widget-name='hubl-admin-circle-link'
+      )
diff --git a/src/views/partials/widgets/hubl-admin-circle-link.pug b/src/views/partials/widgets/hubl-admin-circle-link.pug
new file mode 100644
index 00000000..c4777786
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-circle-link.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('circles')
+  solid-widget(name='hubl-admin-circle-link')
+    template
+      solid-link(
+        data-src='${src}'
+        next=`${getRoute('circles', true)}-information`
+      )
+        solid-display(
+          data-src='${src}'
+          fields='name'
+        )
diff --git a/src/views/partials/widgets/hubl-admin-community-counter.pug b/src/views/partials/widgets/hubl-admin-community-counter.pug
new file mode 100644
index 00000000..5279fee8
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-community-counter.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('chat')
+  solid-widget(name='hubl-admin-community-counter')
+    template
+      div(style='float:right')
+        solid-display(
+          fields=''
+          data-src="${src}"
+          nested-field="community.members"
+          counter-template="\\\${counter}"
+        )
+        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
diff --git a/src/views/partials/widgets/hubl-admin-project-counter-alternate.pug b/src/views/partials/widgets/hubl-admin-project-counter-alternate.pug
new file mode 100644
index 00000000..935fd5a3
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-project-counter-alternate.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('projects')
+  solid-widget(name='hubl-admin-project-counter-alternate')
+    template
+      div(style='float:right')
+        solid-display(
+          fields=''
+          data-src="${src}"
+          nested-field="project.members"
+          counter-template="\\\${counter}"
+        )
+        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
diff --git a/src/views/partials/widgets/hubl-admin-project-counter.pug b/src/views/partials/widgets/hubl-admin-project-counter.pug
new file mode 100644
index 00000000..93a3d5cd
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-project-counter.pug
@@ -0,0 +1,12 @@
+if componentSet.has('admin') && componentSet.has('projects')
+  solid-widget(name='hubl-admin-project-counter')
+    template
+      div(style='float:right')
+        solid-display(
+          fields=''
+          data-src="${src}"
+          nested-field="members"
+          counter-template="\\\${counter}"
+        )
+        span.icon.icon-people.icon-xsmall.margin-right-xxsmall
+        
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-admin-project-link-alternate.pug b/src/views/partials/widgets/hubl-admin-project-link-alternate.pug
new file mode 100644
index 00000000..466efdc9
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-project-link-alternate.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('projects')
+  solid-widget(name='hubl-admin-project-link-alternate')
+    template
+      solid-display(
+        data-src='${src}'
+        nested-field='project'
+        fields='name'
+        class-name='segment block margin-bottom-xxsmall text-xlarge text-color-heading text-semibold text-letter-spacing-large text-underline text-ellipsis admin-name-ellipsis'
+        action-name='name'
+        widget-name='hubl-admin-project-link'
+      )
diff --git a/src/views/partials/widgets/hubl-admin-project-link.pug b/src/views/partials/widgets/hubl-admin-project-link.pug
new file mode 100644
index 00000000..86032be5
--- /dev/null
+++ b/src/views/partials/widgets/hubl-admin-project-link.pug
@@ -0,0 +1,11 @@
+if componentSet.has('admin') && componentSet.has('projects')
+  solid-widget(name='hubl-admin-project-link')
+    template
+      solid-link(
+        data-src='${src}'
+        next=`${getRoute('projects')}-information`
+      )
+        solid-display(
+          data-src='${src}'
+          fields='customer.name'
+        )
diff --git a/src/views/partials/widgets/hubl-captain.pug b/src/views/partials/widgets/hubl-captain.pug
index 61e04873..f6d290f2 100644
--- a/src/views/partials/widgets/hubl-captain.pug
+++ b/src/views/partials/widgets/hubl-captain.pug
@@ -1,31 +1,29 @@
-solid-widget(name='hubl-captain-contact')
+if componentSet.has('projects')
+  solid-widget(name='hubl-captain-contact')
     template 
-      solid-link.icon.icon-secondary.hover.icon-speech.margin-left-xsmall.margin-right-medium(data-src='\${value}', next='messages')
+      solid-link.icon.icon-secondary.hover.icon-speech.margin-left-xsmall.margin-right-medium(data-src='\${value}', next=getRoute('chat', true))
 
-solid-widget(name='hubl-captain')
-  template
-    solid-display.segment.full.margin-bottom-large.labelled-avatar.two-lines(
-      data-src="${value}"
-      fields='segment1(account.picture), segment2(line1(name, user), line2(atom, communities))'
+  solid-widget(name='hubl-captain')
+    template
+      solid-display.segment.full.margin-bottom-large.labelled-avatar.two-lines(
+        data-src="${value}"
+        fields='segment1(account.picture), segment2(line1(name, user), line2(atom, communities))'
 
-      class-segment1='segment'
-      class-account.picture='avatar'
-      
-      class-segment2='segment three-quarter margin-left-xsmall'
-      class-line1='segment block'
-      class-name='text-small text-semibold text-color-heading text-sub'
-      class-line2='segment block'
-      class-atom='icon icon-large icon-third mdi-atom margin-right-xxsmall'
-      class-communities='full'
+        class-segment1='segment'
+        class-account.picture='avatar'
 
-      value-user='${value}'
+        class-segment2='segment three-quarter margin-left-xsmall'
+        class-line1='segment block'
+        class-name='text-small text-semibold text-color-heading text-sub'
+        class-line2='segment block'
+        class-atom='icon icon-large icon-third mdi-atom margin-right-xxsmall'
+        class-communities='full'
 
-      multiple-communities
-      multiple-communities-fields='community.name'
+        value-user='${value}'
 
-      widget-account.picture='hubl-user-avatar'
-      widget-user='hubl-captain-contact'
-    )
-    
-    //- To remove from translate file :
-      data-trans='value-is_lead=template-captain.isLead'
+        multiple-communities
+        multiple-communities-fields='community.name'
+
+        widget-account.picture='hubl-user-avatar'
+        widget-user='hubl-captain-contact'
+      )
diff --git a/src/views/partials/widgets/hubl-circle-edit-admin.pug b/src/views/partials/widgets/hubl-circle-edit-admin.pug
new file mode 100644
index 00000000..ecaf28f5
--- /dev/null
+++ b/src/views/partials/widgets/hubl-circle-edit-admin.pug
@@ -0,0 +1,3 @@
+if componentSet.has('circles')
+  solid-widget(name='hubl-circle-edit-admin')
+    template ${value == "true" ? "Administrateur" : ""}
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-circle-edit-members-delete.pug b/src/views/partials/widgets/hubl-circle-edit-members-delete.pug
new file mode 100644
index 00000000..b7d8eaa7
--- /dev/null
+++ b/src/views/partials/widgets/hubl-circle-edit-members-delete.pug
@@ -0,0 +1,10 @@
+if componentSet.has('circles')
+  solid-widget(name="hubl-circle-edit-members-delete")
+    template
+      solid-ac-checker(permission="acl:Delete", data-src="${src}")
+        solid-delete(
+          class='segment text-xsmall children-link-button children-link-text-bold children-link-text-uppercase children-link-color-secondary bordered'
+          data-src="${src}"
+          data-label=''
+          data-trans='data-label=circle.edit.buttonDelete'
+        )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-circle-join-button.pug b/src/views/partials/widgets/hubl-circle-join-button.pug
new file mode 100644
index 00000000..553a9775
--- /dev/null
+++ b/src/views/partials/widgets/hubl-circle-join-button.pug
@@ -0,0 +1,15 @@
+if componentSet.has('circles')
+  solid-widget(name='hubl-circle-join-button')
+    template
+      button.button.text-xsmall.text-bold.text-uppercase.reversed.color-secondary.bordered.icon.icon-arrow-right-circle
+        solid-form(
+          bind-resource
+          nested-field='members'
+
+          fields='user.username'
+          value-user.username='hubl-workaround-493'
+          widget-user.username='solid-form-hidden'
+
+          submit-button=''
+          data-trans='submit-button=circle.profile.buttonJoin'
+        )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-circle-owner.pug b/src/views/partials/widgets/hubl-circle-owner.pug
new file mode 100644
index 00000000..6cf0f534
--- /dev/null
+++ b/src/views/partials/widgets/hubl-circle-owner.pug
@@ -0,0 +1,19 @@
+if componentSet.has('admin') && componentSet.has('circles')
+  solid-widget(name='hubl-circle-owner')
+    template
+      solid-display.segment.block.margin-top-xxsmall.margin-bottom-xxsmall.labelled-avatar.two-lines(
+        data-src='${await value}'
+        fields='segment1(account.picture), segment2(line1(name), line2(at, username))'
+
+        class-segment1='segment'
+        class-account.picture='avatar'
+
+        class-segment2='segment three-quarter margin-left-xsmall'
+        class-line1='segment block'
+        class-name='text-small text-semibold text-color-heading text-sub'
+        class-line2='segment block text-xsmall'
+
+        widget-account.picture='hubl-user-avatar'
+
+        value-at='@'
+      )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-circle-team-contact.pug b/src/views/partials/widgets/hubl-circle-team-contact.pug
new file mode 100644
index 00000000..c005f461
--- /dev/null
+++ b/src/views/partials/widgets/hubl-circle-team-contact.pug
@@ -0,0 +1,4 @@
+if componentSet.has('circles')
+  solid-widget(name='hubl-circle-team-contact')
+    template 
+      solid-link.icon.icon-secondary.hover.icon-speech.margin-left-xsmall.margin-right-medium(data-src='\${value}', next=getRoute('chat', true))
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-circle-user-admin.pug b/src/views/partials/widgets/hubl-circle-user-admin.pug
new file mode 100644
index 00000000..1d87292c
--- /dev/null
+++ b/src/views/partials/widgets/hubl-circle-user-admin.pug
@@ -0,0 +1,3 @@
+if componentSet.has('circles')
+  solid-widget(name='hubl-circle-user-admin')
+    template ${value == "true" ? "Administrateur" : ""}
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-counter.pug b/src/views/partials/widgets/hubl-counter.pug
new file mode 100644
index 00000000..91609326
--- /dev/null
+++ b/src/views/partials/widgets/hubl-counter.pug
@@ -0,0 +1,7 @@
+if componentSet.has('chat') || componentSet.has('circles') || componentSet.has('projects')
+  solid-widget(name='hubl-counter')
+    template
+      if componentSet.has('notification')
+        solid-badge(data-src="${value == 'badge' ? src : value}")
+      else
+        span
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-create-contact.pug b/src/views/partials/widgets/hubl-create-contact.pug
new file mode 100644
index 00000000..1fec94d0
--- /dev/null
+++ b/src/views/partials/widgets/hubl-create-contact.pug
@@ -0,0 +1,9 @@
+if componentSet.has('chat')
+  solid-widget(name='hubl-create-contact')
+    template
+      p.segment.full.create.text-color-white.whitespace-normal(style='display:block!important')
+        span(data-trans="menuLeft.contact.create")
+        span &nbsp;
+        solid-link(next=getRoute('profileDirectory', true) data-trans="menuLeft.contact.profileDir")
+        span &nbsp;
+        span(data-trans="menuLeft.contact.create2")
diff --git a/src/views/partials/widgets/hubl-email-field.pug b/src/views/partials/widgets/hubl-email-field.pug
new file mode 100644
index 00000000..2fed7c22
--- /dev/null
+++ b/src/views/partials/widgets/hubl-email-field.pug
@@ -0,0 +1,6 @@
+if componentSet.has('admin') && componentSet.has('chat')
+  solid-widget(name='hubl-email-field')
+    template
+      div.segment.margin-bottom-medium.half.sm-full.padding-left-small.sm-padding-none.text-small.text-semibold.text-uppercase.text-color-heading
+        label ${label}
+        input(type="email" label='${label}' name="email" required value="\${value}" data-holder)
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-menu-create.pug b/src/views/partials/widgets/hubl-menu-create.pug
new file mode 100644
index 00000000..30b104f7
--- /dev/null
+++ b/src/views/partials/widgets/hubl-menu-create.pug
@@ -0,0 +1,10 @@
+if componentSet.has('circles') || componentSet.has('projects')
+  solid-widget(name='hubl-menu-create')
+    template
+      p.segment.full.create.text-color-white.whitespace-normal(style='display:block!important')
+        span(data-trans="menuLeft.emptyCircleProject.notPartOf")
+        span &nbsp;${value}.
+        if componentSet.has('admin')
+          span(data-trans="menuLeft.emptyCircleProject.createNew")
+          span &nbsp;
+          solid-link(next=`\${value.startsWith('proj') ? 'admin-${getRoute('projects', true)}' : 'admin-${getRoute('circles', true)}'}`, data-trans="menuLeft.emptyCircleProject.adminPanel")
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-menu-fix-url-circle.pug b/src/views/partials/widgets/hubl-menu-fix-url-circle.pug
new file mode 100644
index 00000000..58dcbf6f
--- /dev/null
+++ b/src/views/partials/widgets/hubl-menu-fix-url-circle.pug
@@ -0,0 +1,24 @@
+if componentSet.has('circles')
+  solid-widget(name='hubl-menu-fix-url-circle')
+    template
+      solid-link.segment.full(data-src="${value}" next=getRoute('circles', true))
+        solid-display.segment.full.text-color-white.heading-active.bg-color-heading.hover.active(
+          data-src='${value}'
+          fields='segment(status, circle(name, jabberID), badge)'
+          class-segment="segment full padding-top-xxsmall padding-bottom-xxsmall padding-right-small padding-left-medium"
+
+          class-status='segment text-top sub-menu-icon'
+
+          class-circle='segment three-quarter sub-menu-name'
+
+          class-name='ellipsis-content'
+
+          class-badge='segment badge'
+
+          value-badge='${value}'
+          widget-status='hubl-menu-publicprivate'
+          widget-badge='hubl-counter'
+          widget-jabberID='hubl-menu-jabberid'
+          widget-name='solid-display-div'
+          order-asc="name"
+        )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-menu-fix-url-contact.pug b/src/views/partials/widgets/hubl-menu-fix-url-contact.pug
new file mode 100644
index 00000000..8c1ca7f7
--- /dev/null
+++ b/src/views/partials/widgets/hubl-menu-fix-url-contact.pug
@@ -0,0 +1,18 @@
+if componentSet.has('chat')
+  solid-widget(name='hubl-menu-fix-url-contact')
+    template
+      solid-link.segment.full(data-src="${value}" next=getRoute('chat', true))
+        solid-display.segment.full.text-color-white.heading-active.bg-color-heading.hover.active(
+          data-src='${value}'
+          fields='segment(message(name, chatProfile.jabberID), badge)'
+          
+          class-segment="segment full padding-top-xxsmall padding-bottom-xxsmall padding-right-small padding-left-medium"
+          class-message='segment three-quarter sub-menu-name'
+          class-badge='segment badge'
+
+          value-badge='${value}'
+          widget-badge='hubl-counter'
+          widget-chatProfile.jabberID='hubl-menu-jabberid'
+          widget-name='solid-display-div'
+          order-asc='username'
+        )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-menu-fix-url-project.pug b/src/views/partials/widgets/hubl-menu-fix-url-project.pug
new file mode 100644
index 00000000..2766fb4a
--- /dev/null
+++ b/src/views/partials/widgets/hubl-menu-fix-url-project.pug
@@ -0,0 +1,25 @@
+if componentSet.has('projects')
+  solid-widget(name='hubl-menu-fix-url-project')
+    template
+      solid-link.segment.full(data-src="${value}" next=getRoute('projects', true))
+        solid-display.segment.full.text-color-white.heading-active.bg-color-heading.hover.active(
+          data-src='${value}'
+          fields='segment(status, project(customer.name, name, jabberID), badge)'
+          class-segment="segment full padding-top-xxsmall padding-bottom-xxsmall padding-right-small padding-left-medium"
+
+          class-status='segment text-top sub-menu-icon'
+
+          class-project='segment three-quarter sub-menu-name'
+
+          class-customer.name='ellipsis-content'
+          class-name='ellipsis-content'
+
+          class-badge='segment badge text-top'
+
+          value-badge='${value}'
+          widget-status='hubl-menu-publicprivate'
+          widget-jabberID='hubl-menu-jabberid'
+          widget-badge='hubl-counter'
+          widget-name='solid-display-div'
+          order-asc="customer.name"
+        )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-menu-jabberid.pug b/src/views/partials/widgets/hubl-menu-jabberid.pug
new file mode 100644
index 00000000..3608d8d5
--- /dev/null
+++ b/src/views/partials/widgets/hubl-menu-jabberid.pug
@@ -0,0 +1,6 @@
+if componentSet.has('chat') || componentSet.has('circles') || componentSet.has('projects')
+  solid-widget(name='hubl-menu-jabberid')
+    template
+      div.hidden(
+        data-jabberID="${value}"
+      )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-menu-publicprivate.pug b/src/views/partials/widgets/hubl-menu-publicprivate.pug
new file mode 100644
index 00000000..986cbdc0
--- /dev/null
+++ b/src/views/partials/widgets/hubl-menu-publicprivate.pug
@@ -0,0 +1,6 @@
+if componentSet.has('circles') || componentSet.has('projects')
+  solid-widget(name='hubl-menu-publicprivate')
+    template
+      div(
+        class="${value == 'Public' ? 'text-simple-line-icons text-large': 'text-simple-line-icons text-xsmall'}"
+      ) ${value == 'Public' ? '#' : ''}
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-project-admins.pug b/src/views/partials/widgets/hubl-project-admins.pug
new file mode 100644
index 00000000..54ea159a
--- /dev/null
+++ b/src/views/partials/widgets/hubl-project-admins.pug
@@ -0,0 +1,9 @@
+if componentSet.has('admin') && componentSet.has('projects')
+  solid-widget(name='hubl-project-admins')
+    template
+      solid-display(
+        data-src='${value}'
+        fields='user'
+        filtered-by='hubl_project_is_admin'
+        widget-user='hubl-project-captain'
+      )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-project-captain.pug b/src/views/partials/widgets/hubl-project-captain.pug
new file mode 100644
index 00000000..08831885
--- /dev/null
+++ b/src/views/partials/widgets/hubl-project-captain.pug
@@ -0,0 +1,19 @@
+if componentSet.has('admin') && componentSet.has('projects')
+  solid-widget(name='hubl-project-captain')
+    template
+      solid-display.segment.margin-top-xxsmall.margin-bottom-xxsmall.labelled-avatar.two-lines.block(
+        data-src='${await value}'
+        fields='segment1(account.picture), segment2(line1(name), line2(at, username))'
+
+        class-segment1='segment'
+        class-account.picture='avatar'
+
+        class-segment2='segment three-quarter margin-left-xsmall'
+        class-line1='segment block'
+        class-name='text-small text-semibold text-color-heading text-sub'
+        class-line2='segment block text-xsmall'
+
+        widget-account.picture='hubl-user-avatar'
+
+        value-at='@'
+      )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-project-edit-admin.pug b/src/views/partials/widgets/hubl-project-edit-admin.pug
new file mode 100644
index 00000000..7ddc2dcf
--- /dev/null
+++ b/src/views/partials/widgets/hubl-project-edit-admin.pug
@@ -0,0 +1,3 @@
+if componentSet.has('projects')
+  solid-widget(name='hubl-project-edit-admin')
+    template ${value == "true" ? "Administrateur" : ""}
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-project-edit-members-delete.pug b/src/views/partials/widgets/hubl-project-edit-members-delete.pug
new file mode 100644
index 00000000..f5db6a69
--- /dev/null
+++ b/src/views/partials/widgets/hubl-project-edit-members-delete.pug
@@ -0,0 +1,10 @@
+if componentSet.has('projects')
+  solid-widget(name="hubl-project-edit-members-delete")
+    template
+      solid-ac-checker(permission="acl:Delete", data-src="${src}")
+        solid-delete(
+          class='segment text-xsmall children-link-text-bold children-link-text-uppercase children-link-button children-link-color-secondary bordered'
+          data-src="${src}"
+          data-label=''
+          data-trans='data-label=project.edit.buttonDelete'
+        )
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-project-team-contact.pug b/src/views/partials/widgets/hubl-project-team-contact.pug
new file mode 100644
index 00000000..61791142
--- /dev/null
+++ b/src/views/partials/widgets/hubl-project-team-contact.pug
@@ -0,0 +1,4 @@
+if componentSet.has('projects')
+  solid-widget(name='hubl-project-team-contact')
+    template 
+      solid-link.icon.icon-secondary.hover.icon-speech.margin-left-xsmall.margin-right-medium(data-src='\${value}', next=getRoute('chat', true))
\ No newline at end of file
diff --git a/src/views/partials/widgets/hubl-username-field.pug b/src/views/partials/widgets/hubl-username-field.pug
new file mode 100644
index 00000000..9fa0255c
--- /dev/null
+++ b/src/views/partials/widgets/hubl-username-field.pug
@@ -0,0 +1,5 @@
+if componentSet.has('admin') && componentSet.has('chat')
+  solid-widget(name='hubl-username-field')
+    template
+      label ${label}
+      input(type="text" title='' pattern="[a-zA-Z0-9]+" label="${label}" data-trans='title=user.create.labelUsernameTitle' name="username" required value="\${value}" data-holder)
\ No newline at end of file
-- 
GitLab