diff --git a/lib/SeMeet/Controller/Meets.pm b/lib/SeMeet/Controller/Meets.pm
index 6bbd904ce3154fec422007a9e997a4f23c9a24b4..27935af16250f1877d3f370a8db8b88616441be4 100644
--- a/lib/SeMeet/Controller/Meets.pm
+++ b/lib/SeMeet/Controller/Meets.pm
@@ -47,12 +47,12 @@ sub get($c) {
     my $args = $c->req->json;
 
     my $meet = $c->_get($c->stash->{id}, 0) // return;
+    my $is_mod = $meet->moderators({ octid => $c->stash->{user}->id})->count;
 
     $c->render(openapi => $c->spec_filter({
         $meet->get_columns,
-        groups => $meet->cached_groups,
-        moderators  => $meet->cached_moderators,
-        is_editable => ( $meet->owner_id == $c->stash->{user}->id),
+        groups       => $meet->cached_groups,
+        moderators   => $meet->cached_moderators,
     }, 'Meet'));
 }
 
@@ -65,11 +65,12 @@ sub list($c) {
         -or => [
             owner_id => $c->stash->{user}->id,
             "groups.group_id" => { '-in' => $c->stash->{groups} },
+            "moderators.octid" => $c->stash->{user}->octid,
         ]
     },
     {
         order_by => 'name',
-        join     => 'groups',
+        join     => ['groups', 'moderators'],
         distinct => 1,
     }
     );
@@ -82,7 +83,8 @@ sub list($c) {
             $meet->get_columns,
             groups => $meet->cached_groups,
             moderators => $meet->cached_moderators,
-            is_editable => ( $meet->owner_id == $c->stash->{user}->id),
+#            is_owned   => ( $meet->owner_id == $c->stash->{user}->id),
+#            is_moderated => 0,
         }, 'Meet')
     }
 
@@ -115,7 +117,7 @@ sub add_moderators($c) {
     $c->openapi->valid_input or return;
     my $args = $c->req->json;
 
-    my $meet = $c->_get($c->stash->{id}, 1) // return;
+    my $meet = $c->_get($c->stash->{id}, 2) // return;
 
     IDS:
     foreach my $user ( @{ $args->{users} } ) {
@@ -148,7 +150,7 @@ sub delete_group($c) {
 sub delete_moderator($c) {
     $c->openapi->valid_input or return;
 
-    my $meet = $c->_get($c->stash->{id}, 1) // return;
+    my $meet = $c->_get($c->stash->{id}, 2) // return;
 
     $meet->delete_related('moderators',
         { octid => $c->stash->{user_id} }
@@ -161,7 +163,7 @@ sub delete_moderator($c) {
 sub delete($c) {
     $c->openapi->valid_input or return;
 
-    my $meet = $c->_get($c->stash->{id}, 1) // return;
+    my $meet = $c->_get($c->stash->{id}, 2) // return;
 
     $meet->update({ deleted => \'now()'});
 
@@ -172,7 +174,7 @@ sub update($c) {
     $c->openapi->valid_input or return;
     my $args = $c->req->json;
 
-    my $meet = $c->_get($c->stash->{id}, 1) // return;
+    my $meet = $c->_get($c->stash->{id}, 2) // return;
 
     my $exists = $c->schema->resultset('Meet')->count({
         id      => { '!=' => $meet->id },
@@ -201,25 +203,32 @@ sub meet($c) { #NENI API!
     });
 
     return $c->error(404, 'NOT_FOUND') if ! $meet;
-    # CHECK MEET ACCESS
 
-    $c->stash->{is_editable} = ( $meet->owner_id == $user->id);
-    $c->stash->{token} = $user->meet_token($meet, $c->config);
+    my $roles = $meet->user_roles($user, $c->current_user->{groups});
+
+    return $c->error(404, 'NOT_FOUND') if ! $roles->{any};
+
     $c->stash->{meet}  = $meet;
+    $c->stash->{roles} = $roles;
+    $c->stash->{token} = $user->meet_token($meet, $c->config);
 
     $c->render('meet');
 }
 
-sub _get($c, $id, $for_owner) {
-
-    my $meet = $c->schema->resultset('Meet')->find({
-        id => $id
-    });
+sub _get($c, $id, $access) {
 
+    my $meet = $c->schema->resultset('Meet')->find({ id => $id });
     return $c->error(404, 'NOT_FOUND') if ! $meet;
 
-    if ( $for_owner ) {
-        return $c->error(403, 'ACCESS_DENIED') if $meet->owner_id != $c->stash->{user}->id;
+    my $roles = $meet->user_roles($c->stash->{user}, $c->stash->{groups});
+    return $c->error(403, 'ACCESS_DENIED') if ! $roles->{any};
+
+    if ( $access == 1 && ! ($roles->{moderator} || $roles->{owner}) ) {
+        return $c->error(403, 'ACCESS_DENIED');
+    }
+
+    if ( $access == 2 && ! $roles->{owner} ) {
+        return $c->error(403, 'ACCESS_DENIED');
     }
 
     return $meet;
diff --git a/lib/SeMeet/I18N/cs.pm b/lib/SeMeet/I18N/cs.pm
index 48fb158a4446a4d4002ef4e205a6e2aaa091dfe3..207ecc64d3fee033efc055af8c0db7bc7e834b6d 100644
--- a/lib/SeMeet/I18N/cs.pm
+++ b/lib/SeMeet/I18N/cs.pm
@@ -23,6 +23,7 @@ our %Lexicon = (
     ENTER                               => 'Vstoupit',
     COPY_LINK                           => 'ZkopĂ­rovat odkaz',
 
+    'About meet'                        => 'O mistnosti',
     'Add groups'                        => 'Přidat skupiny',
     'Add moderators'                    => 'Přidat moderatory',
     'Create meet'                       => 'Vytvořit místnost',
diff --git a/lib/SeMeet/Schema/Result/Meet.pm b/lib/SeMeet/Schema/Result/Meet.pm
index 3fb48994ec7bd215006f94ad2c633081e3fdab3d..991a547e0fd7f3cfc75e41ffdc48f26f4bf47c7c 100644
--- a/lib/SeMeet/Schema/Result/Meet.pm
+++ b/lib/SeMeet/Schema/Result/Meet.pm
@@ -65,6 +65,19 @@ __PACKAGE__->inflate_column('properties', {
     deflate => sub { to_json(shift); },
 });
 
+sub user_roles($self, $user, $groups) {
+
+    my $roles = {
+        participant => $self->meet_groups({ group_id => { -in => $groups } })->count(),
+        moderator   => $self->moderators({ octid => $user->octid })->count(),
+        owner       => ($self->owner_id == $user->id),
+    };
+
+    $roles->{any} = $roles->{participant} || $roles->{moderator} || $roles->{owner};
+
+    return $roles;
+}
+
 sub update_groups_cache($self) {
     my @groups = ();
     foreach my $group ($self->groups) {
diff --git a/openapi.yaml b/openapi.yaml
index bfb8c46a3038fdca89a5fe94de09cfc340640e58..ee4791be141eb235fea203f13d6fe6393b53e73f 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -48,8 +48,6 @@ components:
           type: array
           items:
              $ref: '#/components/schemas/UserInList'
-        is_editable:
-          type: boolean
     GroupInList:
       type: object
       properties:
diff --git a/script/sync_octopus_groups b/script/sync_octopus_groups
index 4b65439f6c04f49d6bb9e2fdf38dfd44ee5c09d5..f018fecd504cdf3c6b9ea9349ef8d9f3a0327602 100755
--- a/script/sync_octopus_groups
+++ b/script/sync_octopus_groups
@@ -27,8 +27,16 @@ my $schema = SeMeet::Schema->connect({
 
 my $octopus_groups = $iapi->get('octopus/groups/');
 
+my @exists = ();
+
+my $guard  = $schema->txn_scope_guard;
+
+# Insert/Update
 GROUP:
 foreach my $group ( @{ $octopus_groups } ) {
+
+    push @exists, $group->{id};
+
     $schema->resultset('Group')->update_or_create(
         {
             octid => $group->{id},
@@ -37,3 +45,16 @@ foreach my $group ( @{ $octopus_groups } ) {
         { key => 'octid'}
     );
 }
+
+# Cleanup
+$schema->resultset('Group')->search({octid => {-not_in => \@exists}})->delete;
+
+# Update cache
+my $meets = $schema->resultset('Meet')->search({deleted => undef});
+
+MEET:
+while ( my $meet = $meets->next ) {
+    $meet->update_groups_cache();
+}
+
+$guard->commit;
diff --git a/templates/includes/meet_groups.html.ep b/templates/includes/meet_groups.html.ep
index bd0c2b7f07de59ab92d86d430de55946b841831f..29545c36658804a7d1f8a158b310a9b72962c23f 100644
--- a/templates/includes/meet_groups.html.ep
+++ b/templates/includes/meet_groups.html.ep
@@ -1,12 +1,15 @@
 <div class="mb-4">
 <span v-for="group in meet.groups" class="chip chip--green-400 mr-1 mb-1 rounded">
 {{ group.name }}
+% if ( $roles->{owner}  || $roles->{moderator} ) {
     <span class="icon">
       <i class="ico--cross ml-3 cursor-pointer" @click="removeGroup(group.id)"></i>
     </span>
+% }
 </span>
 </div>
 
+% if ( $roles->{owner}  || $roles->{moderator} ) {
 <div class="" v-effect="searchGroups()">
   <label class="form-field__label" for="name"><%=l 'LABEL_GROUPS_ADD' %></label>
   <input type="text" class="w-full text-input" value="" v-model="search_groups" id="search_group" placeholder="<%=l 'INPUT_MEET_ADD_GROUPS_PLACEHOLDER' %>"/>
@@ -22,4 +25,4 @@
        </button>
     </div>
 </div>
-
+% }
diff --git a/templates/includes/meet_moderators.html.ep b/templates/includes/meet_moderators.html.ep
index b1fd19651d850f12c4a3a90bfc76c024607b49d7..a6ed19032e893e4e94e2d23d84dc022b9d736a96 100644
--- a/templates/includes/meet_moderators.html.ep
+++ b/templates/includes/meet_moderators.html.ep
@@ -1,12 +1,15 @@
 <div class="mb-4">
 <span v-for="moderator in meet.moderators" class="chip chip--red-600 mr-1 mb-1 rounded">
 {{ moderator.name }}
+% if ( $roles->{owner} ) {
     <span class="icon">
       <i class="ico--cross ml-3 cursor-pointer" @click="removeModerator(moderator.id)"></i>
     </span>
+% }
 </span>
 </div>
 
+% if ( $roles->{owner} ) {
 <div v-effect="searchUsers()">
   <label class="form-field__label" for="name"><%=l 'LABEL_USERS_ADD' %></label>
   <input type="text" class="w-full text-input" value="" v-model="search_users" id="search_user" placeholder="<%=l 'INPUT_MEET_ADD_USERS_PLACEHOLDER' %>"/>
@@ -22,4 +25,4 @@
        </button>
     </div>
 </div>
-
+% }
diff --git a/templates/index.html.ep b/templates/index.html.ep
index 8b2ae835fdd4416cda76847d2c959a1ab574f4d7..a4055a38c46c26b30614dc95f86a116e1c40fe22 100644
--- a/templates/index.html.ep
+++ b/templates/index.html.ep
@@ -12,7 +12,7 @@
 <h1 class="head-alt-lg">Opravdu bezpeÄŤnĂ˝ jitsi</h1>
 <h1 class="head-alt-lg text-green-400">Žádní náhodní moderatoři</h1>
 <h1 class="head-alt-lg text-violet-400">Všechno je pod kontrolou</h1>
-<h1 class="head-alt-lg text-blue-300">Vždy víš s kým mluvíš</h1>
+<h1 class="head-alt-lg text-blue-300">Vždy víš kdo tě poslouchá</h1>
 <h1 class="head-alt-xl text-red-600">TestovacĂ­ provoz</h1>
 </div>
 </div>
diff --git a/templates/meet.html.ep b/templates/meet.html.ep
index b8973f3f083865e917d988587b487eea3f4d8646..2186586a9f5d961e89a1f50ef0f3a5ff4fbeeffe 100644
--- a/templates/meet.html.ep
+++ b/templates/meet.html.ep
@@ -3,18 +3,14 @@
 
 %= include 'includes/meet'
 
-% if ( $is_editable ) {
 <div class="grid grid-cols-3 border border-b-0 divide-x text-center">
 <div @click="active_tab='groups'" class="p-4 bg-grey-125" :class="tabClass('groups')"><%=l 'Authorized groups' %></div>
 <div @click="active_tab='moderators'" class="p-4 bg-grey-125" :class="tabClass('moderators')"><%=l 'Moderators' %></div>
 %#<div @click="active_tab='invites'" class="p-4 bg-grey-125" :class="tabClass('invites')"><%=l 'Invites' %></div>
-<div @click="active_tab='form'" class="p-4 bg-grey-125" :class="tabClass('form')"><%=l 'Configuration' %></div>
+<div @click="active_tab='form'" class="p-4 bg-grey-125" :class="tabClass('form')"><%=l $roles->{owner} ? 'Configuration':'About meet' %></div>
 </div>
 
 <div class="border p-4" v-effect="getMeet()" v-cloak>
-    <div v-if="active_tab == 'form'">
-%= include 'includes/meet_form'
-    </div>
     <div v-if="active_tab == 'groups'">
 %= include 'includes/meet_groups'
     </div>
@@ -23,6 +19,13 @@
     </div>
     <div v-if="active_tab == 'invites'">
     </div>
+    <div v-if="active_tab == 'form'">
+% if ( $roles->{owner} ) {
+%= include 'includes/meet_form'
+% } else {
+<%= $meet->description %>
+% }
+    </div>
 </div>
 
 <script type="module">
@@ -76,6 +79,8 @@
         })
     },
 
+% if ( $roles->{owner} ) {
+
     updateMeet() {
       fetch(MEET_URL, {
         method: "PUT",
@@ -88,40 +93,55 @@
         .then()
     },
 
-    searchGroups() {
-      if ( this.search_groups.length < 2 ) {
-        this.groups = [];
+    searchUsers() {
+      if ( this.search_users.length < 2 ) {
+        this.users = [];
         return true;
       }
 
-      fetch(GROUPS_URL + '?search=' + this.search_groups )
+      fetch(USERS_URL + '?search=' + this.search_users )
         .then((res) => res.json())
         .then(res => {
-            this.groups = res;
+            this.users = res;
         })
     },
 
-    addGroups() {
-      if ( this.selected_groups.length == 0) {
+    deleteMeet() {
+      fetch(MEET_URL, {
+        method: "DELETE",
+        headers: API_HEADERS,
+      })
+        .then( response => {
+            window.location.replace("/");
+        })
+        .catch(() => {
+          this.formError = "<%=l 'ERROR_SERVERSIDE' %>"
+        });
+    },
+
+    addModerators() {
+      if ( this.selected_users.length == 0) {
         return true;
       }
 
-      fetch(ADD_GROUPS_URL, {
+      const selected = this.users.filter(item => this.selected_users.includes(item.id))
+
+      fetch(ADD_USERS_URL, {
         method: "POST",
         headers: API_HEADERS,
-        body: JSON.stringify({ groups: this.selected_groups }),
+        body: JSON.stringify({ users: selected }),
       })
       .then((response) => {
         if (response.ok) {
-            this.selected_groups =[]
-            this.search_groups = ''
+            this.selected_users =[]
+            this.search_users = ''
             this.getMeet()
         }
       })
     },
 
-    removeGroup(id) {
-      fetch(MEET_URL + '/group/' + id, {
+    removeModerator(id) {
+      fetch(MEET_URL + '/moderator/' + id, {
         method: "DELETE",
         headers: API_HEADERS,
       })
@@ -132,42 +152,43 @@
       })
     },
 
-    searchUsers() {
-      if ( this.search_users.length < 2 ) {
-        this.users = [];
+% }
+
+% if ( $roles->{owner} || $roles->{moderator} ) {
+    searchGroups() {
+      if ( this.search_groups.length < 2 ) {
+        this.groups = [];
         return true;
       }
 
-      fetch(USERS_URL + '?search=' + this.search_users )
+      fetch(GROUPS_URL + '?search=' + this.search_groups )
         .then((res) => res.json())
         .then(res => {
-            this.users = res;
+            this.groups = res;
         })
     },
 
-    addModerators() {
-      if ( this.selected_users.length == 0) {
+    addGroups() {
+      if ( this.selected_groups.length == 0) {
         return true;
       }
 
-      const selected = this.users.filter(item => this.selected_users.includes(item.id))
-
-      fetch(ADD_USERS_URL, {
+      fetch(ADD_GROUPS_URL, {
         method: "POST",
         headers: API_HEADERS,
-        body: JSON.stringify({ users: selected }),
+        body: JSON.stringify({ groups: this.selected_groups }),
       })
       .then((response) => {
         if (response.ok) {
-            this.selected_users =[]
-            this.search_users = ''
+            this.selected_groups =[]
+            this.search_groups = ''
             this.getMeet()
         }
       })
     },
 
-    removeModerator(id) {
-      fetch(MEET_URL + '/moderator/' + id, {
+    removeGroup(id) {
+      fetch(MEET_URL + '/group/' + id, {
         method: "DELETE",
         headers: API_HEADERS,
       })
@@ -178,20 +199,8 @@
       })
     },
 
-    deleteMeet() {
-      fetch(MEET_URL, {
-        method: "DELETE",
-        headers: API_HEADERS,
-      })
-        .then( response => {
-            window.location.replace("/");
-        })
-        .catch(() => {
-          this.formError = "<%=l 'ERROR_SERVERSIDE' %>"
-        });
-    }
+% }
 
   }).mount()
 
 </script>
-% }
diff --git a/templates/meets.html.ep b/templates/meets.html.ep
index a4d5aa972d81e836333733bd5badf453a968e74b..78120ca9a1b43c58c08f1ab0bdcbd52751305c26 100644
--- a/templates/meets.html.ep
+++ b/templates/meets.html.ep
@@ -1,19 +1,28 @@
 % layout 'default';
 
-<div v-effect="fetchData()" class="grid grid-cols-2 md:grid-cols-3 gap-4" v-cloak>
+<div v-effect="fetchData()" class="grid grid-cols-1 md:grid-cols-2 gap-4" v-cloak>
   <div v-for="meet in meets" class="card elevation-4">
     <div class="card__body">
-      <div class="flex justify-between mb-3">
+      <div class="flex justify-between mb-2 border-b border-dotted border-grey-300">
         <h2 class="head-alt-xs"><a v-bind:href="'/meets/' + meet.id">{{meet.name}}</a></h2>
       </div>
 
-      <div class="text-xs" v-if="meet.groups.length > 0">
+      <div class="text-xs mb-2" v-if="meet.description">{{ meet.description }}</div>
+
+      <div class="text-xs mb-2" v-if="meet.groups.length > 0">
         <strong><%=l 'Authorized groups' %>:</strong>
         <span v-for="(group, index) in meet.groups" class="text-grey-300">
         {{ group.name }}<span v-if="index != meet.groups.length - 1">, </span>
         </span>
       </div>
 
+      <div class="text-xs mb-2" v-if="meet.moderators.length > 0">
+        <strong><%=l 'Moderators' %>:</strong>
+        <span v-for="(moderator, index) in meet.moderators" class="text-grey-300">
+        {{ moderator.name }}<span v-if="index != meet.moderators.length - 1">, </span>
+        </span>
+      </div>
+
     </div>
   </div>
 </div>
@@ -99,4 +108,3 @@
   }).mount()
 
 </script>
-