diff --git a/app/assets/javascripts/admin/plugins/notyf.js b/app/assets/javascripts/application/plugins/notyf.js
similarity index 100%
rename from app/assets/javascripts/admin/plugins/notyf.js
rename to app/assets/javascripts/application/plugins/notyf.js
diff --git a/app/assets/javascripts/extranet.js b/app/assets/javascripts/extranet.js
index 1bb3ee541721c56a5c7d12ec8380345569d8f078..3c9f58a03895bb50778a8ac9d5bc527d2eb3d50b 100644
--- a/app/assets/javascripts/extranet.js
+++ b/app/assets/javascripts/extranet.js
@@ -6,6 +6,7 @@
 //= require jquery_ujs
 //= require cropperjs/dist/cropper
 //= require jquery-cropper/dist/jquery-cropper
+//= require notyf/notyf.min
 //= require simple_form_password_with_hints
 //= require simple_form_bs5_file_input
 //= require summernote/summernote-bs5
diff --git a/app/assets/stylesheets/extranet.sass b/app/assets/stylesheets/extranet.sass
index d1db953282f08b93bc58d4fd6e0c8581be34292c..a2153a4bb4b9d4f6f49967545b779810f7b7f39b 100644
--- a/app/assets/stylesheets/extranet.sass
+++ b/app/assets/stylesheets/extranet.sass
@@ -11,6 +11,7 @@
 @import 'commons/summernote'
 @import 'commons/bootstrap-icons'
 @import 'leaflet'
+@import 'notyf/notyf.min'
 
 // Default
 @import 'extranet/layout/*'
diff --git a/app/controllers/admin/communication/extranets/assets_controller.rb b/app/controllers/admin/communication/extranets/assets_controller.rb
deleted file mode 100644
index 3ed6ccd7998740bc6ea14548051f23f448fc5343..0000000000000000000000000000000000000000
--- a/app/controllers/admin/communication/extranets/assets_controller.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class Admin::Communication::Extranets::AssetsController < Admin::Communication::Extranets::ApplicationController
-  def index
-    breadcrumb
-    add_breadcrumb Communication::Extranet.human_attribute_name(:feature_assets)
-  end
-end
\ No newline at end of file
diff --git a/app/controllers/admin/communication/extranets/contacts_controller.rb b/app/controllers/admin/communication/extranets/contacts_controller.rb
index 462bd1364d0efe324a543720bd45369558daf330..d74dbda0e861fa1935b9d89dced9a2aa059aa2e7 100644
--- a/app/controllers/admin/communication/extranets/contacts_controller.rb
+++ b/app/controllers/admin/communication/extranets/contacts_controller.rb
@@ -1,7 +1,7 @@
 class Admin::Communication::Extranets::ContactsController < Admin::Communication::Extranets::ApplicationController
   def index
-    @persons = current_university.people.ordered
-    @organizations = current_university.organizations.ordered
+    @persons = current_university.people.ordered.page params[:persons_page]
+    @organizations = current_university.organizations.ordered.page params[:organizations_page]
     breadcrumb
     add_breadcrumb Communication::Extranet.human_attribute_name(:feature_contacts)
   end
diff --git a/app/controllers/admin/communication/extranets/documents_controller.rb b/app/controllers/admin/communication/extranets/documents_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..124981dd684b81afdf566884f6881d8355930625
--- /dev/null
+++ b/app/controllers/admin/communication/extranets/documents_controller.rb
@@ -0,0 +1,64 @@
+class Admin::Communication::Extranets::DocumentsController < Admin::Communication::Extranets::ApplicationController
+  load_and_authorize_resource class: Communication::Extranet::Document, through: :extranet
+
+  def index
+    @documents = @documents.ordered.page params[:page]
+    breadcrumb
+  end
+
+  def show
+    breadcrumb
+  end
+
+  def new
+    breadcrumb
+  end
+
+  def edit
+    breadcrumb
+    add_breadcrumb t('edit')
+  end
+
+  def create
+    if @document.save
+      redirect_to admin_communication_extranet_document_path(@document), notice: t('admin.successfully_created_html', model: @document.to_s)
+    else
+      breadcrumb
+      render :new, status: :unprocessable_entity
+    end
+  end
+
+  def update
+    if @document.update(document_params)
+      redirect_to admin_communication_extranet_document_path(@document), notice: t('admin.successfully_updated_html', model: @document.to_s)
+    else
+      breadcrumb
+      add_breadcrumb t('edit')
+      render :edit, status: :unprocessable_entity
+    end
+  end
+
+  def destroy
+    @document.destroy
+    redirect_to admin_communication_extranet_documents_url, notice: t('admin.successfully_destroyed_html', model: @document.to_s)
+  end
+
+  protected
+
+  def breadcrumb
+    super
+    add_breadcrumb Communication::Extranet.human_attribute_name(:feature_library), admin_communication_extranet_library_path
+    breadcrumb_for @document
+  end
+
+  def document_params
+    params.require(:communication_extranet_document)
+    .permit(
+      :name, :published, :published_at, :slug,
+      :file, :file_delete
+    )
+    .merge(
+      university_id: current_university.id
+    )
+  end
+end
\ No newline at end of file
diff --git a/app/controllers/admin/communication/extranets/posts_controller.rb b/app/controllers/admin/communication/extranets/posts_controller.rb
index 256602b6eb73ae510da558f14e56fecbb3c8c6b2..06a45778374b6f1367e919f4cbed248891ff78c9 100644
--- a/app/controllers/admin/communication/extranets/posts_controller.rb
+++ b/app/controllers/admin/communication/extranets/posts_controller.rb
@@ -2,6 +2,7 @@ class Admin::Communication::Extranets::PostsController < Admin::Communication::E
   load_and_authorize_resource class: Communication::Extranet::Post, through: :extranet
 
   def index
+    @posts = @posts.ordered.page params[:page]
     breadcrumb
   end
 
diff --git a/app/controllers/admin/communication/extranets_controller.rb b/app/controllers/admin/communication/extranets_controller.rb
index d39395957ab78f8eb85dae64b2512c51e5a2af29..d39eec4d35a5566e1812755435602e2dcaae1d17 100644
--- a/app/controllers/admin/communication/extranets_controller.rb
+++ b/app/controllers/admin/communication/extranets_controller.rb
@@ -60,16 +60,16 @@ class Admin::Communication::ExtranetsController < Admin::Communication::Applicat
   def extranet_params
     params.require(:communication_extranet)
           .permit(
-            :about_id, :about_type, 
-            :color, :cookies_policy, 
-            :favicon, :favicon_delete, :feature_alumni, :feature_assets, :feature_contacts, :feature_jobs, :feature_posts,
+            :about_id, :about_type,
+            :color, :cookies_policy,
+            :favicon, :favicon_delete, :feature_alumni, :feature_library, :feature_contacts, :feature_jobs, :feature_posts,
             :has_sso, :host, :home_sentence,
-            :logo, :logo_delete, 
-            :name, 
-            :privacy_policy, 
+            :logo, :logo_delete,
+            :name,
+            :privacy_policy,
             :registration_contact,
             :sass, :sso_target_url, :sso_cert, :sso_name_identifier_format, :sso_mapping, :sso_button_label,
-            :terms, 
+            :terms,
           )
   end
 end
diff --git a/app/controllers/admin/university/alumni/experiences/imports_controller.rb b/app/controllers/admin/university/people/experiences/imports_controller.rb
similarity index 64%
rename from app/controllers/admin/university/alumni/experiences/imports_controller.rb
rename to app/controllers/admin/university/people/experiences/imports_controller.rb
index 538e9dd0de9af981c5b275d54e1bb2599c55d48d..663b26c9bccd8ef393611faeb32117c56580501d 100644
--- a/app/controllers/admin/university/alumni/experiences/imports_controller.rb
+++ b/app/controllers/admin/university/people/experiences/imports_controller.rb
@@ -1,4 +1,4 @@
-class Admin::University::Alumni::Experiences::ImportsController < Admin::University::ApplicationController
+class Admin::University::People::Experiences::ImportsController < Admin::University::ApplicationController
   load_and_authorize_resource class: Import,
                               through: :current_university,
                               through_association: :imports
@@ -6,7 +6,7 @@ class Admin::University::Alumni::Experiences::ImportsController < Admin::Univers
   has_scope :for_status
 
   def index
-    @imports = apply_scopes(@imports.kind_alumni_experiences).ordered.page(params[:page])
+    @imports = apply_scopes(@imports.kind_people_experiences).ordered.page(params[:page])
     breadcrumb
   end
 
@@ -20,11 +20,11 @@ class Admin::University::Alumni::Experiences::ImportsController < Admin::Univers
   end
 
   def create
-    @import.kind = :alumni_experiences
+    @import.kind = :people_experiences
     @import.university = current_university
     @import.user = current_user
     if @import.save
-      redirect_to admin_university_alumni_experiences_import_path(@import),
+      redirect_to admin_university_people_experiences_import_path(@import),
                   notice: t('admin.successfully_created_html', model: @import.to_s)
     else
       breadcrumb
@@ -36,12 +36,12 @@ class Admin::University::Alumni::Experiences::ImportsController < Admin::Univers
 
   def breadcrumb
     super
-    add_breadcrumb  University::Person::Alumnus.model_name.human(count: 2),
-                    admin_university_alumni_path
-    add_breadcrumb  t('university.alumni.experiences.title'),
-                    admin_university_alumni_experiences_imports_path
+    add_breadcrumb  University::Person.model_name.human(count: 2),
+                    admin_university_people_path
+    add_breadcrumb  t('university.person.experiences.title'),
+                    admin_university_people_experiences_imports_path
     return unless @import
-    @import.persisted?  ? add_breadcrumb(@import, admin_university_alumni_experiences_import_path(@import))
+    @import.persisted?  ? add_breadcrumb(@import, admin_university_people_experiences_import_path(@import))
                         : add_breadcrumb(t('create'))
   end
 
diff --git a/app/controllers/admin/university/alumni/experiences_controller.rb b/app/controllers/admin/university/people/experiences_controller.rb
similarity index 70%
rename from app/controllers/admin/university/alumni/experiences_controller.rb
rename to app/controllers/admin/university/people/experiences_controller.rb
index 527edb6e9c72d3bc2d7d391db4b4993d70710246..2fbdec31a3503c52bb25dada807cd3c88ce9241e 100644
--- a/app/controllers/admin/university/alumni/experiences_controller.rb
+++ b/app/controllers/admin/university/people/experiences_controller.rb
@@ -1,5 +1,5 @@
-class Admin::University::Alumni::ExperiencesController < Admin::University::ApplicationController
-  load_and_authorize_resource :alumnus,
+class Admin::University::People::ExperiencesController < Admin::University::ApplicationController
+  load_and_authorize_resource :person,
                               class: University::Person,
                               through: :current_university,
                               through_association: :people,
@@ -9,9 +9,9 @@ class Admin::University::Alumni::ExperiencesController < Admin::University::Appl
   end
 
   def update
-    if @alumnus.update(experiences_params)
-      redirect_to admin_university_alumnus_path(@alumnus),
-                  notice: t('admin.successfully_updated_html', model: @alumnus.to_s)
+    if @person.update(experiences_params)
+      redirect_to admin_university_person_path(@person),
+                  notice: t('admin.successfully_updated_html', model: @person.to_s)
     else
       render :edit
       breadcrumb
@@ -22,9 +22,9 @@ class Admin::University::Alumni::ExperiencesController < Admin::University::Appl
 
   def breadcrumb
     super
-    add_breadcrumb  University::Person::Alumnus.model_name.human(count: 2),
-                    admin_university_alumni_path
-    add_breadcrumb @alumnus, admin_university_alumnus_path(@alumnus)
+    add_breadcrumb  University::Person.model_name.human(count: 2),
+                    admin_university_people_path
+    add_breadcrumb @person, admin_university_person_path(@person)
     add_breadcrumb University::Person::Experience.model_name.human(count: 2)
   end
 
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index de26463477670a34d6a36fbaa83c14c23bf7e164..21384cb34a4cb9c4e03ca2b2585c9ab0057313fd 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -88,7 +88,7 @@ class Admin::UsersController < Admin::ApplicationController
     # Password not provided when user from sso
     params[:user][:password] ||= ''
 
-    if params[:user][:password].empty?
+    if params[:user][:password].blank?
       params[:user].delete(:password)
     else
       @user.reset_password(params[:user][:password], params[:user][:password])
diff --git a/app/controllers/extranet/account_controller.rb b/app/controllers/extranet/account_controller.rb
index 47ded2d779c9b8130fc550c697a9ea505cef683a..ace02aa0c1e5fadb66a76367bb8c6d0ba7fe53b4 100644
--- a/app/controllers/extranet/account_controller.rb
+++ b/app/controllers/extranet/account_controller.rb
@@ -23,7 +23,7 @@ class Extranet::AccountController < Extranet::ApplicationController
     # Password not provided when user from sso
     params[:user][:password] ||= ''
 
-    if params[:user][:password].empty?
+    if params[:user][:password].blank?
       params[:user].delete(:password)
     else
       current_user.reset_password(params[:user][:password], params[:user][:password])
diff --git a/app/controllers/extranet/contacts/search_controller.rb b/app/controllers/extranet/contacts/search_controller.rb
index 0dfc54908cf9a3b075a5ca3d5e45bd3a8d4425d7..72543dc2d2bfd16b3d049de3554637a5ecbd7bdb 100644
--- a/app/controllers/extranet/contacts/search_controller.rb
+++ b/app/controllers/extranet/contacts/search_controller.rb
@@ -1,8 +1,8 @@
 class Extranet::Contacts::SearchController < Extranet::Contacts::ApplicationController
   def index
     @term = params[:term]
-    @people = current_extranet.connected_persons.for_search_term(@term)
-    @organizations = current_extranet.connected_organizations.for_search_term(@term)
+    @people = current_extranet.connected_persons.for_search_term(@term).ordered.limit(20)
+    @organizations = current_extranet.connected_organizations.for_search_term(@term).ordered.limit(20)
     breadcrumb
     add_breadcrumb 'Recherche'
   end
diff --git a/app/controllers/extranet/library/application_controller.rb b/app/controllers/extranet/library/application_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c463290242d49b19e58a4c40fd73c8e1acef5c70
--- /dev/null
+++ b/app/controllers/extranet/library/application_controller.rb
@@ -0,0 +1,9 @@
+class Extranet::Library::ApplicationController < Extranet::ApplicationController
+
+  protected
+
+  def breadcrumb
+    super
+    add_breadcrumb Communication::Extranet.human_attribute_name(:feature_library), library_root_path
+  end
+end
\ No newline at end of file
diff --git a/app/controllers/extranet/library/documents_controller.rb b/app/controllers/extranet/library/documents_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e4dd569db1e66b7502f4a818a145105ab32bbce8
--- /dev/null
+++ b/app/controllers/extranet/library/documents_controller.rb
@@ -0,0 +1,11 @@
+class Extranet::Library::DocumentsController < Extranet::Library::ApplicationController
+
+  def index
+    @documents =  current_extranet.documents
+                                  .published
+                                  .ordered
+                                  .page(params[:page])
+    breadcrumb
+  end
+
+end
diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb
index 14602622f75515cda898e4677d9a16d52ff1d32c..8cfedc5222a5fa063da0ae499c351d894ee5964e 100644
--- a/app/controllers/users/registrations_controller.rb
+++ b/app/controllers/users/registrations_controller.rb
@@ -21,7 +21,7 @@ class Users::RegistrationsController < Devise::RegistrationsController
     # Password not provided when user from sso
     params[:user][:password] ||= ''
 
-    if params[:user][:password].empty?
+    if params[:user][:password].blank?
       params[:user].delete(:password)
     else
       resource.reset_password(params[:user][:password], params[:user][:password])
diff --git a/app/models/communication/block/template/video.rb b/app/models/communication/block/template/video.rb
index de9b378752ee780e5c7aad4f68e52b2d927b1bfc..0e0612d61b86f51883bdc0ff1bf4433d9d8ac71b 100644
--- a/app/models/communication/block/template/video.rb
+++ b/app/models/communication/block/template/video.rb
@@ -4,6 +4,10 @@ class Communication::Block::Template::Video < Communication::Block::Template::Ba
   has_component :video_title, :string
   has_component :transcription, :text
 
+  def video_iframe
+    Video::Provider.find(url).iframe_tag(title: video_title)
+  end
+
   protected
 
   def check_accessibility
diff --git a/app/models/communication/extranet.rb b/app/models/communication/extranet.rb
index 269d82c7414ea74f3fc92a38a01b77309d527979..80bca7540d9803777a961a0a37367c821bc7177f 100644
--- a/app/models/communication/extranet.rb
+++ b/app/models/communication/extranet.rb
@@ -8,9 +8,9 @@
 #  cookies_policy             :text
 #  css                        :text
 #  feature_alumni             :boolean          default(FALSE)
-#  feature_assets             :boolean          default(FALSE)
 #  feature_contacts           :boolean          default(FALSE)
 #  feature_jobs               :boolean          default(FALSE)
+#  feature_library            :boolean          default(FALSE)
 #  feature_posts              :boolean          default(FALSE)
 #  has_sso                    :boolean          default(FALSE)
 #  home_sentence              :text
@@ -58,6 +58,7 @@ class Communication::Extranet < ApplicationRecord
   end
 
   has_many :posts
+  has_many :documents
 
   validates_presence_of :name, :host
   validates :logo, size: { less_than: 1.megabytes }
diff --git a/app/models/communication/extranet/document.rb b/app/models/communication/extranet/document.rb
new file mode 100644
index 0000000000000000000000000000000000000000..081f39cbb290caf496bc1cac72d3051b878208c4
--- /dev/null
+++ b/app/models/communication/extranet/document.rb
@@ -0,0 +1,38 @@
+# == Schema Information
+#
+# Table name: communication_extranet_documents
+#
+#  id            :uuid             not null, primary key
+#  name          :string
+#  published     :boolean
+#  published_at  :datetime
+#  created_at    :datetime         not null
+#  updated_at    :datetime         not null
+#  extranet_id   :uuid             not null, indexed
+#  university_id :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_communication_extranet_documents_on_extranet_id    (extranet_id)
+#  index_communication_extranet_documents_on_university_id  (university_id)
+#
+# Foreign Keys
+#
+#  fk_rails_1272fd263c  (extranet_id => communication_extranets.id)
+#  fk_rails_af877a8c0c  (university_id => universities.id)
+#
+class Communication::Extranet::Document < ApplicationRecord
+  include Sanitizable
+  include WithPublication
+  include WithUniversity
+
+  belongs_to :extranet, class_name: 'Communication::Extranet'
+
+  has_one_attached_deletable :file
+
+  validates :name, presence: true
+
+  def to_s
+    "#{name}"
+  end
+end
diff --git a/app/models/communication/extranet/post.rb b/app/models/communication/extranet/post.rb
index 063fc6dbb9344f6d0ff4044c31dc01690425c936..7c844d233c5418008e67eb29ca1edfab3b11cf6a 100644
--- a/app/models/communication/extranet/post.rb
+++ b/app/models/communication/extranet/post.rb
@@ -33,6 +33,7 @@ class Communication::Extranet::Post < ApplicationRecord
   include WithUniversity
   include WithFeaturedImage
   include WithBlocks
+  include WithPublication
   include WithPermalink
   include WithSlug
 
@@ -41,11 +42,6 @@ class Communication::Extranet::Post < ApplicationRecord
 
   validates :title, presence: true
 
-  before_validation :set_published_at
-
-  scope :published, -> { where(published: true) }
-  scope :ordered, -> { order(published_at: :desc) }
-
   def to_s
     "#{title}"
   end
@@ -58,8 +54,4 @@ class Communication::Extranet::Post < ApplicationRecord
               .where.not(id: self.id)
               .exists?
   end
-
-  def set_published_at
-    self.published_at = Time.zone.now if published && published_at.nil?
-  end
 end
diff --git a/app/models/communication/extranet/with_features.rb b/app/models/communication/extranet/with_features.rb
index 175c1fb2b8b3f1c26ab3194237d5d8fc62c873bd..cc55664d9a07b799c01a98f4df618ea78d742feb 100644
--- a/app/models/communication/extranet/with_features.rb
+++ b/app/models/communication/extranet/with_features.rb
@@ -6,7 +6,7 @@ module Communication::Extranet::WithFeatures
       :alumni,
       :contacts,
       :posts,
-      :assets,
+      :library,
       :jobs,
     ]
   end
diff --git a/app/models/communication/extranet/with_sso.rb b/app/models/communication/extranet/with_sso.rb
index 223eae3bd898d779d7efa81d081dd0be4f90d274..99504282f19fa76477184e2409786a9fb51b61b4 100644
--- a/app/models/communication/extranet/with_sso.rb
+++ b/app/models/communication/extranet/with_sso.rb
@@ -10,7 +10,7 @@ module Communication::Extranet::WithSso
 
   # Setter to serialize data as JSON
   def sso_mapping=(value)
-    if value.empty?
+    if value.blank?
       value = nil
     else
       value = JSON.parse value if value.is_a? String
diff --git a/app/models/concerns/with_publication.rb b/app/models/concerns/with_publication.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d169c33a5bb31bc802feffdf7b160074451bccbb
--- /dev/null
+++ b/app/models/concerns/with_publication.rb
@@ -0,0 +1,29 @@
+module WithPublication
+  extend ActiveSupport::Concern
+
+  included do
+    scope :published, -> { where(published: true) }
+    scope :draft, -> { where(published: false) }
+    scope :ordered, -> { order(published_at: :desc) }
+
+    before_validation :set_published_at
+  end
+
+  def draft?
+    !published || published_in_the_future?
+  end
+
+  def published_in_the_future?
+    published && published_at > Time.now
+  end
+
+  def published_now?
+    published && published_at <= Time.now
+  end
+
+  protected
+
+  def set_published_at
+    self.published_at = Time.zone.now if published && published_at.nil?
+  end
+end
diff --git a/app/models/import.rb b/app/models/import.rb
index 0e7512b8c55885472d778935111c21a007a9be90..d3ebfb313898a94e3b54ae7f60567fb31e867287 100644
--- a/app/models/import.rb
+++ b/app/models/import.rb
@@ -29,7 +29,7 @@ class Import < ApplicationRecord
   has_one_attached_deletable :file
 
 
-  enum kind: { organizations: 0, alumni_cohorts: 1, alumni_experiences: 2 }, _prefix: :kind
+  enum kind: { organizations: 0, alumni_cohorts: 1, people_experiences: 2 }, _prefix: :kind
   enum status: { pending: 0, finished: 1, finished_with_errors: 2 }
 
   validate :file_validation
diff --git a/app/models/university/with_sso.rb b/app/models/university/with_sso.rb
index 1bf5febd1c1d0a7cb548f084399cdc78d61801e9..d54338223d29efe45d074a9beebd3e00f685a9de 100644
--- a/app/models/university/with_sso.rb
+++ b/app/models/university/with_sso.rb
@@ -10,7 +10,7 @@ module University::WithSso
 
   # Setter to serialize data as JSON
   def sso_mapping=(value)
-    if value.empty?
+    if value.blank?
       value = nil
     else
       value = JSON.parse value if value.is_a? String
diff --git a/app/services/icon.rb b/app/services/icon.rb
index ef975717f9b3d22dffc9c8ccbd596305de19597e..57c81aee71c3b8ec2cd6db21c0fc468fa0233c27 100644
--- a/app/services/icon.rb
+++ b/app/services/icon.rb
@@ -20,7 +20,8 @@ class Icon
   COMMUNICATION_EXTRANET_CONTACTS = 'fas fa-address-book'
   COMMUNICATION_EXTRANET_POSTS = 'fas fa-newspaper'
   COMMUNICATION_EXTRANET_JOBS = 'fas fa-code-branch'
-  COMMUNICATION_EXTRANET_ASSETS = 'fas fa-file'
+  COMMUNICATION_EXTRANET_DOCUMENTS = 'fas fa-file'
+  COMMUNICATION_EXTRANET_LIBRARY = COMMUNICATION_EXTRANET_DOCUMENTS
   COMMUNICATION_NEWSLETTERS = 'fas fa-message'
 
   EDUCATION_DIPLOMA = 'fas fa-graduation-cap'
diff --git a/app/services/importers/alumni_cohorts.rb b/app/services/importers/alumni_cohorts.rb
index 2242b8d4ea2bed5e2618b15854aedc54d9e238fe..a225ff76903492b6bdb002b3b5d8fda440721179 100644
--- a/app/services/importers/alumni_cohorts.rb
+++ b/app/services/importers/alumni_cohorts.rb
@@ -1,5 +1,5 @@
 module Importers
-  class AlumniCohorts < Importers::Alumni
+  class AlumniCohorts < Base
 
     protected
 
@@ -16,58 +16,4 @@ module Importers
 
   end
 
-  class HashToCohort
-    def initialize(person, hash)
-      @university = person.university
-      @hash = hash
-      @error = nil
-      extract_variables
-      person.add_to_cohort cohort if valid?
-    end
-
-    def valid?
-      if school.nil?
-        @error = "School #{@school_id} not found"
-      elsif program.nil?
-        @error = "Program #{@program_id} not found"
-      elsif academic_year.nil?
-        @error = "The year #{@year} seems incorrect"
-      elsif cohort.nil?
-        @error = "Unable to create the cohort"
-      end
-      @error.nil?
-    end
-
-    def error
-      @error
-    end
-
-    protected
-
-    def extract_variables
-      @school_id = @hash[17].to_s.strip
-      @program_id = @hash[18].to_s.strip
-      @year = @hash[19].to_s.strip.to_i
-    end
-
-    def school
-      @university.education_schools.find_by(id: @school_id)
-    end
-
-    def program
-      @university.education_programs.find_by(id: @program_id)
-    end
-
-    def academic_year
-      @academic_year ||= @university.academic_years.where(year: @year).first_or_create
-    end
-
-    def cohort
-      @cohort ||= @university.education_cohorts
-                       .where(school: school, program: program, academic_year: academic_year)
-                       .first_or_create
-    end
-
-  end
-
 end
diff --git a/app/services/importers/hash_to_alumnus.rb b/app/services/importers/hash_to_alumnus.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bb032cfef39d6c1127187c551108757c13fe5dbf
--- /dev/null
+++ b/app/services/importers/hash_to_alumnus.rb
@@ -0,0 +1,13 @@
+module Importers
+  class HashToAlumnus < HashToPerson
+
+    def person
+      @person ||= begin
+        person = build_person
+        person.is_alumnus = true
+        person
+      end
+    end
+
+  end
+end
diff --git a/app/services/importers/hash_to_cohort.rb b/app/services/importers/hash_to_cohort.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8cd20a98f5685aeaa276c93673c268d888f60290
--- /dev/null
+++ b/app/services/importers/hash_to_cohort.rb
@@ -0,0 +1,55 @@
+module Importers
+  class HashToCohort
+    def initialize(person, hash)
+      @university = person.university
+      @hash = hash
+      @error = nil
+      extract_variables
+      person.add_to_cohort cohort if valid?
+    end
+
+    def valid?
+      if school.nil?
+        @error = "School #{@school_id} not found"
+      elsif program.nil?
+        @error = "Program #{@program_id} not found"
+      elsif academic_year.nil?
+        @error = "The year #{@year} seems incorrect"
+      elsif cohort.nil?
+        @error = "Unable to create the cohort"
+      end
+      @error.nil?
+    end
+
+    def error
+      @error
+    end
+
+    protected
+
+    def extract_variables
+      @school_id = @hash[17].to_s.strip
+      @program_id = @hash[18].to_s.strip
+      @year = @hash[19].to_s.strip.to_i
+    end
+
+    def school
+      @university.education_schools.find_by(id: @school_id)
+    end
+
+    def program
+      @university.education_programs.find_by(id: @program_id)
+    end
+
+    def academic_year
+      @academic_year ||= @university.academic_years.where(year: @year).first_or_create
+    end
+
+    def cohort
+      @cohort ||= @university.education_cohorts
+                       .where(school: school, program: program, academic_year: academic_year)
+                       .first_or_create
+    end
+
+  end
+end
diff --git a/app/services/importers/alumni_experiences.rb b/app/services/importers/hash_to_experience.rb
similarity index 82%
rename from app/services/importers/alumni_experiences.rb
rename to app/services/importers/hash_to_experience.rb
index 99b66bb630aedb964051a6bb67d5176c477ca360..8f6e88ffb21358bf44118b21b202df29b990deea 100644
--- a/app/services/importers/alumni_experiences.rb
+++ b/app/services/importers/hash_to_experience.rb
@@ -1,21 +1,4 @@
 module Importers
-  class AlumniExperiences < Importers::Alumni
-
-    protected
-
-    def analyze_hash(hash, index)
-      hash_to_alumnus = HashToAlumnus.new(@university, hash)
-      if hash_to_alumnus.valid?
-        person = hash_to_alumnus.person
-        hash_to_experience = HashToExperience.new(person, hash)
-        add_error(hash_to_experience.error, index + 1) unless hash_to_experience.valid?
-      else
-        add_error(hash_to_alumnus.error, index + 1)
-      end
-    end
-
-  end
-
   class HashToExperience
     def initialize(person, hash)
       @person = person
@@ -84,8 +67,5 @@ module Importers
         obj
       end
     end
-
-
   end
-
 end
diff --git a/app/services/importers/alumni.rb b/app/services/importers/hash_to_person.rb
similarity index 58%
rename from app/services/importers/alumni.rb
rename to app/services/importers/hash_to_person.rb
index a539621827601de35f3f42b34f4435e89e57a3c1..72003342e2271cbac7fe9126886f27644f2a7e06 100644
--- a/app/services/importers/alumni.rb
+++ b/app/services/importers/hash_to_person.rb
@@ -1,16 +1,5 @@
 module Importers
-  class Alumni < Base
-
-    protected
-
-    def analyze_hash(hash, index)
-      hash_to_alumnus = HashToAlumnus.new(@university, hash)
-      add_error(hash_to_alumnus.error, index + 1) unless hash_to_alumnus.valid?
-    end
-
-  end
-
-  class HashToAlumnus
+  class HashToPerson
     def initialize(university, hash)
       @university = university
       @hash = hash
@@ -36,36 +25,7 @@ module Importers
     end
 
     def person
-      @person ||= begin
-        if @email.present?
-          person = @university.people
-                             .where(email: @email)
-                             .first_or_initialize
-        elsif @first_name.present? && @last_name.present?
-          person = @university.people
-                             .where(first_name: @first_name, last_name: @last_name)
-                             .first_or_initialize
-        end
-        person.first_name = @first_name
-        person.last_name = @last_name
-        person.gender = gender
-        person.birthdate = @birth
-        person.email = @email
-        person.url = @url
-        person.phone_professional = @phone_professional
-        person.phone_personal = @phone_personal
-        person.phone_mobile = @mobile
-        person.address = @address
-        person.zipcode = @zipcode
-        person.city = @city
-        person.country = @country
-        person.biography = @biography
-        person.twitter = @social_twitter
-        person.linkedin = @social_linkedin
-        person.is_alumnus = true
-        person.slug = person.to_s.parameterize.dasherize
-        person
-      end
+      @person ||= build_person
     end
 
     protected
@@ -90,6 +50,37 @@ module Importers
       @social_linkedin = @hash[16].to_s.strip
     end
 
+    def build_person
+      if @email.present?
+        person = @university.people
+                           .where(email: @email)
+                           .first_or_initialize
+      elsif @first_name.present? && @last_name.present?
+        person = @university.people
+                           .where(first_name: @first_name, last_name: @last_name)
+                           .first_or_initialize
+      end
+      person.first_name = @first_name
+      person.last_name = @last_name
+      person.gender = gender
+      person.birthdate = @birth
+      person.email = @email
+      person.url = @url
+      person.phone_professional = @phone_professional
+      person.phone_personal = @phone_personal
+      person.phone_mobile = @mobile
+      person.address = @address
+      person.zipcode = @zipcode
+      person.city = @city
+      person.country = @country
+      person.biography = @biography
+      person.twitter = @social_twitter
+      person.linkedin = @social_linkedin
+      person.slug = person.to_s.parameterize.dasherize
+      person.language_id = @university.default_language_id
+      person
+    end
+
     def country_not_found?
       ISO3166::Country[@country].nil?
     end
diff --git a/app/services/importers/people_experiences.rb b/app/services/importers/people_experiences.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9e54d1473459ced84b8e93dfd28cc2dedd6ec016
--- /dev/null
+++ b/app/services/importers/people_experiences.rb
@@ -0,0 +1,18 @@
+module Importers
+  class PeopleExperiences < Base
+
+    protected
+
+    def analyze_hash(hash, index)
+      hash_to_person = HashToPerson.new(@university, hash)
+      if hash_to_person.valid?
+        person = hash_to_person.person
+        hash_to_experience = HashToExperience.new(person, hash)
+        add_error(hash_to_experience.error, index + 1) unless hash_to_experience.valid?
+      else
+        add_error(hash_to_person.error, index + 1)
+      end
+    end
+
+  end
+end
diff --git a/app/services/importers/person.rb b/app/services/importers/person.rb
new file mode 100644
index 0000000000000000000000000000000000000000..90c3827b4748f7c285bde819c8b1d4a848842f69
--- /dev/null
+++ b/app/services/importers/person.rb
@@ -0,0 +1,13 @@
+module Importers
+  class Person < Base
+
+    protected
+
+    def analyze_hash(hash, index)
+      hash_to_person = HashToPerson.new(@university, hash)
+      add_error(hash_to_person.error, index + 1) unless hash_to_person.valid?
+    end
+
+  end
+  
+end
diff --git a/app/services/video/provider.rb b/app/services/video/provider.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5b6f3fd68892b3651781a45f47d6e700b448b53a
--- /dev/null
+++ b/app/services/video/provider.rb
@@ -0,0 +1,20 @@
+class Video::Provider
+  PROVIDERS = [
+    Vimeo,
+    Youtube,
+    Dailymotion
+  ]
+
+  def self.find(video_url)
+    PROVIDERS.each do |provider|
+      return provider.new(video_url) if url_in_domains?(video_url, provider::DOMAINS)
+    end
+    Default.new(video_url)
+  end
+
+  protected
+
+  def self.url_in_domains?(url, domains)
+    domains.any? { |domain| url.include? domain }
+  end
+end
diff --git a/app/services/video/provider/dailymotion.rb b/app/services/video/provider/dailymotion.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3a66f5fa5797fd35e2b617b3e45fac6237d77bec
--- /dev/null
+++ b/app/services/video/provider/dailymotion.rb
@@ -0,0 +1,15 @@
+class Video::Provider::Dailymotion < Video::Provider::Default
+  DOMAINS = ['dailymotion.com', 'dai.ly']
+
+  # "https://www.dailymotion.com/video/x35l6b8"
+  # "https://dai.ly/x35l6b8"
+  def identifier
+    video_url.include?('dai.ly')  ? video_url.split('dai.ly/').last
+                                  : video_url.split('video/').last
+  end
+
+  # https://developer.dailymotion.com/player#player-parameters
+  def iframe_url
+    "https://www.dailymotion.com/embed/video/#{identifier}"
+  end
+end
diff --git a/app/services/video/provider/default.rb b/app/services/video/provider/default.rb
new file mode 100644
index 0000000000000000000000000000000000000000..336e8e7aaa27216a09f189c9fc7afee93b43e7cb
--- /dev/null
+++ b/app/services/video/provider/default.rb
@@ -0,0 +1,29 @@
+class Video::Provider::Default
+  attr_reader :video_url
+
+  include ActionView::Helpers::TagHelper
+
+  def initialize(video_url)
+    @video_url = video_url
+  end
+
+  def platform
+    self.class.name.demodulize.downcase.to_sym
+  end
+
+  def iframe_url
+    video_url
+  end
+
+  def iframe_tag(**iframe_options)
+    content_tag(:iframe, nil, default_iframe_options.merge(iframe_options))
+  end
+
+  def default_iframe_options
+    {
+      class: (platform == :default ? nil : platform),
+      loading: 'lazy',
+      src: iframe_url
+    }
+  end
+end
diff --git a/app/services/video/provider/vimeo.rb b/app/services/video/provider/vimeo.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3d10b85440226a7be369e69398803dba4cd20d8b
--- /dev/null
+++ b/app/services/video/provider/vimeo.rb
@@ -0,0 +1,13 @@
+class Video::Provider::Vimeo < Video::Provider::Default
+  DOMAINS = ['vimeo.com']
+
+  # "https://vimeo.com/248482251"
+  def identifier
+    video_url.chomp('/').split('/').last
+  end
+
+  # https://help.vimeo.com/hc/en-us/articles/360001494447-Using-Player-Parameters
+  def iframe_url
+    "https://player.vimeo.com/video/#{identifier}"
+  end
+end
diff --git a/app/services/video/provider/youtube.rb b/app/services/video/provider/youtube.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e9fa299e10619d5ff763a0275c65f1a87718d92e
--- /dev/null
+++ b/app/services/video/provider/youtube.rb
@@ -0,0 +1,15 @@
+class Video::Provider::Youtube < Video::Provider::Default
+  DOMAINS = ['youtube.com', 'youtu.be']
+
+  # "https://www.youtube.com/watch?v=sN8Cq5HEBug"
+  # "https://youtu.be/sN8Cq5HEBug"
+  def identifier
+    video_url.include?('youtu.be')  ? video_url.split('youtu.be/').last
+                                    : video_url.split('v=').last
+  end
+
+  # https://developers.google.com/youtube/player_parameters
+  def iframe_url
+    "https://www.youtube.com/embed/#{identifier}"
+  end
+end
diff --git a/app/views/admin/application/meta_description/_form.html.erb b/app/views/admin/application/meta_description/_form.html.erb
index cc698e0303658fe8bf52f5d0e9f13423d9d7a4fd..0deb74c7d2cb85c05148f67e4e8f7a97ccbe344a 100644
--- a/app/views/admin/application/meta_description/_form.html.erb
+++ b/app/views/admin/application/meta_description/_form.html.erb
@@ -1,8 +1,8 @@
-<%= osuny_panel t('admin.summary') do %>
+<%= osuny_panel t('admin.seo') do %>
   <%= f.input :meta_description,
               label: t('admin.meta_description.label'),
               hint: t('admin.meta_description.hint'),
               input_html: {
                 value: about.meta_description&.gsub('&amp;', '&')
               } %>
-<% end %>
\ No newline at end of file
+<% end %>
diff --git a/app/views/admin/communication/blocks/templates/call_to_action/_preview.html.erb b/app/views/admin/communication/blocks/templates/call_to_action/_preview.html.erb
index dd954f062bd2b68a622d08e95d565644ec155c0b..b9f76636bd6aed01b82e5e86b52f1d293fb59e0d 100644
--- a/app/views/admin/communication/blocks/templates/call_to_action/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/call_to_action/_preview.html.erb
@@ -1,6 +1,6 @@
 <%
-$class = "block block-call_to_action" 
-unless @block.title.empty?
+$class = "block block-call_to_action"
+unless @block.title.blank?
   $class += " block-with-title"
 end
 
@@ -13,7 +13,7 @@ $image_class = "call_to_action--with" + (@block.template.image.empty? ? "out" :
     <div class="block-content">
       <div class="call_to_action <%= $image_class %>">
         <div>
-          <% unless @block.title.empty? %>
+          <% unless @block.title.blank? %>
             <h2><%= @block.title %></h2>
           <% end %>
           <% if @block.template.text %>
diff --git a/app/views/admin/communication/blocks/templates/chapter/_preview.html.erb b/app/views/admin/communication/blocks/templates/chapter/_preview.html.erb
index f36ccec40db610e045ce3c58cde75630969ced50..1be71e833ea3c6e71f390bff03dba5d6877661ed 100644
--- a/app/views/admin/communication/blocks/templates/chapter/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/chapter/_preview.html.erb
@@ -1,7 +1,7 @@
 <%
-$class = "block block-chapter" 
+$class = "block block-chapter"
 
-unless @block.title.empty?
+unless @block.title.blank?
   $class += " block-with-title"
 end
 
@@ -18,17 +18,17 @@ $class += " block-chapter--" + @block.template.layout
     <div class="block-content">
       <div class="chapter">
         <div class="text">
-          <% unless @block.title.empty? %>
+          <% unless @block.title.blank? %>
             <div class="top">
               <h2><%= @block.title %></h2>
             </div>
           <% end %>
-          <% unless @block.template.text.empty? %>
+          <% unless @block.template.text.blank? %>
             <div class="rich-text">
               <%= block_component_preview :text %>
             </div>
           <% end %>
-          <% unless @block.template.notes.empty? %>
+          <% unless @block.template.notes.blank? %>
             <div class="notes">
               <%= block_component_preview :notes %>
             </div>
diff --git a/app/views/admin/communication/blocks/templates/contact/_preview.html.erb b/app/views/admin/communication/blocks/templates/contact/_preview.html.erb
index 3ffb5a299fdd15e417451447d297829e6ac3f65e..9a617582b13cab08266f6fa1c5ab33d85cae7e28 100644
--- a/app/views/admin/communication/blocks/templates/contact/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/contact/_preview.html.erb
@@ -1,6 +1,6 @@
 <%
-$class = "block block-contact" 
-unless @block.title.empty?
+$class = "block block-contact"
+unless @block.title.blank?
   $class += " block-with-title"
 end
 %>
@@ -8,12 +8,12 @@ end
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% unless @block.title.empty? && @block.template.description.empty? %>
+      <% unless @block.title.blank? && @block.template.description.blank? %>
         <div class="top">
-          <% unless @block.title.empty? %>
+          <% unless @block.title.blank? %>
             <h2><%= @block.title %></h2>
           <% end %>
-          <% unless @block.template.description.empty? %>
+          <% unless @block.template.description.blank? %>
             <div class="description">
               <p><%= block_component_preview :description %></p>
             </div>
@@ -23,7 +23,7 @@ end
 
       <div class="informations">
         <address itemscope itemtype="https://schema.org/Organization">
-          <% unless @block.template.name.empty? %>
+          <% unless @block.template.name.blank? %>
             <p><%= block_component_preview :name %></p>
           <% end %>
           <div itemprop="address" itemscope itemtype="https://schema.org/PostalAddress">
diff --git a/app/views/admin/communication/blocks/templates/datatable/_preview.html.erb b/app/views/admin/communication/blocks/templates/datatable/_preview.html.erb
index 4f28c5ab2a22c59949a857416b8188b71a36e63e..fdd161bde54b44ad473f41e1ef64b24d634e20d6 100644
--- a/app/views/admin/communication/blocks/templates/datatable/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/datatable/_preview.html.erb
@@ -1,18 +1,18 @@
 <%
-$class = "block block-datatable" 
-unless @block.title.empty?
+$class = "block block-datatable"
+unless @block.title.blank?
   $class += " block-with-title"
 end
 %>
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% unless @block.title.empty? && @block.template.description.empty? %>
+      <% unless @block.title.blank? && @block.template.description.blank? %>
         <div class="top">
-          <% unless @block.title.empty? %>
+          <% unless @block.title.blank? %>
             <h2><%= @block.title %></h2>
           <% end %>
-          <% unless @block.template.description.empty? %>
+          <% unless @block.template.description.blank? %>
             <div class="description">
               <p><%= block_component_preview :description %></p>
             </div>
@@ -21,7 +21,7 @@ end
       <% end %>
       <div class="table-responsive">
         <table>
-          <% unless @block.template.caption.empty? %>
+          <% unless @block.template.caption.blank? %>
             <caption><%= block_component_preview :caption %></caption>
           <% end %>
           <thead>
diff --git a/app/views/admin/communication/blocks/templates/definitions/_preview.html.erb b/app/views/admin/communication/blocks/templates/definitions/_preview.html.erb
index 62af80feb66c094adcb5a493413aac9935b8b4e0..6770c718db2441be651771243356072bc485a695 100644
--- a/app/views/admin/communication/blocks/templates/definitions/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/definitions/_preview.html.erb
@@ -1,6 +1,6 @@
 <%
-  $class = "block block-definitions" 
-  unless @block.title.empty?
+  $class = "block block-definitions"
+  unless @block.title.blank?
     $class += " block-with-title"
   end
 %>
@@ -8,12 +8,12 @@
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% unless @block.title.empty? && @block.template.description.empty? %>
+      <% unless @block.title.blank? && @block.template.description.blank? %>
         <div class="top">
-          <% unless @block.title.empty? %>
+          <% unless @block.title.blank? %>
             <h2><%= @block.title %></h2>
           <% end %>
-          <% unless @block.template.description.empty? %>
+          <% unless @block.template.description.blank? %>
             <div class="description">
               <p><%= block_component_preview :description %></p>
             </div>
diff --git a/app/views/admin/communication/blocks/templates/files/_preview.html.erb b/app/views/admin/communication/blocks/templates/files/_preview.html.erb
index d216be4a0be9c25f95ec5f8ca10b73b89fb0b318..54f32745652572c91bccae0cb1f3a9c0493b7812 100644
--- a/app/views/admin/communication/blocks/templates/files/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/files/_preview.html.erb
@@ -1,6 +1,6 @@
 <%
-$class = "block block-files" 
-unless @block.title.empty?
+$class = "block block-files"
+unless @block.title.blank?
   $class += " block-with-title"
 end
 %>
@@ -8,19 +8,19 @@ end
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% unless @block.title.empty? && @block.template.description.empty? %>
+      <% unless @block.title.blank? && @block.template.description.blank? %>
         <div class="top">
-          <% unless @block.title.empty? %>
+          <% unless @block.title.blank? %>
             <h2><%= @block.title %></h2>
           <% end %>
-          <% unless @block.template.description.empty? %>
+          <% unless @block.template.description.blank? %>
             <div class="description">
               <p><%= block_component_preview :description %></p>
             </div>
           <% end %>
         </div>
       <% end %>
-        
+
       <ul class="files">
         <% @block.template.elements.each do |element| %>
           <% next unless element.blob %>
diff --git a/app/views/admin/communication/blocks/templates/gallery/_preview.html.erb b/app/views/admin/communication/blocks/templates/gallery/_preview.html.erb
index e0f11498fdfc85702621d012db24413561d49734..1930887a150cc86d8c272c88c9b40751c2b36762 100644
--- a/app/views/admin/communication/blocks/templates/gallery/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/gallery/_preview.html.erb
@@ -1,6 +1,6 @@
 <%
-$class = "block block-gallery" 
-if @block.title
+$class = "block block-gallery"
+if @block.title.present?
   $class += " block-with-title"
 end
 
@@ -10,12 +10,12 @@ $class += " block-gallery--" + @block.template.layout
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% if @block.title || @block.template.description %>
+      <% if @block.title.present? || @block.template.description.present? %>
         <div class="top">
-          <% if @block.title %>
+          <% if @block.title.present? %>
             <h2><%= @block.title %></h2>
           <% end %>
-          <% if @block.template.description %>
+          <% if @block.template.description.present? %>
             <div class="description">
               <p><%= block_component_preview :description %></p>
             </div>
@@ -29,7 +29,7 @@ $class += " block-gallery--" + @block.template.layout
             <div class="splide__track">
               <div class="splide__list">
         <% end %>
-        <% @block.template.elements.each do |element| %> 
+        <% @block.template.elements.each do |element| %>
           <%= block_component_preview :image, template: element %>
         <% end %>
         <% if !@block.template.elements.one? %>
@@ -39,7 +39,7 @@ $class += " block-gallery--" + @block.template.layout
         <% end %>
       <% else %>
         <div class="gallery" role="group">
-          <% @block.template.elements.each do |element| %> 
+          <% @block.template.elements.each do |element| %>
             <%= block_component_preview :image, template: element %>
           <% end %>
         </div>
diff --git a/app/views/admin/communication/blocks/templates/image/_preview.html.erb b/app/views/admin/communication/blocks/templates/image/_preview.html.erb
index 7974851a3ce20c28fc0e4f552f61b220052bfd44..cdb2997ed03d37cf8861f6581f40d0430957d78f 100644
--- a/app/views/admin/communication/blocks/templates/image/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/image/_preview.html.erb
@@ -1,14 +1,14 @@
 <%
-$class = "block block-image" 
+$class = "block block-image"
 
-unless @block.title.empty?
+unless @block.title.blank?
   $class += " block-with-title"
 end
 %>
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% unless @block.title.empty? %>
+      <% unless @block.title.blank? %>
         <div class="top">
           <h2><%= @block.title %></h2>
         </div>
diff --git a/app/views/admin/communication/blocks/templates/key_figures/_preview.html.erb b/app/views/admin/communication/blocks/templates/key_figures/_preview.html.erb
index 6dab913578249b03576ca3dbe438c444d700d5c5..4ca7f51f60737fd74aff8d0b24c857cfe1225354 100644
--- a/app/views/admin/communication/blocks/templates/key_figures/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/key_figures/_preview.html.erb
@@ -1,18 +1,18 @@
 <%
-$class = "block block-key_figures" 
-unless @block.title.empty?
+$class = "block block-key_figures"
+unless @block.title.blank?
   $class += " block-with-title"
 end
 %>
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% unless @block.title.empty? && @block.template.description.empty? %>
+      <% unless @block.title.blank? && @block.template.description.blank? %>
         <div class="top">
-          <% unless @block.title.empty? %>
+          <% unless @block.title.blank? %>
             <h2><%= @block.title %></h2>
           <% end %>
-          <% unless @block.template.description.empty? %>
+          <% unless @block.template.description.blank? %>
             <div class="description">
               <p><%= block_component_preview :description %></p>
             </div>
diff --git a/app/views/admin/communication/blocks/templates/testimonials/_preview.html.erb b/app/views/admin/communication/blocks/templates/testimonials/_preview.html.erb
index 2ee3289916685feac3783819545b7dd2ccbbb773..a4069d658c9b6b67d234e39549d952c540965e39 100644
--- a/app/views/admin/communication/blocks/templates/testimonials/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/testimonials/_preview.html.erb
@@ -1,6 +1,6 @@
 <%
   class_name = "block block-testimonials" 
-  unless @block.title.empty?
+  unless @block.title.blank?
     class_name += " block-with-title"
   end
   if !@block.template.elements.one?
@@ -13,7 +13,7 @@
     <div class="block-content">
       <div class="testimonials">
         <% if !@block.template.elements.one? %>
-          <div class="splide" 
+          <div class="splide"
               data-splide='{
                   "arrows":false,
                   "autoplay":true,
diff --git a/app/views/admin/communication/blocks/templates/timeline/_preview.html.erb b/app/views/admin/communication/blocks/templates/timeline/_preview.html.erb
index 2db59ce4534c8fee90748799ba4541edfe1364a2..ff8f7921a6131a2a9963d9a012c45f47fe15284b 100644
--- a/app/views/admin/communication/blocks/templates/timeline/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/timeline/_preview.html.erb
@@ -1,6 +1,6 @@
 <%
-  $class = "block block-timeline" 
-  unless @block.title.empty?
+  $class = "block block-timeline"
+  unless @block.title.blank?
     $class += " block-with-title"
   end
   $class += " block-timeline--" + @block.template.layout
@@ -10,7 +10,7 @@
   <div class="container">
     <% if @block.template.layout == "vertical" %>
       <div class="block-content">
-        <% unless @block.title.empty? %>
+        <% unless @block.title.blank? %>
           <div class="top">
             <h2><%= @block.title %></h2>
           </div>
@@ -30,7 +30,7 @@
       </div>
     <% else %>
       <div class="timeline">
-        <% unless @block.title.empty? %>
+        <% unless @block.title.blank? %>
           <h2><%= @block.title %></h2>
         <% end %>
         <div class="events">
diff --git a/app/views/admin/communication/blocks/templates/video/_preview.html.erb b/app/views/admin/communication/blocks/templates/video/_preview.html.erb
index b06b4ae42209b8ebf12d61732c7ddceafecdf480..598bfda1afa1c070fa2a5b720bbfa0d9b7244e24 100644
--- a/app/views/admin/communication/blocks/templates/video/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/video/_preview.html.erb
@@ -1,25 +1,20 @@
 <%
-$class = "block block-video" 
-unless @block.title.empty?
+$class = "block block-video"
+unless @block.title.blank?
   $class += " block-with-title"
 end
 %>
 <section class="<%= $class %>">
   <div class="container">
     <div class="block-content">
-      <% unless @block.title.empty? %>
+      <% unless @block.title.blank? %>
         <div class="top">
           <h2><%= @block.title %></h2>
         </div>
       <% end %>
-      <% if @block.template.url %>
+      <% if @block.template.url.present? %>
         <div class="video">
-          <%# TODO: identification du provider de la vidéo %>
-          <iframe 
-            src="<%= block_component_preview :url %>"
-            title="<%= block_component_preview :video_title %>"
-            loading="lazy"
-            ></iframe>
+          <%= @block.template.video_iframe %>
         </div>
       <% end %>
       <% if @block.template.video_title %>
diff --git a/app/views/admin/communication/blocks/templates/video/_static.html.erb b/app/views/admin/communication/blocks/templates/video/_static.html.erb
index ca779a451ec5b3d8212f816dc1df3ec7933a4ea8..ad5aae3546b5a64753c64decc27f1b8154a841f5 100644
--- a/app/views/admin/communication/blocks/templates/video/_static.html.erb
+++ b/app/views/admin/communication/blocks/templates/video/_static.html.erb
@@ -1,3 +1,7 @@
 <%= block_component_static :url %>
 <%= block_component_static :video_title %>
+<% if block.template.url.present? %>
+      video_iframe: >-
+        <%= block.template.video_iframe %>
+<% end %>
 <%= block_component_static :transcription %>
diff --git a/app/views/admin/communication/extranets/_form.html.erb b/app/views/admin/communication/extranets/_form.html.erb
index 62246a4bc018bc966a6e44890cdecf4083468d69..eef002e8e81176d5512e22bc0b363c067fc711ec 100644
--- a/app/views/admin/communication/extranets/_form.html.erb
+++ b/app/views/admin/communication/extranets/_form.html.erb
@@ -30,7 +30,7 @@
       <%= osuny_panel t('extranet.features') do %>
         <%= f.input :feature_alumni %>
         <%= f.input :feature_contacts %>
-        <%= f.input :feature_assets %>
+        <%= f.input :feature_library %>
         <%= f.input :feature_posts %>
         <%= f.input :feature_jobs %>
       <% end %>
diff --git a/app/views/admin/communication/extranets/assets/index.html.erb b/app/views/admin/communication/extranets/assets/index.html.erb
deleted file mode 100644
index f32303c0d78b6d3c0d2265f039c4fb1f036c6afc..0000000000000000000000000000000000000000
--- a/app/views/admin/communication/extranets/assets/index.html.erb
+++ /dev/null
@@ -1,4 +0,0 @@
-<% content_for :title, Communication::Extranet.human_attribute_name(:feature_assets) %>
-
-<%= render 'admin/communication/extranets/sidebar' do %>
-<% end %>
\ No newline at end of file
diff --git a/app/views/admin/communication/extranets/contacts/index.html.erb b/app/views/admin/communication/extranets/contacts/index.html.erb
index f01ffcb4d1cbbf8ce6dbed76f68fef29a2d48e72..9c0b638d69cc7b58fa37ec32d7e904833e08b193 100644
--- a/app/views/admin/communication/extranets/contacts/index.html.erb
+++ b/app/views/admin/communication/extranets/contacts/index.html.erb
@@ -2,68 +2,74 @@
 
 <%= render 'admin/communication/extranets/sidebar' do %>
   <%= osuny_panel University::Person.model_name.human(count: 2) do %>
-    <table class="<%= table_classes%>">
-      <tbody>
-        <% @persons.each do |person| %>
-          <tr>
-            <td><%= link_to person, [:admin, person] %></td>
-            <td><%= person.email %></td>
-            <td>
-              <% if @extranet.connected?(person) %>
-                <%= link_to 'Déconnecter', 
-                                disconnect_admin_communication_extranet_contacts_path(
-                                  extranet_id: @extranet.id, 
-                                  objectId: person.id, 
-                                  objectType: person.class
-                                ),
-                                class: button_classes_danger,
-                                method: :post %>
-               <% else %>
-                <%= link_to 'Connecter', 
-                                connect_admin_communication_extranet_contacts_path(
-                                  extranet_id: @extranet.id, 
-                                  objectId: person.id, 
-                                  objectType: person.class
-                                ),
-                                class: button_classes,
-                                method: :post %>
-               <% end %>
-              </td>
-          </tr>
-        <% end %>
-      </tbody>
-    </table>
+    <div class="table-responsive">
+      <table class="<%= table_classes%>">
+        <tbody>
+          <% @persons.each do |person| %>
+            <tr>
+              <td><%= link_to person, [:admin, person] %></td>
+              <td><%= person.email %></td>
+              <td>
+                <% if @extranet.connected?(person) %>
+                  <%= link_to 'Déconnecter', 
+                                  disconnect_admin_communication_extranet_contacts_path(
+                                    extranet_id: @extranet.id, 
+                                    objectId: person.id, 
+                                    objectType: person.class
+                                  ),
+                                  class: button_classes_danger,
+                                  method: :post %>
+                <% else %>
+                  <%= link_to 'Connecter', 
+                                  connect_admin_communication_extranet_contacts_path(
+                                    extranet_id: @extranet.id, 
+                                    objectId: person.id, 
+                                    objectType: person.class
+                                  ),
+                                  class: button_classes,
+                                  method: :post %>
+                <% end %>
+                </td>
+            </tr>
+          <% end %>
+        </tbody>
+      </table>
+    </div>
+    <%= paginate @persons, theme: 'bootstrap-5', param_name: :persons_page %>
   <% end %>
   <%= osuny_panel University::Organization.model_name.human(count: 2) do %>
-    <table class="<%= table_classes%>">
-      <tbody>
-        <% @organizations.each do |organization| %>
-          <tr>
-            <td><%= link_to organization, [:admin, organization] %></td>
-            <td>
-              <% if @extranet.connected?(organization) %>
-                <%= link_to 'Déconnecter', 
-                                disconnect_admin_communication_extranet_contacts_path(
-                                  extranet_id: @extranet.id, 
-                                  objectId: organization.id, 
-                                  objectType: organization.class
-                                ),
-                                class: button_classes_danger,
-                                method: :post %>
-               <% else %>
-                <%= link_to 'Connecter', 
-                                connect_admin_communication_extranet_contacts_path(
-                                  extranet_id: @extranet.id, 
-                                  objectId: organization.id, 
-                                  objectType: organization.class
-                                ),
-                                class: button_classes,
-                                method: :post %>
-               <% end %>
-              </td>
-          </tr>
-        <% end %>
-      </tbody>
-    </table>
+    <div class="table-responsive">
+      <table class="<%= table_classes%>">
+        <tbody>
+          <% @organizations.each do |organization| %>
+            <tr>
+              <td><%= link_to organization, [:admin, organization] %></td>
+              <td>
+                <% if @extranet.connected?(organization) %>
+                  <%= link_to 'Déconnecter', 
+                                  disconnect_admin_communication_extranet_contacts_path(
+                                    extranet_id: @extranet.id, 
+                                    objectId: organization.id, 
+                                    objectType: organization.class
+                                  ),
+                                  class: button_classes_danger,
+                                  method: :post %>
+                <% else %>
+                  <%= link_to 'Connecter', 
+                                  connect_admin_communication_extranet_contacts_path(
+                                    extranet_id: @extranet.id, 
+                                    objectId: organization.id, 
+                                    objectType: organization.class
+                                  ),
+                                  class: button_classes,
+                                  method: :post %>
+                <% end %>
+                </td>
+            </tr>
+          <% end %>
+        </tbody>
+      </table>
+    </div>
+    <%= paginate @organizations, theme: 'bootstrap-5', param_name: :organizations_page %>
   <% end %>
 <% end %>
\ No newline at end of file
diff --git a/app/views/admin/communication/extranets/documents/_form.html.erb b/app/views/admin/communication/extranets/documents/_form.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..063aa8dc6bfef2611428dd28009d2e95cb9c0cd2
--- /dev/null
+++ b/app/views/admin/communication/extranets/documents/_form.html.erb
@@ -0,0 +1,28 @@
+<%= simple_form_for [:admin, document] do |f| %>
+  <%= f.error_notification %>
+  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
+
+  <div class="row">
+    <div class="col-md-8">
+      <%= osuny_panel t('content') do %>
+        <%= f.input :name %>
+        <%= f.input :file, as: :single_deletable_file %>
+      <% end %>
+    </div>
+    <div class="col-md-4">
+      <%= osuny_panel t('metadata') do %>
+        <% if can? :publish, document %>
+          <div class="row pure__row--small">
+            <div class="col-6">
+              <%= f.input :published %>
+            </div>
+          </div>
+          <%= f.input :published_at, html5: true, as: :date %>
+        <% end %>
+      <% end %>
+    </div>
+  </div>
+  <% content_for :action_bar_right do %>
+    <%= submit f %>
+  <% end %>
+<% end %>
diff --git a/app/views/admin/communication/extranets/documents/_list.html.erb b/app/views/admin/communication/extranets/documents/_list.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..694761907e046fba9544248c5126d3ac08554455
--- /dev/null
+++ b/app/views/admin/communication/extranets/documents/_list.html.erb
@@ -0,0 +1,38 @@
+<div class="table-responsive">
+  <table class="<%= table_classes %>">
+    <thead>
+      <tr>
+        <th class="ps-0" width="60%"><%= Communication::Extranet::Document.human_attribute_name('name') %></th>
+        <th class="ps-3"><%= Communication::Extranet::Document.human_attribute_name('published') %></th>
+        <th colspan="2" class="ps-3"><%= Communication::Extranet::Document.human_attribute_name('meta') %></th>
+      </tr>
+    </thead>
+    <tbody>
+      <% documents.each do |document| %>
+        <tr <% if document.draft? %>class="draft"<% end %>>
+          <td class="ps-0">
+            <%= link_to document,
+                        admin_communication_extranet_document_path(extranet_id: document.extranet.id, id: document.id),
+                        class: "#{'draft' unless document.published?}" %>
+          </td>
+          <td class="ps-3 small">
+            <%= t document.published %>, 
+            <%= l document.published_at, format: :date_with_explicit_month if document.published_at %>
+          </td>
+          <td>
+            <div class="btn-group" role="group">
+              <%= link_to t('edit'),
+                          edit_admin_communication_extranet_document_path(extranet_id: document.extranet.id, id: document.id),
+                          class: button_classes if can?(:update, document) %>
+              <%= link_to t('delete'),
+                          admin_communication_extranet_document_path(extranet_id: document.extranet.id, id: document.id),
+                          method: :delete,
+                          data: { confirm: t('please_confirm') },
+                          class: button_classes_danger if can?(:destroy, document) %>
+            </div>
+          </td>
+        </tr>
+      <% end %>
+    </tbody>
+  </table>
+</div>
diff --git a/app/views/admin/communication/extranets/documents/edit.html.erb b/app/views/admin/communication/extranets/documents/edit.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..56761d20ec4d2a2a35d289eaf8fb55eb2afc542d
--- /dev/null
+++ b/app/views/admin/communication/extranets/documents/edit.html.erb
@@ -0,0 +1,5 @@
+<% content_for :title, @document %>
+
+<%= render 'admin/communication/extranets/sidebar' do %>
+  <%= render 'form', document: @document %>
+<% end %>
diff --git a/app/views/admin/communication/extranets/documents/index.html.erb b/app/views/admin/communication/extranets/documents/index.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..40ec6ed9a75ee524b5dd85ef886ebdcdd295b875
--- /dev/null
+++ b/app/views/admin/communication/extranets/documents/index.html.erb
@@ -0,0 +1,10 @@
+<% content_for :title, Communication::Extranet.human_attribute_name(:feature_library) %>
+
+<%= render 'admin/communication/extranets/sidebar' do %>
+  <%= render 'admin/communication/extranets/documents/list', documents: @documents %>
+  <%= paginate @documents, theme: 'bootstrap-5' %>
+<% end %>
+
+<% content_for :action_bar_right do %>
+  <%= create_link Communication::Extranet::Document %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/admin/communication/extranets/documents/new.html.erb b/app/views/admin/communication/extranets/documents/new.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..b7bf39a1fade903dc438560247991cd92a6e3db5
--- /dev/null
+++ b/app/views/admin/communication/extranets/documents/new.html.erb
@@ -0,0 +1,5 @@
+<% content_for :title, Communication::Extranet::Document.model_name.human %>
+
+<%= render 'admin/communication/extranets/sidebar' do %>
+  <%= render 'form', document: @document %>
+<% end %>
diff --git a/app/views/admin/communication/extranets/documents/show.html.erb b/app/views/admin/communication/extranets/documents/show.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..fbc17175fb3036454f659d82484f6048cda21576
--- /dev/null
+++ b/app/views/admin/communication/extranets/documents/show.html.erb
@@ -0,0 +1,33 @@
+<% content_for :title, @document %>
+
+<%= render 'admin/communication/extranets/sidebar' do %>
+  <div class="row">
+    <div class="col-xl-8">
+      <% if @document.file.attached? %>
+        <%= link_to @document.file.filename, @document.file.url, target: :_blank %>
+      <% end %>
+    </div>
+    <div class="col-xl-4">
+      <%= osuny_panel t('metadata') do %>
+        <div class="row pure__row--small">
+          <div class="col-6">
+            <%= osuny_label Communication::Extranet::Document.human_attribute_name('published') %>
+            <p>
+              <%= t @document.published %><% if @document.published %>,
+                <%= l @document.published_at.to_date, format: :long %>
+              <% end %>
+            </p>
+          </div>
+        </div>
+      <% end %>
+    </div>
+  </div>
+<% end %>
+
+<% content_for :action_bar_left do %>
+  <%= destroy_link @document %>
+<% end %>
+
+<% content_for :action_bar_right do %>
+  <%= edit_link @document %>
+<% end %>
diff --git a/app/views/admin/communication/extranets/posts/_list.html.erb b/app/views/admin/communication/extranets/posts/_list.html.erb
index 1986fdaa671f6d831f4f2f32b74f15101b5025d7..5f4d60c608c099ffaf3f2b8ffd6f5bb996c4d606 100644
--- a/app/views/admin/communication/extranets/posts/_list.html.erb
+++ b/app/views/admin/communication/extranets/posts/_list.html.erb
@@ -4,6 +4,7 @@
       <tr>
         <th class="ps-0" width="60%"><%= Communication::Extranet::Post.human_attribute_name('title') %></th>
         <th><%= Communication::Extranet::Post.human_attribute_name('featured_image') %></th>
+        <th class="ps-3"><%= Communication::Extranet::Post.human_attribute_name('published') %></th>
         <th colspan="2" class="ps-3"><%= Communication::Extranet::Post.human_attribute_name('meta') %></th>
       </tr>
     </thead>
@@ -16,6 +17,7 @@
           <td><%= image_tag post.featured_image.representation(resize: '200x'),
                                             width: 100 if post.featured_image.attached? && post.featured_image.representable? %></td>
           <td class="ps-3 small">
+            <%= t post.published %>, 
             <%= l post.published_at, format: :date_with_explicit_month if post.published_at %><br>
             <%= post.author %>
           </td>
@@ -25,7 +27,7 @@
                           edit_admin_communication_extranet_post_path(website_id: post.extranet.id, id: post.id),
                           class: button_classes if can?(:update, post) %>
               <%= link_to t('delete'),
-                          admin_communication_extranet_post_path(website_id: post.extranet.id, id: post.id),
+                          admin_communication_extranet_post_path(extranet_id: post.extranet.id, id: post.id),
                           method: :delete,
                           data: { confirm: t('please_confirm') },
                           class: button_classes_danger if can?(:destroy, post) %>
diff --git a/app/views/admin/communication/extranets/posts/index.html.erb b/app/views/admin/communication/extranets/posts/index.html.erb
index 57d0771ca34721682a96d22959fe3a2418445a8c..e1daf4ea040673e18b2ac2d6645b03e2acd23639 100644
--- a/app/views/admin/communication/extranets/posts/index.html.erb
+++ b/app/views/admin/communication/extranets/posts/index.html.erb
@@ -2,6 +2,7 @@
 
 <%= render 'admin/communication/extranets/sidebar' do %>
   <%= render 'admin/communication/extranets/posts/list', posts: @posts %>
+  <%= paginate @posts, theme: 'bootstrap-5' %>
 <% end %>
 
 <% content_for :action_bar_right do %>
diff --git a/app/views/admin/communication/extranets/posts/new.html.erb b/app/views/admin/communication/extranets/posts/new.html.erb
index 50458a1077b8aeffec6bc23b38efe9ebb23cd35a..90355fd68bb218aa81575b670ee4c2270682efee 100644
--- a/app/views/admin/communication/extranets/posts/new.html.erb
+++ b/app/views/admin/communication/extranets/posts/new.html.erb
@@ -1,4 +1,4 @@
-<% content_for :title, Communication::Website::Post.model_name.human %>
+<% content_for :title, Communication::Extranet::Post.model_name.human %>
 
 <%= render 'admin/communication/extranets/sidebar' do %>
   <%= render 'form', post: @post %>
diff --git a/app/views/admin/communication/extranets/posts/show.html.erb b/app/views/admin/communication/extranets/posts/show.html.erb
index 23b79bbf351494b9e5fa7f8efa610f4840bcef38..ad9c804d175b4e4646f32224c592078f240ca9f0 100644
--- a/app/views/admin/communication/extranets/posts/show.html.erb
+++ b/app/views/admin/communication/extranets/posts/show.html.erb
@@ -17,7 +17,7 @@
       <%= osuny_panel t('metadata'), action: action do %>
         <div class="row pure__row--small">
           <div class="col-6">
-            <%= osuny_label Communication::Website::Post.human_attribute_name('published') %>
+            <%= osuny_label Communication::Extranet::Post.human_attribute_name('published') %>
             <p>
               <%= t @post.published %><% if @post.published & @post.published_at %>,
                 <%= l @post.published_at.to_date, format: :long if @post.published_at %>
@@ -29,7 +29,7 @@
           <%= osuny_label Communication::Extranet::Post.human_attribute_name('author') %>
           <p><%= @post.author %></p>
         <% end %>
-        <%= osuny_label Communication::Website::Post.human_attribute_name('slug') %>
+        <%= osuny_label Communication::Extranet::Post.human_attribute_name('slug') %>
         <p><%= @post.slug %></p>
       <% end %>
       <%= render 'admin/application/featured_image/show', about: @post %>
diff --git a/app/views/admin/layouts/themes/_appstack.html.erb b/app/views/admin/layouts/themes/_appstack.html.erb
index 8ca84d7862310d69fdd76292152b3f3e87b8a25b..331f7b38364abd8c6d9a9b7a46c14fb087a0b5b0 100644
--- a/app/views/admin/layouts/themes/_appstack.html.erb
+++ b/app/views/admin/layouts/themes/_appstack.html.erb
@@ -1,5 +1,5 @@
 <body class="<%= body_classes %>" data-layout="fluid" data-sidebar-position="left">
-  <%= render 'admin/application/notice' %>
+  <%= render 'application/notice' %>
   <div class="wrapper">
     <%= render "admin/layouts/themes/appstack/nav" %>
     <%= render "admin/layouts/themes/appstack/footer" %>
diff --git a/app/views/admin/layouts/themes/_pure.html.erb b/app/views/admin/layouts/themes/_pure.html.erb
index b5bfe97af04e6dd935348c68a86227b3b57ac607..965029888465752746d75e9336121af843a8d2e2 100644
--- a/app/views/admin/layouts/themes/_pure.html.erb
+++ b/app/views/admin/layouts/themes/_pure.html.erb
@@ -1,7 +1,7 @@
 <body class="<%= body_classes %>">
   <%= render "admin/layouts/themes/pure/nav" %>
   <%= render "admin/layouts/themes/pure/hero" %>
-  <%= render 'admin/application/notice' %>
+  <%= render 'application/notice' %>
   <main class="container-fluid">
     <% unless current_user.confirmed? %>
       <div class="alert alert-warning">
diff --git a/app/views/admin/research/laboratories/axes/show.html.erb b/app/views/admin/research/laboratories/axes/show.html.erb
index e0691afb6c498430efe9c1515bd44e99d6841459..307fee70fe72b075195f9d58d0bb3fa18f3cb6f4 100644
--- a/app/views/admin/research/laboratories/axes/show.html.erb
+++ b/app/views/admin/research/laboratories/axes/show.html.erb
@@ -3,7 +3,7 @@
 <div class="row">
   <div class="col-md-8">
     <%= osuny_panel t('content') do %>
-      <% unless @axis.short_name.empty? %>
+      <% unless @axis.short_name.blank? %>
         <%= osuny_label Research::Laboratory::Axis.human_attribute_name('short_name') %>
         <p><%= @axis.short_name %></p>
       <% end %>
diff --git a/app/views/admin/university/alumni/_list.html.erb b/app/views/admin/university/alumni/_list.html.erb
index 9d171e73e1f653f1502d1ad7a356fbaee6567db4..f0e1db78bacc2b6e57eb8a810ef3399ba3572d2b 100644
--- a/app/views/admin/university/alumni/_list.html.erb
+++ b/app/views/admin/university/alumni/_list.html.erb
@@ -5,7 +5,6 @@
         <th><%= University::Person.human_attribute_name('last_name') %></th>
         <th><%= University::Person.human_attribute_name('first_name') %></th>
         <th><%= Education::Cohort.model_name.human(count: 2) %></th>
-        <th><%= University::Person::Experience.model_name.human(count: 2) %></th>
         <th></th>
       </tr>
     </thead>
@@ -16,7 +15,6 @@
           <td><%= link_to_if can?(:read, alumnus), alumnus.last_name, path %></td>
           <td><%= link_to_if can?(:read, alumnus), alumnus.first_name, path %></td>
           <td><%= link_to_if can?(:update, alumnus), alumnus.cohorts.size, cohorts_admin_university_alumnus_path(alumnus) %></td>
-          <td><%= link_to_if can?(:update, alumnus), alumnus.experiences.size, experiences_admin_university_alumnus_path(alumnus) %></td>
           <td><%= kamifusen_tag alumnus.best_picture, width: 80 if alumnus.best_picture.attached? %></td>
         </tr>
       <% end %>
diff --git a/app/views/admin/university/alumni/experiences/imports/index.html.erb b/app/views/admin/university/alumni/experiences/imports/index.html.erb
deleted file mode 100644
index 58402622cb6c33df962a90859662f25ce6c34df0..0000000000000000000000000000000000000000
--- a/app/views/admin/university/alumni/experiences/imports/index.html.erb
+++ /dev/null
@@ -1,12 +0,0 @@
-<% content_for :title, t('university.alumni.experiences.title') %>
-
-<%= render 'filters', current_path: admin_university_alumni_experiences_imports_path, filters: @filters if @filters.any?  %>
-
-<%= render 'admin/imports/list', imports: @imports, path_pattern: 'admin_university_alumni_experiences_import_path' %>
-
-<% content_for :action_bar_right do %>
-  <%= link_to_if  can?(:create, University::Person::Alumnus),
-                  t('create'),
-                  new_admin_university_alumni_experiences_import_path,
-                  class: button_classes %>
-<% end %>
diff --git a/app/views/admin/university/alumni/index.html.erb b/app/views/admin/university/alumni/index.html.erb
index c6a436b4cbbd66fe9a86e1d6041024508bc43d40..ca8c4e7a7822b32001a7ac72ef828cc6bf309fd6 100644
--- a/app/views/admin/university/alumni/index.html.erb
+++ b/app/views/admin/university/alumni/index.html.erb
@@ -10,9 +10,6 @@
   <%= link_to t('university.alumni.cohorts.import_btn'),
               new_admin_university_alumni_cohorts_import_path,
               class: button_classes if can? :create, University::Person::Alumnus %>
-  <%= link_to t('university.alumni.experiences.import_btn'),
-              new_admin_university_alumni_experiences_import_path,
-              class: button_classes if can? :create, University::Person::Alumnus %>
 <% end %>
 
 <% content_for :action_bar_right do %>
diff --git a/app/views/admin/university/alumni/show.html.erb b/app/views/admin/university/alumni/show.html.erb
index d5723d063c9c20535a5121bcdfd3ac11a4178c3b..c3bc9573280e41fface0ad6ede4bf350f934dc2a 100644
--- a/app/views/admin/university/alumni/show.html.erb
+++ b/app/views/admin/university/alumni/show.html.erb
@@ -12,16 +12,6 @@ action += link_to t('university.manage_cohorts'),
   <%= render 'admin/education/cohorts/list', cohorts: @alumnus.cohorts.ordered %>
 <% end %>
 
-<%
-action = ''
-action += link_to t('university.manage_experiences'),
-                  experiences_admin_university_alumnus_path(@alumnus),
-                  class: button_classes if can?(:update, @alumnus)
-%>
-<%= osuny_panel University::Person::Experience.model_name.human(count: 2), action: action do %>
-  <%= render 'admin/university/people/experiences/list', experiences: @alumnus.experiences.ordered %>
-<% end %>
-
 <% content_for :action_bar_right do %>
   <%= edit_link @alumnus %>
 <% end %>
diff --git a/app/views/admin/university/people/_list.html.erb b/app/views/admin/university/people/_list.html.erb
index f2bd77eecbf84558deecf302b1cbfe0605629d50..9b9fe26e704772d04186e68bc20c361d00c78a6a 100644
--- a/app/views/admin/university/people/_list.html.erb
+++ b/app/views/admin/university/people/_list.html.erb
@@ -5,6 +5,7 @@
         <th><%= University::Person.human_attribute_name('last_name') %></th>
         <th><%= University::Person.human_attribute_name('first_name') %></th>
         <th><%= University::Person.human_attribute_name('roles') %></th>
+        <th><%= University::Person::Experience.model_name.human(count: 2) %></th>
         <th></th>
         <th></th>
       </tr>
@@ -21,6 +22,7 @@
               </span>
             <% end %>
           </td>
+          <td><%= link_to_if can?(:update, person), person.experiences.size, experiences_admin_university_person_path(person) %></td>
           <td>
             <%= kamifusen_tag person.best_picture,
                               width: 80 if person.best_picture.attached? %>
diff --git a/app/views/admin/university/alumni/experiences/_experience_fields.html.erb b/app/views/admin/university/people/experiences/_experience_fields.html.erb
similarity index 100%
rename from app/views/admin/university/alumni/experiences/_experience_fields.html.erb
rename to app/views/admin/university/people/experiences/_experience_fields.html.erb
diff --git a/app/views/admin/university/alumni/experiences/edit.html.erb b/app/views/admin/university/people/experiences/edit.html.erb
similarity index 66%
rename from app/views/admin/university/alumni/experiences/edit.html.erb
rename to app/views/admin/university/people/experiences/edit.html.erb
index 6e203626ca4e8a15ae479094e6f05bd3ea6fc4dc..8d3671123a7bb18b6c23981fd4ac09079726c282 100644
--- a/app/views/admin/university/alumni/experiences/edit.html.erb
+++ b/app/views/admin/university/people/experiences/edit.html.erb
@@ -1,14 +1,14 @@
-<% content_for :title, @alumnus %>
+<% content_for :title, @person %>
 
 <h2 class="h3"><%= University::Person::Experience.model_name.human(count: 2) %></h2>
 
-<%= simple_form_for [:admin, @alumnus], url: experiences_admin_university_alumnus_path(@alumnus) do |f| %>
+<%= simple_form_for [:admin, @person], url: experiences_admin_university_person_path(@person) do |f| %>
   <%= f.error_notification %>
   <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
 
   <div class="mb-3">
-    <%= link_to_add_association t('add'), 
-                                f, 
+    <%= link_to_add_association t('add'),
+                                f,
                                 :experiences,
                                 class: button_classes,
                                 data: {
@@ -18,8 +18,8 @@
   </div>
 
   <div id="experiences">
-    <%= f.simple_fields_for :experiences, @alumnus.experiences.ordered, include_id: false do |experience_f| %>
-      <%= render 'admin/university/alumni/experiences/experience_fields', f: experience_f, include_id: true %>
+    <%= f.simple_fields_for :experiences, @person.experiences.ordered, include_id: false do |experience_f| %>
+      <%= render 'admin/university/people/experiences/experience_fields', f: experience_f, include_id: true %>
     <% end %>
   </div>
 
diff --git a/app/views/admin/university/people/experiences/imports/index.html.erb b/app/views/admin/university/people/experiences/imports/index.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..c4b1abb8175721ea1323db70ad494d56f5466460
--- /dev/null
+++ b/app/views/admin/university/people/experiences/imports/index.html.erb
@@ -0,0 +1,12 @@
+<% content_for :title, t('university.person.experiences.title') %>
+
+<%= render 'filters', current_path: admin_university_people_experiences_imports_path, filters: @filters if @filters.any?  %>
+
+<%= render 'admin/imports/list', imports: @imports, path_pattern: 'admin_university_people_experiences_import_path' %>
+
+<% content_for :action_bar_right do %>
+  <%= link_to_if  can?(:create, University::Person::Experience),
+                  t('create'),
+                  new_admin_university_people_experiences_import_path,
+                  class: button_classes %>
+<% end %>
diff --git a/app/views/admin/university/alumni/experiences/imports/new.html.erb b/app/views/admin/university/people/experiences/imports/new.html.erb
similarity index 96%
rename from app/views/admin/university/alumni/experiences/imports/new.html.erb
rename to app/views/admin/university/people/experiences/imports/new.html.erb
index 88246e722177c3023cd9b609cbef6fd117c942b4..38a41bb9660fe2f4a09058c28ff04236749fce36 100644
--- a/app/views/admin/university/alumni/experiences/imports/new.html.erb
+++ b/app/views/admin/university/people/experiences/imports/new.html.erb
@@ -5,10 +5,10 @@
     <p>
       <%= t('imports.hint_html') %>
       <br>
-      <%= t('university.alumni.experiences.import_hint_html') %>
+      <%= t('university.person.experiences.import_hint_html') %>
     </p>
     <%= simple_form_for @import,
-                        url: admin_university_alumni_experiences_imports_path do |f| %>
+                        url: admin_university_people_experiences_imports_path do |f| %>
 
       <%= f.error_notification %>
       <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
diff --git a/app/views/admin/university/people/index.html.erb b/app/views/admin/university/people/index.html.erb
index df601c13f7ed7424fe37ef9a2f4e46cd067630ee..abb5ce6a2b3a1088433192174c6ce279e2cdc0e1 100644
--- a/app/views/admin/university/people/index.html.erb
+++ b/app/views/admin/university/people/index.html.erb
@@ -5,6 +5,12 @@
 <%= render 'admin/university/people/list', people: @people %>
 <%= paginate @people, theme: 'bootstrap-5' %>
 
+<% content_for :action_bar_left do %>
+  <%= link_to t('university.person.experiences.import_btn'),
+              new_admin_university_people_experiences_import_path,
+              class: button_classes if can? :create, University::Person::Experience %>
+<% end %>
+
 <% content_for :action_bar_right do %>
   <%= create_link University::Person %>
 <% end %>
diff --git a/app/views/admin/university/people/show.html.erb b/app/views/admin/university/people/show.html.erb
index 04860079369f4da22da092075addb163c770f325..485f258b582b51e840b49709353e2089e7ca5581 100644
--- a/app/views/admin/university/people/show.html.erb
+++ b/app/views/admin/university/people/show.html.erb
@@ -21,6 +21,16 @@
   </div>
 <% end %>
 
+<%
+action = ''
+action += link_to t('university.manage_experiences'),
+                  experiences_admin_university_person_path(@person),
+                  class: button_classes if can?(:update, @person)
+%>
+<%= osuny_panel University::Person::Experience.model_name.human(count: 2), action: action do %>
+  <%= render 'admin/university/people/experiences/list', experiences: @person.experiences.ordered %>
+<% end %>
+
 <% content_for :action_bar_left do %>
   <%= destroy_link @person %>
   <%= static_link static_admin_university_person_path(@person) %>
diff --git a/app/views/admin/application/_notice.html.erb b/app/views/application/_notice.html.erb
similarity index 100%
rename from app/views/admin/application/_notice.html.erb
rename to app/views/application/_notice.html.erb
diff --git a/app/views/extranet/layouts/application.html.erb b/app/views/extranet/layouts/application.html.erb
index 0f1ab358370cf60ee21669212d16bbf6d62324f4..8b20a64470b47db0a214116ba3c18c4e12a065a1 100644
--- a/app/views/extranet/layouts/application.html.erb
+++ b/app/views/extranet/layouts/application.html.erb
@@ -4,6 +4,7 @@
     <%= render 'extranet/application/head' %>
   </head>
   <body class="extranet <%= body_classes %> full-width">
+    <%= render 'application/notice' %>
     <%= render 'extranet/application/nav' %>
     <%= render 'extranet/application/header' %>
     <main class="container">
diff --git a/app/views/extranet/library/documents/index.html.erb b/app/views/extranet/library/documents/index.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..cb923255bbdfebac385474bb1feb9daba9141c9c
--- /dev/null
+++ b/app/views/extranet/library/documents/index.html.erb
@@ -0,0 +1,18 @@
+<% content_for :title, Communication::Extranet::Document.model_name.human(count: 2) %>
+
+<div class="row mt-n5">
+  <% @documents.each do |document| %>
+    <div class="col-lg-4">
+      <div class="position-relative mt-5">
+        <p class="mt-2">
+          <b><%= document %></b><br>
+          <span class="text-muted"><%= l document.published_at.to_date %><span>
+        </p>
+        <%= link_to t('extranet.library.download'), 
+                    document.file.url,
+                    class: 'btn btn-primary',
+                    target: :_blank if document.file.attached? %>
+      </div>
+    </div>
+  <% end %>
+</div>
\ No newline at end of file
diff --git a/app/views/server/layouts/application.html.erb b/app/views/server/layouts/application.html.erb
index fd3d6120b03f44e903b0d070519faffa5cdae7c9..11b3a9e841fad85e728205ea3838967cb332f502 100644
--- a/app/views/server/layouts/application.html.erb
+++ b/app/views/server/layouts/application.html.erb
@@ -15,7 +15,7 @@
   <body class="<%= body_classes %>">
     <%= render "admin/layouts/themes/pure/nav", context: :server %>
     <%= render "admin/layouts/themes/pure/hero" %>
-    <%= render 'admin/application/notice' %>
+    <%= render 'application/notice' %>
     <main class="container-fluid">
       <% unless current_user.confirmed? %>
         <div class="alert alert-warning">
diff --git a/config/extranet_navigation.rb b/config/extranet_navigation.rb
index cf5443b548a1be0995a7a3494d2070dd038771dc..c1ee40b667553b847577978c9e38e29e0b3af3ba 100644
--- a/config/extranet_navigation.rb
+++ b/config/extranet_navigation.rb
@@ -6,9 +6,14 @@ SimpleNavigation::Configuration.run do |navigation|
   navigation.items do |primary|
     primary.item      :posts,
                       Communication::Extranet.human_attribute_name(:feature_posts),
-                      posts_root_path if current_extranet.feature_posts
+                      posts_root_path if current_extranet.feature_posts?
 
-    primary.item :contacts, Communication::Extranet.human_attribute_name(:feature_contacts) do |secondary|
+    primary.item      :library,
+                      Communication::Extranet.human_attribute_name(:feature_library),
+                      library_root_path if current_extranet.feature_library?
+
+    primary.item      :contacts, 
+                      Communication::Extranet.human_attribute_name(:feature_contacts) do |secondary|
       secondary.item  :person,
                       University::Person.model_name.human(count: 2),
                       contacts_university_persons_path
@@ -17,7 +22,8 @@ SimpleNavigation::Configuration.run do |navigation|
                       contacts_university_organizations_path
     end if current_extranet.feature_contacts?
 
-    primary.item :alumni, University::Person::Alumnus.model_name.human(count: 2) do |secondary|
+    primary.item      :alumni, 
+                      University::Person::Alumnus.model_name.human(count: 2) do |secondary|
       secondary.item  :person,
                       University::Person.model_name.human(count: 2),
                       alumni_university_persons_path
diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml
index fcd096d8f4c320559d4999328f1e52d6bdb512e7..0f4b689b9124ec29809b9d8a6b0e906148b9d48a 100644
--- a/config/locales/communication/en.yml
+++ b/config/locales/communication/en.yml
@@ -12,6 +12,9 @@ en:
       communication/extranet:
         one: Extranet
         other: Extranets
+      communication/extranet/document:
+        one: Document
+        other: Documents
       communication/extranet/post:
         one: Post
         other: Posts
@@ -59,10 +62,10 @@ en:
         description: Espaces d'échanges sécurisés dédiés aux personnes authentifiées
         favicon: Favicon (.png)
         feature_alumni: Alumni
-        feature_assets: Asset management
         feature_contacts: Directory
-        feature_posts: News
         feature_jobs: Job board
+        feature_library: Documents
+        feature_posts: News
         has_sso: Has SSO?
         home_sentence: Sentence displayed on homepage
         host: Domain
@@ -78,6 +81,10 @@ en:
         sso_name_identifier_format: Name Identifier Format
         sso_target_url: Target URL
         terms: Terms of service
+      communication/extranet/document:
+        name: Name
+        published: Published?
+        published_at: Publication date
       communication/extranet/post:
         author: Author
         featured_image: Featured image
diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml
index 7594a214c5c2ccad3644588257f5c28a02e6ac7e..007f913905480ce036ec8af0ad53005cc446d908 100644
--- a/config/locales/communication/fr.yml
+++ b/config/locales/communication/fr.yml
@@ -12,6 +12,9 @@ fr:
       communication/extranet:
         one: Extranet
         other: Extranets
+      communication/extranet/document:
+        one: Document
+        other: Documents
       communication/extranet/post:
         one: Actualité
         other: Actualités
@@ -59,10 +62,10 @@ fr:
         description: Espaces d'échanges sécurisés dédiés aux personnes authentifiées
         favicon: Favicon (.png)
         feature_alumni: Alumni
-        feature_assets: Gestion de fichiers
         feature_contacts: Annuaire
-        feature_posts: Actualités
         feature_jobs: Offres d'emploi
+        feature_library: Documents
+        feature_posts: Actualités
         has_sso: A un SSO ?
         home_sentence: Phrase affichée sur la home
         host: Domaine
@@ -78,6 +81,10 @@ fr:
         sso_name_identifier_format: Name Identifier Format
         sso_target_url: URL cible
         terms: Conditions d'utilisation
+      communication/extranet/document:
+        name: Nom
+        published: Publié ?
+        published_at: Date de publication
       communication/extranet/post:
         author: Auteur·rice
         featured_image: Image à la une
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 532844c10cdc8e5f195020193a84ec7ca872bc66..56de4b0f1de4e3d1c3fffac4742cb6e1bf294c56 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -105,6 +105,7 @@ en:
       label: Background tasks pending
       hint: Those tasks precompute your data in order to minimize its carbon footprint. It creates a delay before your changes are online.
     password_hint: Leave blank if you do not wish to change the password.
+    seo: SEO
     successfully_created_html: "<i>%{model}</i> was successfully created."
     successfully_destroyed_html: "<i>%{model}</i> was successfully destroyed."
     successfully_duplicated_html: "<i>%{model}</i> was successfully duplicated."
diff --git a/config/locales/extranet/en.yml b/config/locales/extranet/en.yml
index 60a20170038d89ef0a73529fb54867e549f29ea4..fb877a0b81a1a8e13a913c766b1ee9b417e7e671 100644
--- a/config/locales/extranet/en.yml
+++ b/config/locales/extranet/en.yml
@@ -25,6 +25,8 @@ en:
       recent_cohorts: Recent cohorts
       recent_experiences: Recent experiences
       welcome: Welcome!
+    library:
+      download: Download
     menu: Menu
     organization:
       experiences: Alumni in this organization (%{count})
diff --git a/config/locales/extranet/fr.yml b/config/locales/extranet/fr.yml
index e00a646cf5b9a5d41ce5ac368266f9ec1b6dbfdc..87fcc92b5e502247244bb5761ce3c12ede289ffd 100644
--- a/config/locales/extranet/fr.yml
+++ b/config/locales/extranet/fr.yml
@@ -25,6 +25,8 @@ fr:
       recent_cohorts: Promotions récentes
       recent_experiences: Mouvements récents
       welcome: Bienvenue !
+    library:
+      download: Télécharger
     menu: Menu
     organization:
       experiences: Alumni dans cette organisation (%{count})
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index ba028427c365e4174f854e6f32431cb116fc07e8..711fa805dbedff947b0f666147be92f0b97f1ddb 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -105,6 +105,7 @@ fr:
       label: Tâches en cours de traitement
       hint: L'exécution de ces tâches contribue à diminuer l'empreinte carbone du numérique, en précalculant ce qui peut l'être. Cela peut générer un délai avant que vos modifications ne soient visibles.
     password_hint: Laissez vide si vous ne souhaitez pas modifier le mot de passe.
+    seo: SEO
     successfully_created_html: "<i>%{model}</i> a bien été créé(e)."
     successfully_destroyed_html: "<i>%{model}</i> a bien été détruit(e)."
     successfully_duplicated_html: "<i>%{model}</i> a bien été dupliqué(e)."
@@ -202,7 +203,7 @@ fr:
   imports:
     error_msg: "Ligne %{line} : %{error}"
     errors: Erreurs
-    hint_html: "Les données doivent être au format xlsx.<br>La première ligne doit être dédiée aux entêtes.<br>Les noms des entêtes sont obligatoires et doivent être respectés strictement.<br>Les caractères doivent être encodés en UTF-8.<br>Les champs marqués d'une astérisque sont obligatoires."
+    hint_html: "Les données doivent être au format xlsx.<br>La première ligne doit être dédiée aux en-têtes.<br>Les noms des entêtes sont obligatoires et doivent être respectés strictement.<br>Les caractères doivent être encodés en UTF-8.<br>Les champs marqués d'une astérisque sont obligatoires."
     initiated_by: "Initié par :"
     number_of_lines: "Nombre de lignes dans le fichier :"
     status: "Status :"
diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml
index b71021709b80578c36b747a0c278993028422419..1958db7928d4368fc45c70cc5542c3b85ceb0ee4 100644
--- a/config/locales/university/en.yml
+++ b/config/locales/university/en.yml
@@ -188,10 +188,6 @@ en:
         import_btn: Import cohorts
         import_hint_html: "Possible values for <i>gender</i> are: m (male), f (female) and n (non binary).<br><i>Phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> and <i>zipcode</i> fields must have a text format, not numbers.<br><i>Country</i> field must contain the ISO 3166 code of the country, so 2 upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>).<br><i>Social_twitter</i> field should have no @.<br><i>School</i> field should contain the internal school id.<br><i>Program</i> field should contain the internal program id."
         title: Cohorts imports
-      experiences:
-        import_btn: Import experiences
-        import_hint_html: "Possible values for <i>gender</i> are: m (male), f (female) and n (non binary).<br><i>Phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> and <i>zipcode</i> fields must have a text format, not numbers.<br><i>Country</i> field must contain the ISO 3166 code of the country, so 2 upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>).<br><i>Social_twitter</i> field should have no @."
-        title: Experiences imports
     description:
       text: Une université est une institution d'enseignement supérieur, d'étude et de recherche, constituée par la réunion de divers établissements nommés suivant les traditions “collèges”, “facultés”, “instituts”, “départements”, “centres”, “sections”, “unités” ou écoles spécifiques, mais aussi bibliothèque ou atelier, médiathèque ou musée, etc. formant un ensemble administratif cohérent avec un statut de droit défini, public, privé ou éventuellement mixte.
       source: Wikipedia
@@ -210,6 +206,10 @@ en:
         no_organization_hint_html: "If the organization is not in the list, you can <a href=\"%{url}\">create it</a>"
         no_organization_hint_no_access_html: "If the organization is not in the list, you should ask to create it"
         period: Period
+      experiences:
+        import_btn: Import experiences
+        import_hint_html: "Possible values for <i>gender</i> are: m (male), f (female) and n (non binary).<br><i>Phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> and <i>zipcode</i> fields must have a text format, not numbers.<br><i>Country</i> field must contain the ISO 3166 code of the country, so 2 upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>).<br><i>Social_twitter</i> field should have no @."
+        title: Experiences imports
       personal_data_warning: Warning! The information provided below can be publicly visible on the websites and the extranets about you.
       taught_programs: Taught programs
     sso: SSO
diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml
index 8214f25cd9d402d78a1fbc9b3e43e5651ab27f36..bec6dcddafad2f5715b4fcb1e02d19bce32c0f9d 100644
--- a/config/locales/university/fr.yml
+++ b/config/locales/university/fr.yml
@@ -188,10 +188,6 @@ fr:
         import_btn: Importer des promotions
         import_hint_html: "Les valeurs pour <i>gender</i> peuvent être m (masculin), f (féminin) et n (non binaire).<br>Les champs <i>phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> et <i>zipcode</i> doivent être au format texte, pas nombre.<br>Le champ <i>country</i> doit contenir le code ISO 3166 du pays, sur 2 caratères en majuscule (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">liste</a>)<br>Le champ <i>social_twitter</i> ne doit pas contenir d'@.<br>Le champ <i>school</i> doit contenir l'id interne de l'école.<br>Le champ <i>program</i> doit contenir l'id interne de la formation."
         title: Imports de promotions
-      experiences:
-        import_btn: Importer des expériences
-        import_hint_html: "Les valeurs pour <i>gender</i> peuvent être m (masculin), f (féminin) et n (non binaire).<br>Les champs <i>phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> et <i>zipcode</i> doivent être au format texte, pas nombre.<br>Le champ <i>country</i> doit contenir le code ISO 3166 du pays, sur 2 caratères en majuscule (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">liste</a>)<br>Le champ <i>social_twitter</i> ne doit pas contenir d'@."
-        title: Imports d'expériences
     description:
       text: Une université est une institution d'enseignement supérieur, d'étude et de recherche, constituée par la réunion de divers établissements nommés suivant les traditions “collèges”, “facultés”, “instituts”, “départements”, “centres”, “sections”, “unités” ou écoles spécifiques, mais aussi bibliothèque ou atelier, médiathèque ou musée, etc. formant un ensemble administratif cohérent avec un statut de droit défini, public, privé ou éventuellement mixte.
       source: Wikipedia
@@ -210,6 +206,10 @@ fr:
         no_organization_hint_html: "Si l'entreprise n'apparait pas dans la liste, vous pouvez la <a href=\"%{url}\">créer</a>"
         no_organization_hint_no_access_html: "Si l'entreprise n'apparait pas dans la liste, il faut demander à la créer"
         period: Période
+      experiences:
+        import_btn: Importer des expériences
+        import_hint_html: "Les valeurs pour <i>gender</i> peuvent être m (masculin), f (féminin) et n (non binaire).<br>Les champs <i>phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> et <i>zipcode</i> doivent être au format texte, pas nombre.<br>Le champ <i>country</i> doit contenir le code ISO 3166 du pays, sur 2 caratères en majuscule (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">liste</a>)<br>Le champ <i>social_twitter</i> ne doit pas contenir d'@."
+        title: Imports d'expériences
       personal_data_warning: Attention ! Les informations renseignées ici sont susceptibles d'être visibles publiquement sur les sites web et les extranets vous concernant.
       taught_programs: Formations enseignées
     sso: SSO
diff --git a/config/routes/admin/communication.rb b/config/routes/admin/communication.rb
index 198e624b8ce0ef3a0b41a1460d7e6b7637faf89c..b9e462905f3284ebe3bc4e70198e8228ea2e33ad 100644
--- a/config/routes/admin/communication.rb
+++ b/config/routes/admin/communication.rb
@@ -78,8 +78,10 @@ namespace :communication do
         get :preview
       end
     end
-    resources :assets, only: :index, controller: 'extranets/assets'
-    resources :jobs, only: :index, controller: 'extranets/jobs'
+    # Automatic routes based on feature names
+    get 'library' => 'extranets/documents#index', as: :library
+    resources :documents, controller: 'extranets/documents'
+    resources :jobs, controller: 'extranets/jobs'
   end
   resources :alumni do
     collection do
diff --git a/config/routes/admin/university.rb b/config/routes/admin/university.rb
index e7db269e913d25c0cb96d4403594b88023e81f4b..8a573a0a173b23a2f24c546b7bd5582f2a936e1e 100644
--- a/config/routes/admin/university.rb
+++ b/config/routes/admin/university.rb
@@ -7,22 +7,24 @@ namespace :university do
     namespace :cohorts do
       resources :imports, only: [:index, :show, :new, :create]
     end
-    namespace :experiences do
-      resources :imports, only: [:index, :show, :new, :create]
-    end
   end
   resources :alumni, only: [:index, :show] do
     member do
       get 'cohorts' => 'alumni/cohorts#edit'
       patch 'cohorts' => 'alumni/cohorts#update'
-      get 'experiences' => 'alumni/experiences#edit'
-      patch 'experiences' => 'alumni/experiences#update'
     end
   end
   resources :people do
     member do
       get :static
       get "/translations/:lang" => "people#in_language", as: :show_in_language
+      get 'experiences' => 'people/experiences#edit'
+      patch 'experiences' => 'people/experiences#update'
+    end
+  end
+  namespace :people do
+    namespace :experiences do
+      resources :imports, only: [:index, :show, :new, :create]
     end
   end
   resources :organizations do
diff --git a/config/routes/extranet.rb b/config/routes/extranet.rb
index 8c4e91623ece2aaead60ed2da519048895f3d157..33ef5dcb5825064d32fd1b23c3d121f256a07b05 100644
--- a/config/routes/extranet.rb
+++ b/config/routes/extranet.rb
@@ -23,6 +23,9 @@ namespace :posts do
   get ':slug' => 'posts#show', as: :communication_extranet_post
   root to: 'posts#index'
 end
+namespace :library do
+  root to: 'documents#index'
+end
 get 'account' => 'account#show', as: :account
 get 'account/edit' => 'account#edit', as: :edit_account
 patch 'account' => 'account#update'
diff --git a/db/migrate/20230308155237_create_communication_extranet_files.rb b/db/migrate/20230308155237_create_communication_extranet_files.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2399d634523d243ab50a5e7257e993f2c5066106
--- /dev/null
+++ b/db/migrate/20230308155237_create_communication_extranet_files.rb
@@ -0,0 +1,15 @@
+class CreateCommunicationExtranetFiles < ActiveRecord::Migration[7.0]
+  def change
+    rename_column :communication_extranets, :feature_assets, :feature_files
+
+    create_table :communication_extranet_files, id: :uuid do |t|
+      t.string :name
+      t.references :university, null: false, foreign_key: true, type: :uuid
+      t.references :extranet, null: false, foreign_key: {to_table: :communication_extranets}, type: :uuid
+      t.boolean :published
+      t.datetime :published_at
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20230309111101_rename_extranet_files_to_library.rb b/db/migrate/20230309111101_rename_extranet_files_to_library.rb
new file mode 100644
index 0000000000000000000000000000000000000000..51d5a3bb81abcf30bbb325d58b6bd74519353c95
--- /dev/null
+++ b/db/migrate/20230309111101_rename_extranet_files_to_library.rb
@@ -0,0 +1,6 @@
+class RenameExtranetFilesToLibrary < ActiveRecord::Migration[7.0]
+  def change
+    rename_column :communication_extranets, :feature_files, :feature_library
+    rename_table :communication_extranet_files, :communication_extranet_documents
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 5286da914d2d13c38b8a0bc431f145081b9bf9db..a6e4c7da3607d29bc7790e3ccc1c8c3dfb5533d1 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.0].define(version: 2023_03_08_101244) do
+ActiveRecord::Schema[7.0].define(version: 2023_03_09_111101) do
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
   enable_extension "plpgsql"
@@ -105,6 +105,18 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_08_101244) do
     t.index ["university_id"], name: "index_communication_extranet_connections_on_university_id"
   end
 
+  create_table "communication_extranet_documents", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+    t.string "name"
+    t.uuid "university_id", null: false
+    t.uuid "extranet_id", null: false
+    t.boolean "published"
+    t.datetime "published_at"
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
+    t.index ["extranet_id"], name: "index_communication_extranet_documents_on_extranet_id"
+    t.index ["university_id"], name: "index_communication_extranet_documents_on_university_id"
+  end
+
   create_table "communication_extranet_posts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
     t.string "title"
     t.boolean "published", default: false
@@ -145,7 +157,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_08_101244) do
     t.string "sso_button_label"
     t.boolean "feature_alumni", default: false
     t.boolean "feature_contacts", default: false
-    t.boolean "feature_assets", default: false
+    t.boolean "feature_library", default: false
     t.boolean "feature_posts", default: false
     t.boolean "feature_jobs", default: false
     t.text "home_sentence"
@@ -974,6 +986,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_08_101244) do
   add_foreign_key "communication_blocks", "universities"
   add_foreign_key "communication_extranet_connections", "communication_extranets", column: "extranet_id"
   add_foreign_key "communication_extranet_connections", "universities"
+  add_foreign_key "communication_extranet_documents", "communication_extranets", column: "extranet_id"
+  add_foreign_key "communication_extranet_documents", "universities"
   add_foreign_key "communication_extranet_posts", "communication_extranets", column: "extranet_id"
   add_foreign_key "communication_extranet_posts", "universities"
   add_foreign_key "communication_extranet_posts", "university_people", column: "author_id"
diff --git a/test/fixtures/communication/extranet/documents.yml b/test/fixtures/communication/extranet/documents.yml
new file mode 100644
index 0000000000000000000000000000000000000000..be1d0d6ab57326b590356596a4609a335ddd6e69
--- /dev/null
+++ b/test/fixtures/communication/extranet/documents.yml
@@ -0,0 +1,37 @@
+# == Schema Information
+#
+# Table name: communication_extranet_documents
+#
+#  id            :uuid             not null, primary key
+#  name          :string
+#  published     :boolean
+#  published_at  :datetime
+#  created_at    :datetime         not null
+#  updated_at    :datetime         not null
+#  extranet_id   :uuid             not null, indexed
+#  university_id :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_communication_extranet_documents_on_extranet_id    (extranet_id)
+#  index_communication_extranet_documents_on_university_id  (university_id)
+#
+# Foreign Keys
+#
+#  fk_rails_1272fd263c  (extranet_id => communication_extranets.id)
+#  fk_rails_af877a8c0c  (university_id => universities.id)
+#
+
+one:
+  name: MyString
+  university: one
+  extranet: one
+  published: false
+  published_at: 2023-03-08 16:55:05
+
+two:
+  name: MyString
+  university: two
+  extranet: two
+  published: false
+  published_at: 2023-03-08 16:55:05
diff --git a/test/fixtures/communication/extranets.yml b/test/fixtures/communication/extranets.yml
index 32d364d3e55c226aa13e6fcacf8c069de294cc3e..c4a72564511a4905256b44eff1b90d9ad95d76db 100644
--- a/test/fixtures/communication/extranets.yml
+++ b/test/fixtures/communication/extranets.yml
@@ -8,9 +8,9 @@
 #  cookies_policy             :text
 #  css                        :text
 #  feature_alumni             :boolean          default(FALSE)
-#  feature_assets             :boolean          default(FALSE)
 #  feature_contacts           :boolean          default(FALSE)
 #  feature_jobs               :boolean          default(FALSE)
+#  feature_library            :boolean          default(FALSE)
 #  feature_posts              :boolean          default(FALSE)
 #  has_sso                    :boolean          default(FALSE)
 #  home_sentence              :text
diff --git a/test/models/communication/extranet/file_test.rb b/test/models/communication/extranet/file_test.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4cc52fa6ea798522faf62a68747a3d240f48eca0
--- /dev/null
+++ b/test/models/communication/extranet/file_test.rb
@@ -0,0 +1,30 @@
+# == Schema Information
+#
+# Table name: communication_extranet_files
+#
+#  id            :uuid             not null, primary key
+#  name          :string
+#  published     :boolean
+#  published_at  :datetime
+#  created_at    :datetime         not null
+#  updated_at    :datetime         not null
+#  extranet_id   :uuid             not null, indexed
+#  university_id :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_communication_extranet_files_on_extranet_id    (extranet_id)
+#  index_communication_extranet_files_on_university_id  (university_id)
+#
+# Foreign Keys
+#
+#  fk_rails_1272fd263c  (extranet_id => communication_extranets.id)
+#  fk_rails_af877a8c0c  (university_id => universities.id)
+#
+require "test_helper"
+
+class Communication::Extranet::FileTest < ActiveSupport::TestCase
+  # test "the truth" do
+  #   assert true
+  # end
+end
diff --git a/test/models/communication/extranet_test.rb b/test/models/communication/extranet_test.rb
index 504f037d0f2ffdab7721c74bf3d60750bac26cf8..72be11939515c0927e5c3266698692eae000ee5a 100644
--- a/test/models/communication/extranet_test.rb
+++ b/test/models/communication/extranet_test.rb
@@ -8,9 +8,9 @@
 #  cookies_policy             :text
 #  css                        :text
 #  feature_alumni             :boolean          default(FALSE)
-#  feature_assets             :boolean          default(FALSE)
 #  feature_contacts           :boolean          default(FALSE)
 #  feature_jobs               :boolean          default(FALSE)
+#  feature_library            :boolean          default(FALSE)
 #  feature_posts              :boolean          default(FALSE)
 #  has_sso                    :boolean          default(FALSE)
 #  home_sentence              :text