diff --git a/src/plainui/jinja2/plainui/event.html.j2 b/src/plainui/jinja2/plainui/event.html.j2
index 048769f4ff4a39801d311b581739e8d3f59094df..293a3ddb79daa9b85e9674fe356a27f0f674a8f8 100644
--- a/src/plainui/jinja2/plainui/event.html.j2
+++ b/src/plainui/jinja2/plainui/event.html.j2
@@ -19,27 +19,33 @@
 {% extends "plainui/base.html.j2" %}
 
 {% block title %}
-  {{ event.name }} - {{ conf.slug.upper() }}
+  {{ event.name }} - {{ event.conference.slug.upper() }}
 {% endblock title %}
 
 {% block head %}
   <script src="{{ static('plainui/js/player.js') }}"></script>
 {% endblock head %}
 {% block content %}
+  {% set current_assembly = {
+      "link": url('plainui:assembly', assembly_slug=event.assembly.slug),
+      "name": event.assembly.name,
+      "is_official": event.assembly.is_official,
+    } if event.assembly and event.assembly.slug else {} %}
+
   <article class="mt-10">
     {{ navMacro.top_nav(_("Event") , has_breadcrumbs=True) }}
     <nav aria-label="breadcrumb">
       <ol class="breadcrumb hub-breadcrumbs">
         <li class="breadcrumb-item">
-          <a href="{{ url('plainui:index') }}">{{ conf.name }}</a>
+          <a href="{{ url('plainui:index') }}">{{ event.conference.name }}</a>
         </li>
-        {% if not assembly.is_official %}
+        {% if not current_assembly.is_official %}
           <li class="breadcrumb-item">
             <a href="{{ url('plainui:assemblies') }}">{{ _("assemblies") }}</a>
           </li>
         {% endif %}
         <li class="breadcrumb-item">
-          <a href="{{ url('plainui:assembly', assembly_slug=assembly.slug) }}">{{ assembly.name }}</a>
+          <a href="{{ current_assembly.link }}">{{ current_assembly.name }}</a>
         </li>
         {% if event.room and event.room.name %}
           <li class="breadcrumb-item">
@@ -49,12 +55,6 @@
       </ol>
     </nav>
 
-    {% set current_assembly = {
-          "link": url('plainui:assembly', assembly_slug=assembly.slug),
-          "name": assembly.name,
-          "is_official": assembly.is_official,
-        } if assembly and assembly.slug else {} %}
-
     <div class="hub-vlayout">
       <div class="hub-row">
         <div class="hub-col hub-col-remaining hub-card hub-hlayout-l">
@@ -72,7 +72,7 @@
             <div class="hub-vlayout">
               <div class="hub-head-main">{{ event.name }}</div>
 
-              {% if event.room or speakers or event.language %}
+              {% if event.room or event.public_speakers or event.language %}
                 <div class="hub-tags">
                   {% if event.room %}
                     {{ tagboxMacro.tag(event.room.name,
@@ -82,8 +82,8 @@
                     ) }}
                   {% endif %}
 
-                  {% if speakers %}
-                    {% for speaker in speakers %}
+                  {% if event.public_speakers %}
+                    {% for speaker in event.public_speakers %}
                       {{ tagboxMacro.user(speaker.get_display_name() ,
                       link=url('plainui:user', user_slug=speaker.slug)
                       ) }}
@@ -117,7 +117,7 @@
                   </div>
                 {% endif %}
 
-                {% if tags %}{{ tagboxMacro.tagbox(tags, icon='tag') }}{% endif %}
+                {% if event.public_tags %}{{ tagboxMacro.tagbox(event.public_tags, icon='tag') }}{% endif %}
               </div>
             </div>
 
@@ -144,7 +144,7 @@
               {% endif %}
 
               {%- if not event.is_sos and can_manage -%}
-                {{ fbtns.edit(hub_absolute('backoffice:assembly-event', assembly=assembly.id, pk=event.id) ,
+                {{ fbtns.edit(hub_absolute('backoffice:assembly-event', assembly=event.assembly.id, pk=event.id) ,
                 color="secondary", margin=False) }}
               {%- elif event.is_sos and can_manage -%}
                 {{ fbtns.edit(hub_absolute('backoffice:sos-edit', pk=event.id) , color="secondary", margin=False) }}
diff --git a/src/plainui/views/events.py b/src/plainui/views/events.py
index 7a82df3a87fd33e120a908f6af2d7ca728679d40..2e9d46af9c2eb39609d34fb55ad80ab526babf74 100644
--- a/src/plainui/views/events.py
+++ b/src/plainui/views/events.py
@@ -5,15 +5,15 @@ __all__ = (
     'UpcomingView',
 )
 
-from django.contrib.contenttypes.models import ContentType
-from django.shortcuts import get_object_or_404
+from typing import Any
+
+from django.db.models.query import QuerySet
 from django.urls import reverse
+from django.views.generic import DetailView
 from django.views.generic.base import TemplateView
 
 from core.models import (
     Event,
-    EventAttachment,
-    TagItem,
 )
 from core.views.list_views import FilteredListView
 
@@ -37,24 +37,24 @@ class AssembliesEventsView(ConferenceRequiredMixin, TemplateView):
         return context
 
 
-class EventView(ConferenceRequiredMixin, TemplateView):
+class EventView(ConferenceRequiredMixin, DetailView):
     template_name = 'plainui/event.html.j2'
+    slug_field = 'slug__iexact'
+    slug_url_kwarg = 'event_slug'
+    context_object_name = 'event'
+
+    def get_queryset(self) -> QuerySet[Any]:
+        return Event.objects.conference_accessible(self.conf).select_related('assembly', 'owner', 'track')
 
-    def get_context_data(self, event_slug, **kwargs):
+    def get_context_data(self, **kwargs):
+        if not Event.type_is(event := self.get_object()):  # pragma: no cover
+            raise ValueError(f'Object {event} is not an Event')
         context = super().get_context_data(**kwargs)
-        context['conf'] = self.conf
 
-        event = get_object_or_404(Event.objects.conference_accessible(self.conf).select_related('assembly', 'owner', 'track'), slug=event_slug)
-        context['event'] = event
         favorites = session_get_favorite_events(self.request.session, self.request.user)
         context['is_favorite'] = str(event.id) in favorites
         context['is_favorite_events'] = favorites
         context['can_manage'] = event.can_manage(self.request.user)
-        context['speakers'] = event.public_speakers
-        context['tags'] = TagItem.objects.select_related('tag').filter(
-            tag__is_public=True, target_type=ContentType.objects.get_for_model(Event), target_id=event.pk
-        )
-        context['assembly'] = event.assembly
         now = self.now
         if event.schedule_start is None or event.schedule_end is None:
             running_state = ''
@@ -66,11 +66,6 @@ class EventView(ConferenceRequiredMixin, TemplateView):
             running_state = 'upcoming'
         context['running_state'] = running_state
 
-        context['attachments'] = EventAttachment.objects.filter(
-            event=event, visibility__in=[EventAttachment.Visibility.PUBLIC, EventAttachment.Visibility.CONFERENCE]
-        )
-
-        context['report_info'] = {'lookup_key': event.slug}
         context['report_info'] = {'url': reverse('plainui:event', kwargs={'event_slug': event.slug})}
         context['fav_info'] = {'type': 'event', 'id': event.id, 'is': str(event.id) in favorites}
 
@@ -106,7 +101,6 @@ class SosList(ConferenceRequiredMixin, FilteredListView):
         context['conf'] = self.conf
 
         context['events_upcoming'] = event_filter(self.request.user, self.conf, kinds=[Event.Kind.SELF_ORGANIZED], calendar_mode=False, upcoming=True)
-        context['events'] = event_filter(self.request.user, self.conf, kinds=[Event.Kind.SELF_ORGANIZED], calendar_mode=False)
         context['is_favorite_events'] = session_get_favorite_events(self.request.session, self.request.user)
         context['manageable_events'] = Event.objects.manageable_by_user(self.conf, user=self.request.user).only('id')