diff --git a/app/controllers/dashboard/application_controller.rb b/app/controllers/dashboard/application_controller.rb
index 80c65948fff14348c7d161f1b52310433e8bbd77..d035a67d9b5335ddf5603c865f5030ce99cfdcf1 100644
--- a/app/controllers/dashboard/application_controller.rb
+++ b/app/controllers/dashboard/application_controller.rb
@@ -11,7 +11,7 @@ class Dashboard::ApplicationController < ApplicationController
   private
 
   def projects
-    @projects ||= current_user.authorized_projects.sorted_by_updated_desc.non_archived
+    @projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
   end
 end
 
diff --git a/app/models/project.rb b/app/models/project.rb
index 7f1c3cd475c2f31f5e02a6974870d435978900ab..5e17fe6bc4f091eba920f43b00b6297c67f9000e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -107,6 +107,9 @@ class Project < ApplicationRecord
     snippets: gitlab_config_features.snippets
   }.freeze
 
+  # List of attributes that, when updated, should be considered as Project Activity
+  PROJECT_ACTIVITY_ATTRIBUTES = %w[description name].freeze
+
   cache_markdown_field :description, pipeline: :description
 
   attribute :packages_enabled, default: true
@@ -132,6 +135,7 @@ class Project < ApplicationRecord
   before_validation :ensure_project_namespace_in_sync
   before_validation :set_package_registry_access_level, if: :packages_enabled_changed?
   before_validation :remove_leading_spaces_on_name
+  before_validation :set_last_activity_at
   after_validation :check_pending_delete
   before_save :ensure_runners_token
 
@@ -630,8 +634,9 @@ def self.integration_association_name(name)
         .or(arel_table[:storage_version].eq(nil)))
   end
 
-  scope :sorted_by_updated_asc, -> { reorder(self.arel_table['updated_at'].asc) }
-  scope :sorted_by_updated_desc, -> { reorder(self.arel_table['updated_at'].desc) }
+  scope :sorted_by_activity, -> { reorder(self.arel_table['last_activity_at'].desc) }
+  scope :sorted_by_updated_asc, -> { reorder(self.arel_table['last_activity_at'].asc) }
+  scope :sorted_by_updated_desc, -> { reorder(self.arel_table['last_activity_at'].desc) }
   scope :sorted_by_stars_desc, -> { reorder(self.arel_table['star_count'].desc) }
   scope :sorted_by_stars_asc, -> { reorder(self.arel_table['star_count'].asc) }
   scope :sorted_by_path_asc, -> { reorder(self.arel_table['path'].asc) }
@@ -1676,10 +1681,6 @@ def last_activity
     last_event
   end
 
-  def last_activity_date
-    updated_at
-  end
-
   def project_id
     self.id
   end
@@ -3357,7 +3358,7 @@ def repository_with_same_path_already_exists?
   end
 
   def set_timestamps_for_create
-    update_columns(last_activity_at: self.created_at, last_repository_updated_at: self.created_at)
+    update_columns(last_repository_updated_at: self.created_at)
   end
 
   def cross_namespace_reference?(from)
@@ -3501,6 +3502,16 @@ def remove_leading_spaces_on_name
     name&.lstrip!
   end
 
+  def set_last_activity_at
+    return if last_activity_at_changed?
+
+    if new_record? || (changed & PROJECT_ACTIVITY_ATTRIBUTES).any?
+      self.last_activity_at = Time.current
+    elsif last_activity_at.nil?
+      self.last_activity_at = created_at
+    end
+  end
+
   def set_package_registry_access_level
     return if !project_feature || project_feature.package_registry_access_level_changed?
 
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index 5bb15c2f5ca56f4123ecdc17db11e5a4fb095cb9..5e60e66bf844523220afdfe89e5988000ec4faf8 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -9,7 +9,7 @@
 - compact_mode = false unless local_assigns[:compact_mode] == true
 - show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true && can_show_last_commit_in_list?(project)
 - css_class = "gl-sm-display-flex gl-align-items-center gl-vertical-align-middle!" if project.description.blank? && !show_last_commit_as_description
-- updated_tooltip = time_ago_with_tooltip(project.last_activity_date)
+- updated_tooltip = time_ago_with_tooltip(project.last_activity_at || project.updated_at)
 - show_pipeline_status_icon = pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project)
 - last_pipeline = last_pipeline_from_status_cache(project) if show_pipeline_status_icon
 - css_controls_class = "with-pipeline-status" if show_pipeline_status_icon && last_pipeline.present?
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb
index 68ae1ca218bf41d2a0096497fc72917ac00bfa53..273b96526958571a14ca6c47cd5a46ca3b54745f 100644
--- a/spec/controllers/explore/projects_controller_spec.rb
+++ b/spec/controllers/explore/projects_controller_spec.rb
@@ -75,9 +75,9 @@
       end
 
       context 'projects aimed for deletion' do
-        let(:project1) { create(:project, :public, updated_at: 3.days.ago) }
-        let(:project2) { create(:project, :public, updated_at: 1.day.ago) }
-        let(:aimed_for_deletion_project) { create(:project, :public, :archived, updated_at: 2.days.ago, marked_for_deletion_at: 2.days.ago) }
+        let_it_be(:project1) { create(:project, :public, path: 'project-1') }
+        let_it_be(:project2) { create(:project, :public, path: 'project-2') }
+        let_it_be(:aimed_for_deletion_project) { create(:project, :public, :archived, marked_for_deletion_at: 2.days.ago) }
 
         before do
           create(:trending_project, project: project1)
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index e9b55ab2900d77c9fa5aa35ff87e653cb15d6deb..bd878c5e3ab2cde9b78d4bc5dfb46e37c36b4866 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -54,15 +54,7 @@
     end
   end
 
-  context 'when last_repository_updated_at, last_activity_at and update_at are present' do
-    it 'shows the last_repository_updated_at attribute as the update date' do
-      project.update!(last_repository_updated_at: Time.zone.now, last_activity_at: 1.hour.ago)
-
-      visit dashboard_projects_path
-
-      expect(page).to have_xpath("//time[@datetime='#{project.last_repository_updated_at.getutc.iso8601}']")
-    end
-
+  context 'when last_activity_at and update_at are present' do
     it 'shows the last_activity_at attribute as the update date' do
       project.update!(last_repository_updated_at: 1.hour.ago, last_activity_at: Time.zone.now)
 
@@ -72,9 +64,9 @@
     end
   end
 
-  context 'when last_repository_updated_at and last_activity_at are missing' do
+  context 'when last_activity_at is missing' do
     it 'shows the updated_at attribute as the update date' do
-      project.update!(last_repository_updated_at: nil, last_activity_at: nil)
+      project.update!(last_activity_at: nil)
       project.touch
 
       visit dashboard_projects_path
diff --git a/spec/finders/namespaces/projects_finder_spec.rb b/spec/finders/namespaces/projects_finder_spec.rb
index 10d8145d15ac2be3b31c1f90bf9d530479f7c5f8..64fb45940d3515f26d4ab060a4de57ba448c83fb 100644
--- a/spec/finders/namespaces/projects_finder_spec.rb
+++ b/spec/finders/namespaces/projects_finder_spec.rb
@@ -144,6 +144,7 @@
         let(:params) { { sort: :latest_activity_desc } }
 
         before do
+          project_7.update!(last_activity_at: 20.minutes.ago)
           project_6.update!(last_activity_at: 15.minutes.ago)
           project_2.update!(last_activity_at: 10.minutes.ago)
           project_1.update!(last_activity_at: 5.minutes.ago)
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 6eb69bf958a6e41dffe934227f7407c6e620082c..fa7468655197fef03bf9f52685989296df17ad1a 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -31,15 +31,22 @@
 
     describe 'after_create :set_last_repository_updated_at' do
       context 'with a push event' do
-        it 'updates the project last_repository_updated_at and updated_at' do
-          project.touch(:last_repository_updated_at, time: 1.year.ago)
+        it 'updates the project last_repository_updated_at' do
+          project.update!(last_repository_updated_at: 1.year.ago)
 
           event = create_push_event(project, project.first_owner)
 
           project.reload
 
           expect(project.last_repository_updated_at).to be_like_time(event.created_at)
-          expect(project.updated_at).to be_like_time(event.created_at)
+        end
+
+        it 'calls the reset_project_activity method' do
+          expect_next_instance_of(described_class) do |instance|
+            expect(instance).to receive(:reset_project_activity)
+          end
+
+          create_push_event(project, project.first_owner)
         end
       end
 
@@ -916,14 +923,13 @@ def visible_to_all_except(*roles)
       end
 
       it 'updates the project' do
-        project.touch(:last_activity_at, time: 1.year.ago)
+        project.update!(last_activity_at: 1.year.ago)
 
         event = create_push_event(project, project.first_owner)
 
         project.reload
 
         expect(project.last_activity_at).to be_like_time(event.created_at)
-        expect(project.updated_at).to be_like_time(event.created_at)
       end
 
       it "deletes the redis key for if the project was inactive" do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 3d5ccbc6feb177950e1f15481bb2a3b4c4078608..651c01a036080056de774b9f20c1ab32498d1728 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -612,6 +612,53 @@
         end
       end
     end
+
+    context 'when last_activity_at is being set' do
+      let(:last_activity_at) { 1.day.ago }
+      let(:project) { build(:project, last_activity_at: last_activity_at) }
+
+      it 'will use supplied timestamp' do
+        expect { project.valid? }.not_to change(project, :last_activity_at)
+      end
+    end
+
+    context 'when last_activity_at is not being set' do
+      context 'and one of PROJECT_ACTIVITY_ATTRIBUTES is updated' do
+        let(:project) { build(:project) }
+
+        before do
+          project.name = "Name Changed"
+        end
+
+        it 'sets last_activity_at to the current time' do
+          freeze_time do
+            expect { project.valid? }.to change(project, :last_activity_at).to(Time.current)
+          end
+        end
+      end
+
+      context 'and the record is new' do
+        let(:project) { build(:project) }
+
+        it 'sets last_activity_at to the current time' do
+          freeze_time do
+            expect { project.valid? }.to change(project, :last_activity_at).from(nil).to(Time.current)
+          end
+        end
+      end
+
+      context 'and the last_activity_at is nil' do
+        let_it_be(:project) { create(:project) }
+
+        before do
+          project.update_column(:last_activity_at, nil)
+        end
+
+        it 'sets last_activity_at to created_at' do
+          expect { project.valid? }.to change(project, :last_activity_at).from(nil).to(project.created_at)
+        end
+      end
+    end
   end
 
   describe 'validation' do
@@ -1603,12 +1650,6 @@
         expect(project.last_activity).to eq(last_event)
       end
     end
-
-    describe 'last_activity_date' do
-      it 'returns the project\'s last update date' do
-        expect(project.last_activity_date).to be_like_time(project.updated_at)
-      end
-    end
   end
 
   describe '#get_issue' do
@@ -2091,9 +2132,9 @@ def has_external_wiki
   end
 
   describe '.sort_by_attribute' do
-    let_it_be(:project1) { create(:project, star_count: 2, updated_at: 1.minute.ago) }
+    let_it_be(:project1) { create(:project, star_count: 2, last_activity_at: 1.minute.ago) }
     let_it_be(:project2) { create(:project, star_count: 1) }
-    let_it_be(:project3) { create(:project, updated_at: 2.minutes.ago) }
+    let_it_be(:project3) { create(:project, last_activity_at: 2.minutes.ago) }
 
     it 'reorders the input relation by start count desc' do
       projects = described_class.sort_by_attribute(:stars_desc)