diff --git a/app/models/research/journal/article.rb b/app/models/research/journal/article.rb
index 56d568e4ef621fc9916eef717eeef382f2a4c9a0..9adf754d3de4be0b3168e0b8e0d6e3855eaa6c6b 100644
--- a/app/models/research/journal/article.rb
+++ b/app/models/research/journal/article.rb
@@ -29,7 +29,16 @@ class Research::Journal::Article < ApplicationRecord
   belongs_to :journal, foreign_key: :research_journal_id
   belongs_to :volume, foreign_key: :research_journal_volume_id, optional: true
 
+  after_save :publish_to_github
+
   def to_s
     "#{ title }"
   end
+
+  protected
+
+  def publish_to_github
+    return if journal.repository.blank?
+    Github.publish_article self
+  end
 end
diff --git a/app/models/research/journal/volume.rb b/app/models/research/journal/volume.rb
index 38b1f2cdcc15f5d448fb2e9a90fd9913b8db4890..39fc7f41a2b6c2f6d1a0d06548a57d0bc16c9909 100644
--- a/app/models/research/journal/volume.rb
+++ b/app/models/research/journal/volume.rb
@@ -26,7 +26,7 @@ class Research::Journal::Volume < ApplicationRecord
   belongs_to :journal, foreign_key: :research_journal_id
   has_many :articles, foreign_key: :research_journal_volume_id
 
-  after_save :publish
+  after_save :publish_to_github
 
   def to_s
     "##{ number } #{ title }"
@@ -34,25 +34,8 @@ class Research::Journal::Volume < ApplicationRecord
 
   protected
 
-  def publish
+  def publish_to_github
     return if journal.repository.blank?
-    data = "---\ntitle: #{ title }\nnumber: #{number}\n---"
-    directory = "tmp/volumes"
-    FileUtils.mkdir_p directory
-    local_file = "#{directory}/#{id}.md"
-    File.write local_file, data
-    remote_file = "_volumes/#{id}.md"
-    client = Octokit::Client.new access_token: journal.access_token
-    begin
-      content = client.content journal.repository, path: remote_file
-      sha = content[:sha]
-    rescue
-      sha = nil
-    end
-    client.create_contents  journal.repository,
-                            remote_file,
-                            "Save volume #{ title }",
-                            file: local_file,
-                            sha: sha
+    Github.publish_volume self
   end
 end
diff --git a/app/services/github.rb b/app/services/github.rb
new file mode 100644
index 0000000000000000000000000000000000000000..908094fb8130308e31c50b67d964f85fa6532c76
--- /dev/null
+++ b/app/services/github.rb
@@ -0,0 +1,58 @@
+class Github
+  attr_reader :access_token, :repository
+
+  def self.publish_article(article)
+    with_journal(article.journal).publish_article(article)
+  end
+
+  def self.publish_volume(volume)
+    with_journal(volume.journal).publish_volume(volume)
+  end
+
+  def self.with_journal(journal)
+    new(journal.access_token, journal.repository)
+  end
+
+  def initialize(access_token, repository)
+    @access_token = access_token
+    @repository = repository
+  end
+
+  def publish_article(article)
+    publish local_directory: "tmp/articles",
+            local_file: "#{article.id}.md",
+            data: "---\ntitle: #{ article.title }\n\n---\n#{ article.text }",
+            remote_file: "_articles/#{article.id}.md",
+            commit_message: "Save article #{ article.title }"
+  end
+
+  def publish_volume(volume)
+    publish local_directory: "tmp/volumes",
+            local_file: "#{volume.id}.md",
+            data: "---\ntitle: #{ volume.title }\nnumber: #{ volume.number }\n---",
+            remote_file: "_volumes/#{volume.id}.md",
+            commit_message: "Save volume #{ volume.title }"
+  end
+
+  def publish(local_directory:, local_file:, data:, remote_file:, commit_message:)
+    FileUtils.mkdir_p local_directory
+    local_path = "#{local_directory}/#{ local_file }"
+    File.write local_path, data
+    begin
+      content = client.content repository, path: remote_file
+      sha = content[:sha]
+    rescue
+      sha = nil
+    end
+    client.create_contents  repository,
+                            remote_file,
+                            commit_message,
+                            file: local_path,
+                            sha: sha
+
+  end
+
+  def client
+    @client ||= Octokit::Client.new access_token: access_token
+  end
+end
diff --git a/app/views/admin/research/journal/articles/_form.html.erb b/app/views/admin/research/journal/articles/_form.html.erb
index 9e61c6117d4585cf9db0b4bc49b51679ffb4dcab..c78e3e4eda560cf3ff58af08c94a089fb3233f40 100644
--- a/app/views/admin/research/journal/articles/_form.html.erb
+++ b/app/views/admin/research/journal/articles/_form.html.erb
@@ -6,7 +6,7 @@
       <%= f.input :published_at, html5: true %>
     </div>
     <div class="col-md-8">
-      <%= f.input :text, input_html: { rows: 100 } %>
+      <%= f.input :text, input_html: { rows: 30 } %>
     </div>
   </div>
   <% content_for :buttons do %>
diff --git a/app/views/admin/research/journals/show.html.erb b/app/views/admin/research/journals/show.html.erb
index 01840bc0c4685c5c2d18f58456c10023a24f9c9b..ab48f259c99252e3a994891a432cdb11e056b403 100644
--- a/app/views/admin/research/journals/show.html.erb
+++ b/app/views/admin/research/journals/show.html.erb
@@ -19,6 +19,23 @@
   <% end %>
 </div>
 
+<h2 class="mt-5"><%= Research::Journal::Article.model_name.human(count: 2) %></h2>
+
+<%= link_to t('create'),
+            new_admin_research_journal_article_path(journal_id: @journal),
+            class: button_classes %>
+
+<%= link_to 'Tous les articles',
+            admin_research_journal_articles_path(journal_id: @journal) %>
+
+<div class="row">
+  <% @journal.articles.each do |article| %>
+    <div class="col-md-3 mt-4">
+      <%= link_to article, admin_research_journal_article_path(journal_id: @journal, id: article) %>
+    </div>
+  <% end %>
+</div>
+
 <% content_for :buttons do %>
   <%= edit_link @journal %>
 <% end %>