diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css
index d388dd9441db7031b13425671d1ec087cf2e8bf6..094625f7998bd737fd69e7012a5790d20f40fe88 100644
--- a/app/assets/stylesheets/application.tailwind.css
+++ b/app/assets/stylesheets/application.tailwind.css
@@ -26,7 +26,7 @@ select {
 }
 .session-holder { @apply w-full; }
 .session {
-  @apply border p-2 bg-slate-100 border-slate-300 rounded-md w-full flex flex-col;
+  @apply border p-2 bg-slate-100 border-slate-300 rounded-md w-full flex flex-col hover:shadow-2xl;
 
   &.translators-needed {
     @apply bg-red-200 border-red-400;
diff --git a/app/controllers/assignments_controller.rb b/app/controllers/assignments_controller.rb
index 553638913002561f835a97dee79ff712106b2faf..fe2197fe6d8c8cfb63d5475b0aa4c32e27ad90df 100644
--- a/app/controllers/assignments_controller.rb
+++ b/app/controllers/assignments_controller.rb
@@ -9,10 +9,20 @@ class AssignmentsController < ApplicationController
   end
 
   def create
+    params[:user_id] ||= params[:assignment][:user_id]
+    if params[:user_id].nil? or params[:user_id].empty?
+      flash.now[:alert] = 'Please select a user to assign.'
+
+      respond_to do |format|
+        format.turbo_stream { render turbo_stream: turbo_stream.replace(helpers.dom_id(@session), partial: "sessions/session", locals: { session: @session }), status: :unprocessable_entity }
+        format.html { redirect_to conference_session_path(@session.conference, @session), alert: 'Please select a user to assign.' }
+      end
+      return
+    end
     @session = Session.find_by(ref_id: params[:session_ref_id])
     @conference = Conference.find_by(slug: params[:conference_slug])
     @user = User.find(params[:user_id])
-    @assignment = @session.assignments.new(user: @user)
+    @assignment = Assignment.new(user: @user, session: @session)
 
     if @assignment.save
       flash.now[:success] = 'User assigned successfully.'
diff --git a/app/models/assignment.rb b/app/models/assignment.rb
index b6db13245d0af1ae3e1810ba1f139c4eb2cd8137..3426f2244d12b0885bdf0726c9a4d485c0fc5660 100644
--- a/app/models/assignment.rb
+++ b/app/models/assignment.rb
@@ -3,4 +3,26 @@ class Assignment < ApplicationRecord
   belongs_to :session
 
   validates :user_id, uniqueness: { scope: :session_id, message: "has already been assigned to this session" }
+
+  validate :no_overlapping_assignments
+
+  private
+
+  def no_overlapping_assignments
+    return if session.blank? || user.blank?
+
+    overlapping_assignments = user.assignments
+                                  .joins(:session)
+                                  .where.not(id: id)
+                                  .where(
+                                    "sessions.starts_at < ? AND sessions.ends_at > ?",
+                                    session.ends_at, session.starts_at
+                                  )
+
+    logger.debug(overlapping_assignments)
+
+    if overlapping_assignments.exists?
+      errors.add(:base, "This assignment overlaps with another assignment for this user.")
+    end
+  end
 end
diff --git a/app/subscribers/notifications_subscriber.rb b/app/subscribers/notifications_subscriber.rb
index c6aad96807b5b6ce00be5156564a0bfbf5ac9d83..5d07e66250f88c1a3b53553dd0943e9ad9e1fec4 100644
--- a/app/subscribers/notifications_subscriber.rb
+++ b/app/subscribers/notifications_subscriber.rb
@@ -13,6 +13,17 @@ class NotificationsSubscriber
 
     conference = record.conference
 
+    # record.assignments.includes(:user).each do |assignment|
+    #   Notification.create!(
+    #     channel: 'telegram_group_chat',
+
+    #   )
+    # end
+    Notification.create!(
+      channel: 'telegram_group_chat',
+      target:
+    )
+
     Revision.create!(
       conference:,
       target_type: model_name,
diff --git a/app/views/assignments/_user_add.html.erb b/app/views/assignments/_user_add.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..65c56c26f5803261fc9ad57a11a67e204cb0c501
--- /dev/null
+++ b/app/views/assignments/_user_add.html.erb
@@ -0,0 +1,26 @@
+<% disabled = local_assigns.fetch(:disabled, false) %>
+<% if not disabled %>
+<span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" style="background-color: <%= user.avatar_color %>" title="<%= user.name %>">
+  <span style="color: <%= user.text_color %>"><%= user.name %></span>
+  <button type="button" class="group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20">
+    <%= link_to conference_session_assignments_path(session.conference, session, user_id: user.id), data: { turbo_method: :post, turbo_frame: dom_id(session) } do %>
+      <span class="sr-only">Add</span>
+      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16" stroke-width="1" class="size-3.5 stroke-gray-600/50 group-hover:stroke-gray-600/75 fill-gray-600/50" style="stroke: <%= user.text_color %>; fill: <%= user.text_color %>">
+        <path d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" />
+      </svg>
+      <span class="absolute -inset-1"></span>
+    <% end %>
+  </button>
+</span>
+<% else %>
+<span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" title="<%= user.name %>">
+  <span><%= user.name %></span>
+  <div class="group relative -mr-1 size-3.5 rounded-sm">
+      <span class="sr-only">Add</span>
+      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16" stroke-width="1" class="size-3.5 stroke-gray-600/50 fill-gray-600/50">
+        <path d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" />
+      </svg>
+      <span class="absolute -inset-1"></span>
+  </button>
+</span>
+<% end %>
\ No newline at end of file
diff --git a/app/views/conferences/show.html.erb b/app/views/conferences/show.html.erb
index bc490b8289b5f3997e57f2090ca3ae7f7f22f22b..34d625f429af897139667de442e3a1949bcdaa68 100644
--- a/app/views/conferences/show.html.erb
+++ b/app/views/conferences/show.html.erb
@@ -104,7 +104,7 @@ current_time = Time.zone.now.in_time_zone(@conference.time_zone).advance(days: 1
             <h4><%= stage.name %></h4>
             <div class="stage-sessions">
               <% sessions.each do |session| %>
-                <div class="session-holder" style="position: absolute; top: <%= (session.starts_at - timeline_starts_at) / 3600.0 * pixels_per_hour %>px; height: <%= (session.ends_at - session.starts_at) / 3600.0 * pixels_per_hour %>px; overflow: scroll;">
+                <div class="session-holder hover:z-30" style="position: absolute; top: <%= (session.starts_at - timeline_starts_at) / 3600.0 * pixels_per_hour %>px; max-height: <%= (session.ends_at - session.starts_at) / 3600.0 * pixels_per_hour %>px; height: <%= (session.ends_at - session.starts_at) / 3600.0 * pixels_per_hour %>px;">
                   <%= render partial: "sessions/session", locals: { session: session } %>
                 </div>
               <% end %>
diff --git a/app/views/sessions/_assignment_form.html.erb b/app/views/sessions/_assignment_form.html.erb
index 686a20f4020bc8e4724eacb24002eee7fee22045..1f6dabc129bb21bf1b6bbc642e780d54aec4aa3f 100644
--- a/app/views/sessions/_assignment_form.html.erb
+++ b/app/views/sessions/_assignment_form.html.erb
@@ -2,7 +2,7 @@
 <% if unassigned_users.length > 0 %>
   <div class="text-sm">
     <%= form_with url: conference_session_assignments_path(session.conference, session), method: :post, data: { turbo_frame: dom_id(session) } do |f| %>
-      <%= f.select :user_id, options_from_collection_for_select(unassigned_users, :id, :name), {}, { class: "text-sm" } %>
+      <%= f.select :user_id, options_from_collection_for_select(unassigned_users, :id, :name), { disabled: '', prompt: '-' }, { class: "text-sm" } %>
       <%= f.submit "Assign", class: 'primary text-sm' %>
       <% if @assignment&.errors&.any? %>
         <div class="alert alert-danger">
diff --git a/app/views/sessions/_session.html.erb b/app/views/sessions/_session.html.erb
index 0534eb41a0c0a3174760a7096769f33fff670ce7..4079c1a7289888e9c9c7044a8b56dcee3b2fb5c7 100644
--- a/app/views/sessions/_session.html.erb
+++ b/app/views/sessions/_session.html.erb
@@ -1,7 +1,27 @@
+<% unassigned_users = @users - session.assignments.collect(&:user) %>
 <%= turbo_frame_tag dom_id(session) do %>
-  <div class="session text-sm w-full h-full <%= session.translators_needed? ? "translators-needed" : "no-translators-needed" %> <%= session.backup_needed? ? "backup-needed" : "no-backup-needed" %> <%= session.has_assignees? ? "has-assignees" : "no-assignees" %>">
-    <h4><small class="text-2xs uppercase font-light bg-black/10 rounded-sm p-1 mr-1 lang-<%= session.language %>"><%= session.language %></small><%= link_to session.title, session.url, target: "_top" %></h4>
-    <p class="session-time"><%= session.starts_at.strftime('%H:%M') %> - <%= session.ends_at.strftime('%H:%M') %> @ <%= session.stage.name %> &middot; <%= session.language %><% if session.is_interpreted %> <strong>(int)</strong><% end %></p>
+  <div class="session shadow hover:shadow-lg overflow-scroll hover:h-max text-sm w-full h-full <%= session.translators_needed? ? "translators-needed" : "no-translators-needed" %> <%= session.backup_needed? ? "backup-needed" : "no-backup-needed" %> <%= session.has_assignees? ? "has-assignees" : "no-assignees" %>">
+    <h4>
+      <small class="text-2xs uppercase font-light bg-black/10 rounded-sm p-1 mr-1 lang-<%= session.language %>"><%= session.language %></small>
+      <%= link_to session.title, session.url, target: "_top" %>
+    </h4>
+    <% if false %>
+    <div>
+      <span class="session-time"><%= session.starts_at.strftime('%H:%M') %> - <%= session.ends_at.strftime('%H:%M') %></span>
+       &ndash;
+      <span class="session-location text-sm font-medium"><%= session.stage.name %></span>
+    </div>
+    <% end %>
+    
+    <% if false and (session.translators_needed? or session.backup_needed?) %>
+      <% if session.translators_needed? %>
+        <div class="border font-medium text-sm border-red-400 bg-red-200 px-2 py-1 shadow-inner rounded-md inline w-max">needs translators</div>
+      <% else %>
+        <div class="border font-medium text-sm border-amber-400 bg-amber-200 px-2 py-1 shadow-inner rounded-md inline w-max">needs backup</div>
+      <% end %>
+    <% end %>
+
+    <small>assigned (<%= session.assignments.length %>)</small>
     <ul class="inline-flex flex-wrap gap-1 my-1">
       <% session.assignments.each do |assignment| %>
         <li>
@@ -9,6 +29,25 @@
         </li>
       <% end %>
     </ul>
-    <%= render partial: "sessions/assignment_form", locals: { session: session } %>
+    <hr>
+    <% if @assignment&.errors&.any? %>
+      <div class="alert alert-danger bg-red-600 border-red-800 text-white border p-2 shadow z-30 rounded-md" onclick="this.parentNode.removeChild(this)">
+        <div class="float-right"><span class="sr-only">Close</span>
+          <svg viewBox="0 0 14 14" class="size-3.5 stroke-white">
+            <path d="M4 4l6 6m0-6l-6 6" />
+          </svg>
+          <span class="absolute -inset-1"></span>
+        </div>
+        <%= @assignment.errors.full_messages.join(", ") %>
+      </div>
+    <% end %>
+    <small>unassigned (<%= unassigned_users.length %>)</small>
+    <ul class="flex flex-row flex-wrap gap-1 my-1 flex-shrink-0">
+      <% unassigned_users.each do |user| %>
+        <li>
+          <span class="unassigned-user"><%= render partial: 'assignments/user_add', locals: { user: user, session: session } %></span>
+        </li>
+      <% end %>
+    </ul>
   </div>
 <% end %>
diff --git a/db/migrate/20240526121600_add_telegram_username_to_user.rb b/db/migrate/20240526121600_add_telegram_username_to_user.rb
new file mode 100644
index 0000000000000000000000000000000000000000..90ff2b9b87bb351cd43fc9d027393835e23827a3
--- /dev/null
+++ b/db/migrate/20240526121600_add_telegram_username_to_user.rb
@@ -0,0 +1,5 @@
+class AddTelegramUsernameToUser < ActiveRecord::Migration[7.1]
+  def change
+    add_column :users, :telegram_username, :string
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 31489c275614c9813a70299809031db4782ff753..c3f6ce6618899243a05b2fad1730239e4494ac57 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.1].define(version: 2024_05_26_063139) do
+ActiveRecord::Schema[7.1].define(version: 2024_05_26_121600) do
   create_table "assignments", force: :cascade do |t|
     t.integer "user_id", null: false
     t.integer "session_id", null: false
@@ -226,6 +226,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_26_063139) do
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
     t.string "avatar_color"
+    t.string "telegram_username"
   end
 
   add_foreign_key "assignments", "sessions"
diff --git a/db/seeds.rb b/db/seeds.rb
index de2afc9522f0db2c128a54f926698320ed2689c0..ebbcef77ea32e1a7807d7246f1e07f9d8dd2b98b 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -37,6 +37,10 @@ end
 %w[Teal hdsjulian Sophie bergpiratin sblsg Max aerowaffle ningwie Senana ToniHDS].each do |username|
   User.find_or_create_by!(name: username, email: "c3lingo+#{username}@x.moeffju.net")
 end
+u = User.find_by(name: 'sblsg')
+u.name = 'sebalis'
+u.telegram_username = 'sblsg'
+u.save!
 
 NotificationChannel.create!(
   name: 'telegram_group_chat',