diff --git a/app/controllers/admin/universities_controller.rb b/app/controllers/admin/universities_controller.rb
deleted file mode 100644
index 8347979a3bc4f4c16da400e578a91629bb4910c3..0000000000000000000000000000000000000000
--- a/app/controllers/admin/universities_controller.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-class Admin::UniversitiesController < Admin::ApplicationController
-  load_and_authorize_resource
-
-  def index
-    breadcrumb
-  end
-
-  def show
-    breadcrumb
-  end
-
-  def new
-    breadcrumb
-  end
-
-  def edit
-    breadcrumb
-    add_breadcrumb 'Modifier'
-  end
-
-  def create
-    if @university.save
-      redirect_to [:admin, @university], notice: "University was successfully created."
-    else
-      breadcrumb
-      render :new, status: :unprocessable_entity
-    end
-  end
-
-  def update
-    if @university.update(university_params)
-      redirect_to [:admin, @university], notice: "University was successfully updated."
-    else
-      breadcrumb
-      render :edit, status: :unprocessable_entity
-    end
-  end
-
-  def destroy
-    @university.destroy
-    redirect_to admin_universities_url, notice: "University was successfully destroyed."
-  end
-
-  protected
-
-  def breadcrumb
-    super
-    add_breadcrumb University.model_name.human(count: 2), admin_universities_path
-    if @university
-      if @university.persisted?
-        add_breadcrumb @university, [:admin, @university]
-      else
-        add_breadcrumb 'Créer'
-      end
-    end
-  end
-
-  def university_params
-    params.require(:university).permit(:name, :address, :zipcode, :city, :country, :private, :identifier)
-  end
-end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 86d995b3395a45d48f26c2cd3299483a4503ea2f..d843a8c056d7de947824c5a5803a4b6d02bfa91b 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -20,19 +20,21 @@ class Admin::UsersController < Admin::ApplicationController
   end
 
   def create
-    breadcrumb
     if @user.save
       redirect_to [:admin, @user], notice: "User was successfully created."
     else
+      breadcrumb
       render :new, status: :unprocessable_entity
     end
   end
 
   def update
-    breadcrumb
+    @user.modified_by = current_user
     if @user.update(user_params)
       redirect_to [:admin, @user], notice: "User was successfully updated."
     else
+      breadcrumb
+      add_breadcrumb 'Modifier'
       render :edit, status: :unprocessable_entity
     end
   end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 27badced9dec040e51315291cc24f8dc1ea959dc..c21323d51354df8dd2e94efec70a7f8c8b9a9790 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,4 +1,5 @@
 class ApplicationController < ActionController::Base
+  include WithErrors
   include WithLocale
   include WithUniversity
 
diff --git a/app/controllers/server/application_controller.rb b/app/controllers/server/application_controller.rb
index f285d2347ebd7d4a4ec9b31449800b5276e07f80..01fcffda36de6ae6ae8f6277f0843b8603c06762 100644
--- a/app/controllers/server/application_controller.rb
+++ b/app/controllers/server/application_controller.rb
@@ -1,11 +1,15 @@
 class Server::ApplicationController < ApplicationController
   layout 'server/layouts/application'
 
-  before_action :authenticate_user!
+  before_action :authenticate_user!, :ensure_user_if_superadmin
 
   protected
 
   def breadcrumb
     add_breadcrumb 'Tableau de bord', :server_root_path
   end
+
+  def ensure_user_if_superadmin
+    raise CanCan::AccessDenied unless current_user.superadmin?
+  end
 end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 53665c42ec3c488e91711663f132e038f4f59f51..bdbba796ba00728fa0faa83cdb38ab074d86dfbb 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -4,6 +4,48 @@ class Ability
   include CanCan::Ability
 
   def initialize(user)
+    @user = user ||= User.new # guest user (not logged in)
+    send @user.role.to_sym
+  end
+
+  protected
+
+  def visitor
+    can :read, Administration::Qualiopi::Criterion
+    can :read, Administration::Qualiopi::Indicator
+    can :read, Communication::Website, university_id: @user.university_id
+    can :read, Communication::Website::Page, university_id: @user.university_id
+    can :read, Communication::Website::Post, university_id: @user.university_id
+    can :read, Communication::Website::Imported::Website, university_id: @user.university_id
+    can :read, Communication::Website::Imported::Page, university_id: @user.university_id
+    can :read, Communication::Website::Imported::Post, university_id: @user.university_id
+    can :read, Education::Program, university_id: @user.university_id
+    can :read, Research::Researcher
+    can :read, Research::Journal, university_id: @user.university_id
+    can :read, Research::Journal::Article, university_id: @user.university_id
+    can :read, Research::Journal::Volume, university_id: @user.university_id
+    can :read, User, university_id: @user.university_id
+  end
+
+  def admin
+    can :read, Administration::Qualiopi::Criterion
+    can :read, Administration::Qualiopi::Indicator
+    can :manage, Communication::Website, university_id: @user.university_id
+    can :manage, Communication::Website::Page, university_id: @user.university_id
+    can :manage, Communication::Website::Post, university_id: @user.university_id
+    can :manage, Communication::Website::Imported::Website, university_id: @user.university_id
+    can :manage, Communication::Website::Imported::Page, university_id: @user.university_id
+    can :manage, Communication::Website::Imported::Post, university_id: @user.university_id
+    can :manage, Education::Program, university_id: @user.university_id
+    can :manage, Research::Researcher
+    can :manage, Research::Journal, university_id: @user.university_id
+    can :manage, Research::Journal::Article, university_id: @user.university_id
+    can :manage, Research::Journal::Volume, university_id: @user.university_id
+    can :read, User, university_id: @user.university_id
+    can :manage, User, university_id: @user.university_id, role: @user.managed_roles
+  end
+
+  def superadmin
     can :manage, :all
   end
 end
diff --git a/app/models/user/with_roles.rb b/app/models/user/with_roles.rb
index 992305e06755434f6f13368df7c811fc3ee2534c..635cac94847f5eef5a3f4e9e8ac0a428b8e6f049 100644
--- a/app/models/user/with_roles.rb
+++ b/app/models/user/with_roles.rb
@@ -10,7 +10,7 @@ module User::WithRoles
 
     before_validation :check_modifier_role
 
-    def roles_managed
+    def managed_roles
       User.roles.map do |role_name, role_id|
         next if role_id > User.roles[role]
         role_name
@@ -20,7 +20,7 @@ module User::WithRoles
     protected
 
     def check_modifier_role
-      errors.add(:role, 'cannot be set to this role') if modified_by && !modified_by.roles_managed.include?(self.role)
+      errors.add(:role, 'cannot be set to this role') if modified_by && !modified_by.managed_roles.include?(self.role)
     end
 
   end
diff --git a/app/views/admin/universities/_form.html.erb b/app/views/admin/universities/_form.html.erb
deleted file mode 100644
index 67ed4f997db3a685486a98e953dc83ef9cf0f7bc..0000000000000000000000000000000000000000
--- a/app/views/admin/universities/_form.html.erb
+++ /dev/null
@@ -1,24 +0,0 @@
-<%= simple_form_for [:admin, university] do |f| %>
-  <div class="row">
-    <div class="col-md-4">
-      <%= f.input :name %>
-      <%= f.input :identifier %>
-      <%= f.input :private %>
-    </div>
-    <div class="col-md-8">
-      <%= f.input :address %>
-      <div class="row">
-        <div class="col-md-4">
-          <%= f.input :zipcode %>
-        </div>
-        <div class="col-md-8">
-          <%= f.input :city %>
-        </div>
-      </div>
-      <%= f.input :country %>
-    </div>
-  </div>
-  <% content_for :buttons do %>
-    <%= submit f %>
-  <% end %>
-<% end %>
diff --git a/app/views/admin/universities/edit.html.erb b/app/views/admin/universities/edit.html.erb
deleted file mode 100644
index ea1755f50fc993923d5b2492d4f12c8ba16b9532..0000000000000000000000000000000000000000
--- a/app/views/admin/universities/edit.html.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<% content_for :title, @university %>
-
-<%= render 'form', university: @university %>
diff --git a/app/views/admin/universities/index.html.erb b/app/views/admin/universities/index.html.erb
deleted file mode 100644
index da186a894aa0e61c7d86c5a5f8d61ab886813448..0000000000000000000000000000000000000000
--- a/app/views/admin/universities/index.html.erb
+++ /dev/null
@@ -1,29 +0,0 @@
-<% content_for :title, University.model_name.human(count: 2) %>
-
-<table class="table">
-  <thead>
-    <tr>
-      <th><%= University.human_attribute_name('name') %></th>
-      <th><%= University.human_attribute_name('url') %></th>
-      <th><%= University.human_attribute_name('public_or_private') %></th>
-      <th></th>
-    </tr>
-  </thead>
-  <tbody>
-    <% @universities.each do |university| %>
-      <tr>
-        <td><%= link_to university, [:admin, university] %></td>
-        <td><%= link_to university.url, university.url, target: :_blank %></td>
-        <td><%= university.private ? University.human_attribute_name('private') : University.human_attribute_name('public') %></td>
-        <td class="text-end">
-          <%= edit_link university %>
-          <%= destroy_link university %>
-        </td>
-      </tr>
-    <% end %>
-  </tbody>
-</table>
-
-<% content_for :buttons do %>
-  <%= create_link University %>
-<% end %>
diff --git a/app/views/admin/universities/new.html.erb b/app/views/admin/universities/new.html.erb
deleted file mode 100644
index 765486836c3896a53498516651ceda1a0195143c..0000000000000000000000000000000000000000
--- a/app/views/admin/universities/new.html.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<% content_for :title, University.model_name.human %>
-
-<%= render 'form', university: @university %>
diff --git a/app/views/admin/universities/show.html.erb b/app/views/admin/universities/show.html.erb
deleted file mode 100644
index 2cc54885e6c8ff3459b8147a29519c19cf9e1ceb..0000000000000000000000000000000000000000
--- a/app/views/admin/universities/show.html.erb
+++ /dev/null
@@ -1,34 +0,0 @@
-<% content_for :title, @university %>
-
-<p>
-  <%= link_to @university.url, @university.url, target: :_blank %>
-</p>
-
-<p>
-  <strong>Address:</strong>
-  <%= @university.address %>
-</p>
-
-<p>
-  <strong>Zipcode:</strong>
-  <%= @university.zipcode %>
-</p>
-
-<p>
-  <strong>City:</strong>
-  <%= @university.city %>
-</p>
-
-<p>
-  <strong>Country:</strong>
-  <%= @university.country %>
-</p>
-
-<p>
-  <strong>Private:</strong>
-  <%= @university.private %>
-</p>
-
-<% content_for :buttons do %>
-  <%= edit_link @university %>
-<% end %>
diff --git a/app/views/admin/users/_form.html.erb b/app/views/admin/users/_form.html.erb
index a75f56c807694a7422338334717568a49556ae69..a39d469f0e75c5232c0170eb7f1c40270540a3e5 100644
--- a/app/views/admin/users/_form.html.erb
+++ b/app/views/admin/users/_form.html.erb
@@ -2,7 +2,7 @@
   <div class="row">
     <div class="col-md-4">
       <%= f.input :email %>
-      <%#= f.input :role %>
+      <%= f.input :role, include_blank: false, collection: current_user.managed_roles %>
     </div>
     <div class="col-md-4">
       <%= f.input :first_name %>
diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb
index d46e205911946091a78f617db102c954fc5e13dd..a55d80578f9c6e73c2b4dde5e200e6b5ec1e6d34 100644
--- a/app/views/admin/users/index.html.erb
+++ b/app/views/admin/users/index.html.erb
@@ -6,6 +6,7 @@
       <th><%= User.human_attribute_name('email') %></th>
       <th><%= User.human_attribute_name('first_name') %></th>
       <th><%= User.human_attribute_name('last_name') %></th>
+      <th><%= User.human_attribute_name('role') %></th>
       <th><%= User.human_attribute_name('language') %></th>
       <th></th>
     </tr>
@@ -16,6 +17,7 @@
         <td><%= link_to user.email, [:admin, user] %></td>
         <td><%= user.first_name %></td>
         <td><%= user.last_name %></td>
+        <td><%= user.role.humanize %></td>
         <td><%= user.language %></td>
         <td class="text-end">
           <%= edit_link user %>
diff --git a/config/admin_navigation.rb b/config/admin_navigation.rb
index 96fb9864f507070cd6ae2c7eef29cf76519b8901..eb04f04d58421c52c8412310218f73209a0b5ef1 100644
--- a/config/admin_navigation.rb
+++ b/config/admin_navigation.rb
@@ -6,29 +6,37 @@ SimpleNavigation::Configuration.run do |navigation|
   navigation.items do |primary|
     primary.item :dashboard, t('dashboard'), admin_root_path, { icon: 'tachometer-alt', highlights_on: /admin$/ }
 
-    primary.item :teaching, Education.model_name.human, nil, { kind: :header }
-    primary.item :teaching, 'Enseignants', nil, { icon: 'user-graduate' }
-    primary.item :teaching, 'Ecoles', nil, { icon: 'university' }
-    primary.item :education, Education::Program.model_name.human(count: 2), admin_education_programs_path, { icon: 'graduation-cap' }
-    primary.item :teaching, 'Ressources éducatives', nil, { icon: 'laptop' }
-    primary.item :teaching, 'Feedbacks', nil, { icon: 'comments' }
+    if can?(:read, Education::Program)
+      primary.item :education, Education.model_name.human, nil, { kind: :header }
+      primary.item :education, 'Enseignants', nil, { icon: 'user-graduate' }
+      primary.item :education, 'Ecoles', nil, { icon: 'university' }
+      primary.item :education_programs, Education::Program.model_name.human(count: 2), admin_education_programs_path, { icon: 'graduation-cap' } if can?(:read, Education::Program)
+      primary.item :education, 'Ressources éducatives', nil, { icon: 'laptop' }
+      primary.item :education, 'Feedbacks', nil, { icon: 'comments' }
+    end
 
-    primary.item :teaching, Research.model_name.human, nil, { kind: :header }
-    primary.item :teaching, Research::Researcher.model_name.human(count: 2), admin_research_researchers_path(journal_id: nil), { icon: 'microscope' }
-    primary.item :teaching, 'Laboratoires', nil, { icon: 'flask' }
-    primary.item :teaching, 'Veille', nil, { icon: 'eye' }
-    primary.item :journals, Research::Journal.model_name.human(count: 2), admin_research_journals_path, { icon: 'newspaper' }
+    if can?(:read, Research::Researcher) || can?(:read, Research::Journal)
+      primary.item :research, Research.model_name.human, nil, { kind: :header }
+      primary.item :research_researchers, Research::Researcher.model_name.human(count: 2), admin_research_researchers_path(journal_id: nil), { icon: 'microscope' } if can?(:read, Research::Researcher)
+      primary.item :research, 'Laboratoires', nil, { icon: 'flask' }
+      primary.item :research, 'Veille', nil, { icon: 'eye' }
+      primary.item :research_journals, Research::Journal.model_name.human(count: 2), admin_research_journals_path, { icon: 'newspaper' } if can?(:read, Research::Journal)
+    end
 
-    primary.item :teaching, 'Communication', nil, { kind: :header }
-    primary.item :websites, 'Sites Web', admin_communication_websites_path, { icon: 'sitemap' }
-    primary.item :teaching, 'Lettres d\'information', nil, { icon: 'envelope' }
-    primary.item :teaching, 'Alumni', nil, { icon: 'users' }
+    if can?(:read, Communication::Website)
+      primary.item :communication, 'Communication', nil, { kind: :header }
+      primary.item :communication_websites, 'Sites Web', admin_communication_websites_path, { icon: 'sitemap' } if can?(:read, Communication::Website)
+      primary.item :communication, 'Lettres d\'information', nil, { icon: 'envelope' }
+      primary.item :communication, 'Alumni', nil, { icon: 'users' }
+    end
 
-    primary.item :teaching, 'Administration', nil, { kind: :header }
-    primary.item :users, User.model_name.human(count: 2), admin_users_path, { icon: 'user' }
-    primary.item :settings, 'Campus', nil, { icon: 'map-marker-alt' }
-    primary.item :settings, 'Admissions', nil, { icon: 'door-open' }
-    primary.item :settings, 'Statistiques', nil, { icon: 'cog' }
-    primary.item :settings, 'Qualité', admin_administration_qualiopi_criterions_path, { icon: 'tasks' }
+    if can?(:read, User) || can?(:read, Administration::Qualiopi::Criterion)
+      primary.item :administration, 'Administration', nil, { kind: :header }
+      primary.item :administration_users, User.model_name.human(count: 2), admin_users_path, { icon: 'user' } if can?(:read, User)
+      primary.item :administration, 'Campus', nil, { icon: 'map-marker-alt' }
+      primary.item :administration, 'Admissions', nil, { icon: 'door-open' }
+      primary.item :administration, 'Statistiques', nil, { icon: 'cog' }
+      primary.item :administration_qualiopi, 'Qualité', admin_administration_qualiopi_criterions_path, { icon: 'tasks' } if can?(:read, Administration::Qualiopi::Criterion)
+    end
   end
 end
diff --git a/config/routes.rb b/config/routes.rb
index a1e9a7a4dc06563928746fd45775b59b61e0553b..c1aae1fe06e87bd9b0312a5b4fb4316369055d8f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -7,18 +7,14 @@ Rails.application.routes.draw do
     unlocks: 'users/unlocks'
   }
 
-  resources :languages
-
   namespace :admin do
     resources :users do
-      member do
-        patch 'unlock' => 'users#unlock'
-      end
+      patch 'unlock' => 'users#unlock', on: :member
     end
-    draw 'education'
-    draw 'research'
-    draw 'communication'
-    draw 'administration'
+    draw 'admin/administration'
+    draw 'admin/communication'
+    draw 'admin/education'
+    draw 'admin/research'
     root to: 'dashboard#index'
   end
 
diff --git a/config/routes/administration.rb b/config/routes/admin/administration.rb
similarity index 100%
rename from config/routes/administration.rb
rename to config/routes/admin/administration.rb
diff --git a/config/routes/communication.rb b/config/routes/admin/communication.rb
similarity index 100%
rename from config/routes/communication.rb
rename to config/routes/admin/communication.rb
diff --git a/config/routes/education.rb b/config/routes/admin/education.rb
similarity index 100%
rename from config/routes/education.rb
rename to config/routes/admin/education.rb
diff --git a/config/routes/research.rb b/config/routes/admin/research.rb
similarity index 100%
rename from config/routes/research.rb
rename to config/routes/admin/research.rb
diff --git a/config/server_navigation.rb b/config/server_navigation.rb
index 72d21f8591daa4d497f9a952f829bb76a135ebbe..49e8a3f8f5f2fdab6db7442a73f33149d07d6643 100644
--- a/config/server_navigation.rb
+++ b/config/server_navigation.rb
@@ -5,7 +5,7 @@ SimpleNavigation::Configuration.run do |navigation|
   navigation.selected_class = 'active'
   navigation.items do |primary|
     primary.item :dashboard, t('dashboard'), server_root_path, { icon: 'tachometer-alt', highlights_on: %r{adminserver$} }
-    primary.item :universities, University.model_name.human(count: 2), server_universities_path, { icon: 'university' }
-    primary.item :languages, Language.model_name.human(count: 2), server_languages_path, { icon: 'flag' }
+    primary.item :universities, University.model_name.human(count: 2), server_universities_path, { icon: 'university' } if can?(:read, University)
+    primary.item :languages, Language.model_name.human(count: 2), server_languages_path, { icon: 'flag' } if can?(:read, Language)
   end
 end