diff --git a/anatomy/migrations/0025_exam_created_exam_updated.py b/anatomy/migrations/0025_exam_created_exam_updated.py
new file mode 100644
index 00000000..e9c4aa0c
--- /dev/null
+++ b/anatomy/migrations/0025_exam_created_exam_updated.py
@@ -0,0 +1,25 @@
+# Generated by Django 5.2.7 on 2026-01-26 11:05
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('anatomy', '0024_exam_results_supervisor_visible'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='exam',
+ name='created',
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='exam',
+ name='updated',
+ field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'),
+ ),
+ ]
diff --git a/atlas/migrations/0090_casecollection_created_casecollection_updated.py b/atlas/migrations/0090_casecollection_created_casecollection_updated.py
new file mode 100644
index 00000000..dc66189f
--- /dev/null
+++ b/atlas/migrations/0090_casecollection_created_casecollection_updated.py
@@ -0,0 +1,25 @@
+# Generated by Django 5.2.7 on 2026-01-26 11:05
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('atlas', '0089_remove_condition_primary_remove_condition_synonym'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='casecollection',
+ name='created',
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='casecollection',
+ name='updated',
+ field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'),
+ ),
+ ]
diff --git a/atlas/templates/atlas/index.html b/atlas/templates/atlas/index.html
index be43b9bd..1816376b 100644
--- a/atlas/templates/atlas/index.html
+++ b/atlas/templates/atlas/index.html
@@ -20,7 +20,14 @@
hx-swap="innerHTML">
Collections to view / take
+
+
diff --git a/atlas/templates/atlas/partials/_user_related_collections.html b/atlas/templates/atlas/partials/_user_related_collections.html
new file mode 100644
index 00000000..d5a2568a
--- /dev/null
+++ b/atlas/templates/atlas/partials/_user_related_collections.html
@@ -0,0 +1,19 @@
+
+
+
Related collections
+
+
+ {% for item in related_collections %}
+ -
+ {{ item.collection.name }}
+ {% if item.is_author %}Author{% endif %}
+ {% if item.is_marker %}Marker{% endif %}
+ {% if item.collection.description %} — {{ item.collection.description }}{% endif %}
+
+ {% empty %}
+ - No related collections.
+ {% endfor %}
+
+
+
+
\ No newline at end of file
diff --git a/atlas/urls.py b/atlas/urls.py
index 2fdcbbee..d21b80ba 100755
--- a/atlas/urls.py
+++ b/atlas/urls.py
@@ -37,6 +37,7 @@ urlpatterns = [
path("collection/case_search", views.case_search, name="case_search"),
path("collection/", views.CollectionView.as_view(), name="collection_view"),
path("collection/user", views.user_collections, name="user_collections"),
+ path("collection/related", views.user_related_collections, name="user_related_collections"),
path("uploads", views.user_uploads, name="user_uploads"),
path("uploads//user", views.other_user_uploads, name="other_user_uploads"),
path("uploads/all", views.all_uploads, name="all_uploads"),
diff --git a/atlas/views.py b/atlas/views.py
index 0c913aae..15580884 100755
--- a/atlas/views.py
+++ b/atlas/views.py
@@ -1151,6 +1151,39 @@ def user_collections(request):
# endpoint is called by HTMX we prefer returning a small fragment so it
# can be swapped into the index page without duplicating layout.
+
+@login_required
+def user_related_collections(request):
+ """Return up to 10 most recently modified collections where the user
+ is an author or a marker. If called via HTMX return a fragment suitable
+ for swapping into the index page.
+ """
+ user = request.user
+ qs = (
+ CaseCollection.objects.filter(Q(author=user) | Q(markers=user))
+ .distinct()
+ .order_by("-updated")[:10]
+ )
+
+ related = []
+ for c in qs:
+ related.append(
+ {
+ "collection": c,
+ "is_author": c.author.filter(id=user.id).exists(),
+ "is_marker": c.markers.filter(id=user.id).exists(),
+ }
+ )
+
+ context = {"related_collections": related}
+
+ is_htmx = getattr(request, "htmx", False) or request.headers.get("HX-Request", "").lower() == "true"
+ if is_htmx:
+ html = render_to_string("atlas/partials/_user_related_collections.html", context, request=request)
+ return HttpResponse(html)
+
+ return render(request, "atlas/user_collections.html", context)
+
@login_required
def collection_options(request):
if not request.htmx:
diff --git a/generic/models.py b/generic/models.py
index 2110b507..c14ea5be 100644
--- a/generic/models.py
+++ b/generic/models.py
@@ -667,6 +667,9 @@ class ExamOrCollectionGenericBase(models.Model, AuthorMixin):
name = models.CharField(max_length=200, help_text="Name of the exam/collection")
+ created = models.DateTimeField(auto_now_add=True, help_text="Creation timestamp")
+ updated = models.DateTimeField(auto_now=True, help_text="Last updated timestamp")
+
start_date = models.DateTimeField(
help_text="Date (and time) the exam/collection starts", null=True, blank=True
)
diff --git a/longs/migrations/0034_exam_created_exam_updated.py b/longs/migrations/0034_exam_created_exam_updated.py
new file mode 100644
index 00000000..a524704e
--- /dev/null
+++ b/longs/migrations/0034_exam_created_exam_updated.py
@@ -0,0 +1,25 @@
+# Generated by Django 5.2.7 on 2026-01-26 11:05
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('longs', '0033_alter_longseriesimage_image_md5_hash'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='exam',
+ name='created',
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='exam',
+ name='updated',
+ field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'),
+ ),
+ ]
diff --git a/physics/migrations/0018_exam_created_exam_updated.py b/physics/migrations/0018_exam_created_exam_updated.py
new file mode 100644
index 00000000..1ebabb89
--- /dev/null
+++ b/physics/migrations/0018_exam_created_exam_updated.py
@@ -0,0 +1,25 @@
+# Generated by Django 5.2.7 on 2026-01-26 11:05
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('physics', '0017_exam_results_supervisor_visible'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='exam',
+ name='created',
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='exam',
+ name='updated',
+ field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'),
+ ),
+ ]
diff --git a/rapids/migrations/0017_exam_created_exam_updated.py b/rapids/migrations/0017_exam_created_exam_updated.py
new file mode 100644
index 00000000..4d6b0683
--- /dev/null
+++ b/rapids/migrations/0017_exam_created_exam_updated.py
@@ -0,0 +1,25 @@
+# Generated by Django 5.2.7 on 2026-01-26 11:05
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('rapids', '0016_exam_results_supervisor_visible'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='exam',
+ name='created',
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='exam',
+ name='updated',
+ field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'),
+ ),
+ ]
diff --git a/sbas/migrations/0023_exam_created_exam_updated.py b/sbas/migrations/0023_exam_created_exam_updated.py
new file mode 100644
index 00000000..5c1e70b7
--- /dev/null
+++ b/sbas/migrations/0023_exam_created_exam_updated.py
@@ -0,0 +1,25 @@
+# Generated by Django 5.2.7 on 2026-01-26 11:05
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sbas', '0022_question_frcr_appropriate'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='exam',
+ name='created',
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='exam',
+ name='updated',
+ field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'),
+ ),
+ ]
diff --git a/shorts/migrations/0011_exam_created_exam_updated.py b/shorts/migrations/0011_exam_created_exam_updated.py
new file mode 100644
index 00000000..51fedf82
--- /dev/null
+++ b/shorts/migrations/0011_exam_created_exam_updated.py
@@ -0,0 +1,25 @@
+# Generated by Django 5.2.7 on 2026-01-26 11:05
+
+import django.utils.timezone
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('shorts', '0010_alter_useranswer_candidate_feedback_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='exam',
+ name='created',
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='Creation timestamp'),
+ preserve_default=False,
+ ),
+ migrations.AddField(
+ model_name='exam',
+ name='updated',
+ field=models.DateTimeField(auto_now=True, help_text='Last updated timestamp'),
+ ),
+ ]