diff --git a/app/controllers/admin/education/program/role/people_controller.rb b/app/controllers/admin/education/program/role/people_controller.rb
index 6202bf3e80f4bf070433fb13bcb5163d4688596b..bf9002f61b718b77f33eaf9f5d43a5b370e26624 100644
--- a/app/controllers/admin/education/program/role/people_controller.rb
+++ b/app/controllers/admin/education/program/role/people_controller.rb
@@ -2,7 +2,9 @@ class Admin::Education::Program::Role::PeopleController < Admin::Education::Prog
   load_and_authorize_resource :role, class: Education::Program::Role, through: :program
   load_and_authorize_resource class: Education::Program::Role::Person, through: :role
 
-  include Admin::Reorderable 
+  before_action :get_available_people, except: :destroy
+
+  include Admin::Reorderable
 
   def new
     breadcrumb
@@ -24,6 +26,11 @@ class Admin::Education::Program::Role::PeopleController < Admin::Education::Prog
 
   protected
 
+  def get_available_people
+    used_person_ids = @role.people.where.not(id: @person.id).pluck(:person_id)
+    @available_people = current_university.people.where.not(id: used_person_ids).accessible_by(current_ability).ordered
+  end
+
   def breadcrumb
     super
     add_breadcrumb Education::Program::Role.model_name.human(count: 2)
diff --git a/app/controllers/admin/education/program/teachers_controller.rb b/app/controllers/admin/education/program/teachers_controller.rb
index ab3cb3f3eed5e2f491c51c673fd6cfd39c902940..52d7085d53b763e28311db97fbfe040db9a152cc 100644
--- a/app/controllers/admin/education/program/teachers_controller.rb
+++ b/app/controllers/admin/education/program/teachers_controller.rb
@@ -1,6 +1,8 @@
 class Admin::Education::Program::TeachersController < Admin::Education::Program::ApplicationController
   load_and_authorize_resource class: Education::Program::Teacher, through: :program
 
+  before_action :get_teachers, except: :destroy
+
   def new
     breadcrumb
   end
@@ -36,6 +38,11 @@ class Admin::Education::Program::TeachersController < Admin::Education::Program:
 
   protected
 
+  def get_teachers
+    used_teacher_ids = @program.teachers.where.not(id: @teacher.id).pluck(:person_id)
+    @teachers = current_university.people.teachers.where.not(id: used_teacher_ids).accessible_by(current_ability).ordered
+  end
+
   def breadcrumb
     super
     add_breadcrumb Education::Program::Teacher.model_name.human(count: 2)
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 63cb0f45470d8967614809321d9e345e12ea2a3d..5829446e32b2bd938a56afeac09db7374d86f5c3 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -29,6 +29,18 @@ class Ability
     can :read, User, university_id: @user.university_id
   end
 
+  def teacher
+    can :manage, University::Person, user_id: @user.id
+    can :read, Education::Program, university_id: @user.university_id
+    can :manage, Education::Program::Teacher, person_id: @user.person&.id
+    can :read, Education::Program::Role, university_id: @user.university_id
+    can :manage, Education::Program::Role::Person, person_id: @user.person&.id
+  end
+
+  def program_manager
+
+  end
+
   def admin
     can :read, Administration::Qualiopi::Criterion
     can :read, Administration::Qualiopi::Indicator
@@ -44,6 +56,8 @@ class Ability
     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, Education::Program::Role, university_id: @user.university_id
+    can :manage, Education::Program::Role::Person, university_id: @user.university_id
     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
diff --git a/app/models/user/with_roles.rb b/app/models/user/with_roles.rb
index 2853b84432441b8b2156e8447d0cf11dc03df2c6..84fb51a7d8304eb19685f7a6aebcbe78ab525e5c 100644
--- a/app/models/user/with_roles.rb
+++ b/app/models/user/with_roles.rb
@@ -4,7 +4,7 @@ module User::WithRoles
   included do
     attr_accessor :modified_by
 
-    enum role: { visitor: 0, admin: 20, server_admin: 30 }
+    enum role: { visitor: 0, teacher: 10, program_manager: 12, admin: 20, server_admin: 30 }
 
     scope :for_role, -> (role) { where(role: role) }
 
diff --git a/app/views/admin/education/program/role/people/new.html.erb b/app/views/admin/education/program/role/people/new.html.erb
index 402d1727d98c843d5b6807ec06bdd7d73a1f607b..d2a7ac69768b51844a88ea8619cf00ff449dd98e 100644
--- a/app/views/admin/education/program/role/people/new.html.erb
+++ b/app/views/admin/education/program/role/people/new.html.erb
@@ -8,8 +8,7 @@
           <h5 class="card-title mb-0"><%= t('admin.infos') %></h5>
         </div>
         <div class="card-body">
-          <% used_person_ids = @role.people.where.not(id: @person.id).pluck(:person_id) %>
-          <%= f.association :person, collection: current_university.people.where.not(id: used_person_ids).ordered %>
+          <%= f.association :person, collection: @available_people %>
         </div>
       </div>
     </div>
diff --git a/app/views/admin/education/program/roles/_list.html.erb b/app/views/admin/education/program/roles/_list.html.erb
index 0a152d39a6e3204e32b1a026dbf9830b714074aa..c4465b6573d625c4e5fee70a81ee2240a26b8f47 100644
--- a/app/views/admin/education/program/roles/_list.html.erb
+++ b/app/views/admin/education/program/roles/_list.html.erb
@@ -20,12 +20,12 @@
             <div class="btn-group" role="group">
               <%= link_to t('edit'),
                           edit_admin_education_program_role_path(role, { program_id: @program.id }),
-                          class: button_classes %>
+                          class: button_classes if can?(:edit, role) %>
               <%= link_to t('delete'),
                           admin_education_program_role_path(role, { program_id: @program.id }),
                           method: :delete,
                           data: { confirm: t('please_confirm') },
-                          class: button_classes_danger %>
+                          class: button_classes_danger if can?(:destroy, role) %>
             </div>
           </td>
         </tr>
diff --git a/app/views/admin/education/program/roles/show.html.erb b/app/views/admin/education/program/roles/show.html.erb
index 051d0859a6b646ee517b4ced7cfab8b9568fae08..09d1438bae5ebeb50909afb7c2d79e657036ada7 100644
--- a/app/views/admin/education/program/roles/show.html.erb
+++ b/app/views/admin/education/program/roles/show.html.erb
@@ -18,8 +18,10 @@
         <h2 class="card-title mb-0 h5"><%= Education::Program::Role.human_attribute_name('people') %></h2>
       </div>
       <div class="card-body">
-        <p><%= link_to t('create'), new_admin_education_program_role_person_path(role_id: @role.id), class: 'btn btn-primary' %></p>
         <%= render 'admin/education/program/role/people/list', people: @role.people.includes(:person).ordered %>
+        <% if can? :create, Education::Program::Role::Person %>
+          <p><%= link_to t('create'), new_admin_education_program_role_person_path(role_id: @role.id), class: 'btn btn-primary' %></p>
+        <% end %>
       </div>
     </div>
   </div>
diff --git a/app/views/admin/education/program/teachers/_form.html.erb b/app/views/admin/education/program/teachers/_form.html.erb
index 503032b23e866226f69cd4455e81ada146777148..31950531cded62732c883007d24af5dd0f8a7685 100644
--- a/app/views/admin/education/program/teachers/_form.html.erb
+++ b/app/views/admin/education/program/teachers/_form.html.erb
@@ -6,8 +6,7 @@
     <div class="card-body">
       <div class="row">
         <div class="col-md-6">
-          <% used_teacher_ids = @program.teachers.where.not(id: teacher.id).pluck(:person_id) %>
-          <%= f.association :person, collection: current_university.people.teachers.where.not(id: used_teacher_ids).ordered %>
+          <%= f.association :person, collection: @teachers %>
         </div>
         <div class="col-md-6">
           <%= f.input :description, as: :string %>
diff --git a/app/views/admin/education/program/teachers/_list.html.erb b/app/views/admin/education/program/teachers/_list.html.erb
index 5fb075887d0d93c3106f82133c7e966076b70fc1..cc7d9c17b4e0f0bd685a4fc0525771250f30610f 100644
--- a/app/views/admin/education/program/teachers/_list.html.erb
+++ b/app/views/admin/education/program/teachers/_list.html.erb
@@ -20,12 +20,12 @@
             <div class="btn-group" role="group">
               <%= link_to t('edit'),
                           edit_admin_education_program_teacher_path(teacher, { program_id: @program.id }),
-                          class: button_classes %>
+                          class: button_classes if can? :update, teacher.person %>
               <%= link_to t('delete'),
                           admin_education_program_teacher_path(teacher, { program_id: @program.id }),
                           method: :delete,
                           data: { confirm: t('please_confirm') },
-                          class: button_classes_danger %>
+                          class: button_classes_danger if can? :update, teacher.person %>
             </div>
           </td>
         </tr>
diff --git a/app/views/admin/education/programs/_list.html.erb b/app/views/admin/education/programs/_list.html.erb
index 1694c7d619ccb23bfe2a7a014ca9389df7287e02..0aa706121699f7dc97becf241a58eebc82096b56 100644
--- a/app/views/admin/education/programs/_list.html.erb
+++ b/app/views/admin/education/programs/_list.html.erb
@@ -15,12 +15,12 @@
           <div class="btn-group" role="group">
             <%= link_to t('edit'),
                         edit_admin_education_program_path(program),
-                        class: button_classes %>
+                        class: button_classes if can?(:update, program) %>
             <%= link_to t('delete'),
                         admin_education_program_path(program),
                         method: :delete,
                         data: { confirm: program.children.any? ? t('please_confirm_with_children') : t('please_confirm') },
-                        class: button_classes_danger %>
+                        class: button_classes_danger if can?(:destroy, program) %>
           </div>
         </td>
       </tr>
diff --git a/app/views/admin/education/programs/show.html.erb b/app/views/admin/education/programs/show.html.erb
index 1cd1e48366ec359e093e45b81427d2f86153ef34..4ebd03b90caa3aa1586b5ea5b0ac6d798ec67e58 100644
--- a/app/views/admin/education/programs/show.html.erb
+++ b/app/views/admin/education/programs/show.html.erb
@@ -123,7 +123,7 @@
       <div class="col-md-6">
         <h3 class="h5"><%= Education::Program.human_attribute_name('roles') %></h3>
         <%= render 'admin/education/program/roles/list', roles: @program.roles.ordered %>
-        <%= link_to t('create'), new_admin_education_program_role_path(program_id: @program.id), class: button_classes %>
+        <%= link_to t('create'), new_admin_education_program_role_path(program_id: @program.id), class: button_classes if can?(:create, Education::Program::Role) %>
       </div>
       <div class="col-md-6">
         <h3 class="h5"><%= Education::Program.human_attribute_name('teachers') %></h3>
diff --git a/app/views/admin/university/people/_form.html.erb b/app/views/admin/university/people/_form.html.erb
index 498d3415064421a7f3e8db884bcdc71e9390019d..9c0ae01d0ed5dfe3143d2baa7f05eb20e637dfcd 100644
--- a/app/views/admin/university/people/_form.html.erb
+++ b/app/views/admin/university/people/_form.html.erb
@@ -57,7 +57,7 @@
             class: 'js-slug-input',
             data: { source: '#university_person_first_name, #university_person_last_name' }
           } %>
-          <%= f.association :user, collection: current_university.users.ordered %>
+          <%= f.association :user, collection: current_university.users.ordered if can?(:manage, User) %>
         </div>
       </div>
       <div class="card flex-fill w-100">
diff --git a/app/views/admin/university/people/_main_infos.html.erb b/app/views/admin/university/people/_main_infos.html.erb
index bf82980bdcb3f4331af572bb2d1b47a0f2e24071..ac859c5eece68165f4c5c54a727d0b6b63fc7d20 100644
--- a/app/views/admin/university/people/_main_infos.html.erb
+++ b/app/views/admin/university/people/_main_infos.html.erb
@@ -43,7 +43,7 @@
           <% if person.best_picture_inherits_from_user? %>
             <p>
               <span class="small text-muted">
-                <%= t 'admin.inheritance.sentence_html', link: link_to(person.user, [:admin, person.user]) %>
+                <%= t 'admin.inheritance.sentence_html', link: link_to_if(can?(:read, person.user), person.user, [:admin, person.user]) %>
               </span>
             </p>
           <% end %>
diff --git a/app/views/admin/users/_form.html.erb b/app/views/admin/users/_form.html.erb
index 317c715232946f7596a3ff9e27cb21d60377dfb6..15f7c0d6dcbab185cd9c2497597f2180e4fe6112 100644
--- a/app/views/admin/users/_form.html.erb
+++ b/app/views/admin/users/_form.html.erb
@@ -29,7 +29,7 @@
                       },
                       input_html: { autocomplete: "new-password" } %>
           <%= f.input :mobile_phone %>
-          <%= f.input :role, include_blank: false, collection: current_user.managed_roles %>
+          <%= f.input :role, include_blank: false, collection: current_user.managed_roles, label_method: lambda { |k| t("activerecord.attributes.user.roles.#{k[1]}")} %>
         </div>
       </div>
     </div>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index aea1857ea0e32fc83b615261681bef125abddd19..c692b52c30b57506cce0168e7d49cf8a83b99efe 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -13,6 +13,12 @@ en:
         mobile_phone: Mobile phone
         picture: Profile picture
         role: Role
+        roles:
+          admin: Administrator
+          program_manager: Program manager
+          server_admin: Server admin
+          teacher: Teacher
+          visitor: Visitor
     errors:
       models:
         user:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index ebbd8d67b579b7226fb5c6e3c0a70da68da989cd..768f6224d7e927bcbf8074ed9592f72993c6cc91 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -13,6 +13,12 @@ fr:
         mobile_phone: Téléphone portable
         picture: Photo de profil
         role: Rôle
+        roles:
+          admin: Administrateur
+          program_manager: Responsable de formation
+          server_admin: Administrateur du serveur
+          teacher: Enseignant·e
+          visitor: Visiteur
     errors:
       models:
         user: