diff --git a/server/web_app/composer.json b/server/web_app/composer.json
index 2075e56099dcbd0eab3da5f38c027a8c5e5bd563..f407a8cce070bbada204355dc15c7d17728134f7 100644
--- a/server/web_app/composer.json
+++ b/server/web_app/composer.json
@@ -11,6 +11,7 @@
         "doctrine/doctrine-bundle": "^2.13",
         "doctrine/doctrine-migrations-bundle": "^3.4",
         "doctrine/orm": "^3.3",
+        "symfony/asset": "7.2.*",
         "symfony/console": "7.2.*",
         "symfony/dotenv": "7.2.*",
         "symfony/flex": "^2",
@@ -18,8 +19,11 @@
         "symfony/runtime": "7.2.*",
         "symfony/security-bundle": "7.2.*",
         "symfony/security-core": "7.2.*",
+        "symfony/twig-bundle": "7.2.*",
         "symfony/validator": "7.2.*",
-        "symfony/yaml": "7.2.*"
+        "symfony/yaml": "7.2.*",
+        "twig/extra-bundle": "^2.12|^3.0",
+        "twig/twig": "^2.12|^3.0"
     },
     "config": {
         "allow-plugins": {
diff --git a/server/web_app/config/bundles.php b/server/web_app/config/bundles.php
index d1c745acc529dbea17aac1040902965183b399a1..53c245c59fa2c94e3a785d2902d664f084e7e8c8 100644
--- a/server/web_app/config/bundles.php
+++ b/server/web_app/config/bundles.php
@@ -7,4 +7,6 @@ return [
     Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
     Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
     Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
+    Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
+    Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
 ];
diff --git a/server/web_app/config/packages/framework.yaml b/server/web_app/config/packages/framework.yaml
index 7e1ee1f1e0d1183963de0d822c064178a2c4422c..23797d50b9d9645d7a31f5d27813f454d23f4a76 100644
--- a/server/web_app/config/packages/framework.yaml
+++ b/server/web_app/config/packages/framework.yaml
@@ -10,6 +10,8 @@ framework:
 
 when@test:
     framework:
+        router:
+            strict_requirements: null
         test: true
         session:
             storage_factory_id: session.storage.factory.mock_file
diff --git a/server/web_app/config/packages/security.yaml b/server/web_app/config/packages/security.yaml
index 367af25a56d2decba5041becc5770b16c91b60d4..e02fa5807db32ee5e86328cc6e9ecc76d71bb3cf 100644
--- a/server/web_app/config/packages/security.yaml
+++ b/server/web_app/config/packages/security.yaml
@@ -4,14 +4,25 @@ security:
         Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
     # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
     providers:
-        users_in_memory: { memory: null }
+        app_user_provider:
+            entity:
+                class: App\Entity\User
+                property: userName
+
     firewalls:
-        dev:
-            pattern: ^/(_(profiler|wdt)|css|images|js)/
-            security: false
         main:
             lazy: true
-            provider: users_in_memory
+            provider: app_user_provider
+
+            form_login:
+                login_path: app_login
+                check_path: app_login_check
+                default_target_path: home
+
+            logout:
+                path: app_logout
+                # where to redirect after logout
+                # target: app_any_route
 
             # activate different ways to authenticate
             # https://symfony.com/doc/current/security.html#the-firewall
@@ -22,18 +33,19 @@ security:
     # Easy way to control access for large sections of your site
     # Note: Only the *first* access control that matches will be used
     access_control:
-        # - { path: ^/admin, roles: ROLE_ADMIN }
-        # - { path: ^/profile, roles: ROLE_USER }
+        - { path: ^/login, roles: PUBLIC_ACCESS }  # Allow access to the login page
+        - { path: ^/dashboard, roles: ROLE_ADMIN }  # Secure the dashboard
+        - { path: ^/profile, roles: ROLE_USER }     # Secure user profiles
 
-when@test:
-    security:
-        password_hashers:
-            # By default, password hashers are resource intensive and take time. This is
-            # important to generate secure password hashes. In tests however, secure hashes
-            # are not important, waste resources and increase test times. The following
-            # reduces the work factor to the lowest possible values.
-            Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
-                algorithm: auto
-                cost: 4 # Lowest possible value for bcrypt
-                time_cost: 3 # Lowest possible value for argon
-                memory_cost: 10 # Lowest possible value for argon
+# when@test:
+#     security:
+#         password_hashers:
+#             # By default, password hashers are resource intensive and take time. This is
+#             # important to generate secure password hashes. In tests however, secure hashes
+#             # are not important, waste resources and increase test times. The following
+#             # reduces the work factor to the lowest possible values.
+#             Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
+#                 algorithm: auto
+#                 cost: 4 # Lowest possible value for bcrypt
+#                 time_cost: 3 # Lowest possible value for argon
+#                 memory_cost: 10 # Lowest possible value for argon
diff --git a/server/web_app/config/packages/twig.yaml b/server/web_app/config/packages/twig.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8f597df0bd1a6e78f44f6097bcb40735daa470f6
--- /dev/null
+++ b/server/web_app/config/packages/twig.yaml
@@ -0,0 +1,9 @@
+twig:
+    file_name_pattern: '*.twig'
+    default_path: '%kernel.project_dir%/templates'
+    paths:
+        '%kernel.project_dir%/templates': ~
+
+when@test:
+    twig:
+        strict_variables: true
diff --git a/server/web_app/config/routes.yaml b/server/web_app/config/routes.yaml
index 41ef8140ba811c0da46ce1962ffa50d4c56b9840..dbdcf2c70a5677b874b54bb1b0585ee13a8f3ccb 100644
--- a/server/web_app/config/routes.yaml
+++ b/server/web_app/config/routes.yaml
@@ -3,3 +3,7 @@ controllers:
         path: ../src/Controller/
         namespace: App\Controller
     type: attribute
+
+app_login_check:
+    path: /login_check
+
diff --git a/server/web_app/migrations/Version20250312182453.php b/server/web_app/migrations/Version20250319155149.php
similarity index 90%
rename from server/web_app/migrations/Version20250312182453.php
rename to server/web_app/migrations/Version20250319155149.php
index 0fd37f30a0f73d43ebd6d96854db3465b97aae36..d2e3ff7063d03173db878d94cafe1409452d8bf0 100644
--- a/server/web_app/migrations/Version20250312182453.php
+++ b/server/web_app/migrations/Version20250319155149.php
@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
 /**
  * Auto-generated Migration: Please modify to your needs!
  */
-final class Version20250312182453 extends AbstractMigration
+final class Version20250319155149 extends AbstractMigration
 {
     public function getDescription(): string
     {
@@ -25,12 +25,12 @@ final class Version20250312182453 extends AbstractMigration
         $this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, user_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, surname VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, is_blocked TINYINT(1) DEFAULT 0 NOT NULL, role VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_8D93D64924A232CF (user_name), UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
         $this->addSql('CREATE TABLE wish_list (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255) DEFAULT NULL, expiration_date DATETIME DEFAULT NULL, is_active TINYINT(1) DEFAULT 1 NOT NULL, url_view_mode VARCHAR(255) NOT NULL, url_edit_mode VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_5B8739BDA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
         $this->addSql('CREATE TABLE wish_list_member (id INT AUTO_INCREMENT NOT NULL, wish_list_id INT NOT NULL, user_id INT NOT NULL, can_edit TINYINT(1) DEFAULT NULL, is_accepted TINYINT(1) DEFAULT 0, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_F4CA81DFD69F3311 (wish_list_id), INDEX IDX_F4CA81DFA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
-        $this->addSql('ALTER TABLE item ADD CONSTRAINT FK_1F1B251ED69F3311 FOREIGN KEY (wish_list_id) REFERENCES wish_list (id)');
-        $this->addSql('ALTER TABLE purchase ADD CONSTRAINT FK_6117D13BA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
-        $this->addSql('ALTER TABLE purchase ADD CONSTRAINT FK_6117D13B126F525E FOREIGN KEY (item_id) REFERENCES item (id)');
-        $this->addSql('ALTER TABLE wish_list ADD CONSTRAINT FK_5B8739BDA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
-        $this->addSql('ALTER TABLE wish_list_member ADD CONSTRAINT FK_F4CA81DFD69F3311 FOREIGN KEY (wish_list_id) REFERENCES wish_list (id)');
-        $this->addSql('ALTER TABLE wish_list_member ADD CONSTRAINT FK_F4CA81DFA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
+        $this->addSql('ALTER TABLE item ADD CONSTRAINT FK_1F1B251ED69F3311 FOREIGN KEY (wish_list_id) REFERENCES wish_list (id) ON DELETE CASCADE');
+        $this->addSql('ALTER TABLE purchase ADD CONSTRAINT FK_6117D13BA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE');
+        $this->addSql('ALTER TABLE purchase ADD CONSTRAINT FK_6117D13B126F525E FOREIGN KEY (item_id) REFERENCES item (id) ON DELETE CASCADE');
+        $this->addSql('ALTER TABLE wish_list ADD CONSTRAINT FK_5B8739BDA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE');
+        $this->addSql('ALTER TABLE wish_list_member ADD CONSTRAINT FK_F4CA81DFD69F3311 FOREIGN KEY (wish_list_id) REFERENCES wish_list (id) ON DELETE CASCADE');
+        $this->addSql('ALTER TABLE wish_list_member ADD CONSTRAINT FK_F4CA81DFA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE');
     }
 
     public function down(Schema $schema): void
diff --git a/server/web_app/public/css/dashboard.css b/server/web_app/public/css/dashboard.css
new file mode 100644
index 0000000000000000000000000000000000000000..2f2ec2ec0de53b5953848019ac48fbdb72f04c0b
--- /dev/null
+++ b/server/web_app/public/css/dashboard.css
@@ -0,0 +1,48 @@
+@import url('global.css');
+
+.container {
+  display: flex;
+  justify-content: space-around;
+  flex-wrap: wrap;
+  gap: var(--margin-space-normal);
+}
+
+.card {
+  display: block;
+  width: 16rem;
+  max-height: 26rem;
+  color: black;
+  border-radius: 15px;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+  text-decoration: none;
+  transition: transform 0.3s ease, box-shadow 0.3s ease;
+  background-color: var(--color-complementary);
+}
+
+.card:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
+}
+
+.card article {
+  text-align: center;
+}
+
+.card img {
+  width: 100%;
+  object-fit: cover;
+  border-radius: 15px 0px;
+}
+
+.card h4 {
+  font-size: var(--font-size-big);
+  color: var(--color-hover);
+  margin: 10px 0;
+}
+
+.card p {
+  font-size: var(--font-size-normal);
+  line-height: 1.5;
+  padding: var(--padding-space-normal);
+}
diff --git a/server/web_app/public/css/global.css b/server/web_app/public/css/global.css
new file mode 100644
index 0000000000000000000000000000000000000000..a868886906392770e04b221d96d5f7d5b91db5cf
--- /dev/null
+++ b/server/web_app/public/css/global.css
@@ -0,0 +1,52 @@
+:root {
+  --font-size-normal: 1rem;
+  --font-size-small: 0.8rem;
+  --font-size-big: 1.5rem;
+  --font-size-extrabig: 2rem;
+
+  --line-heigth-small: 1.2rem;
+  --line-heigth-normal: 1.5rem;
+  --line-heigth-large: 1.7rem;
+
+  --padding-space-large: 2rem;
+  --padding-space-normal: 1rem;
+  --padding-space-small: 0.5rem;
+
+  --margin-space-large: 3rem;
+  --margin-space-normal: 2rem;
+  --margin-space-small: 1rem;
+  --margin-space-xsmall: 0.5rem;
+
+  --border-thin: 1px;
+  --border-normal: 3px;
+  --border-thick: 5px;
+
+  --font-family-style: Helvetica, Arial, sans-serif;
+
+  --color-basic: #00B8DE;
+  --color-hover:#14223C;
+  --color-secondary: #99CC99;
+  --color-light: #EDF3F4;
+  --color-complementary: #FFFFFF;
+
+  --font-weight-light: 300;
+  --font-weight-regular: 500;
+  --font-weight-bold: 700;
+}
+
+* {
+  box-sizing: border-box;
+  font-family: var(--font-family-style);
+  line-height: var(--line-heigth-normal);
+  font-weight: var(--font-weight-regular);
+  margin: 0;
+  padding: 0;
+}
+
+body {
+  background-color: var(--color-light);
+}
+
+.container {
+  margin: var(--padding-space-large);
+}
diff --git a/server/web_app/public/css/insights.css b/server/web_app/public/css/insights.css
new file mode 100644
index 0000000000000000000000000000000000000000..20d32d76fcd3da6fc04a81066945a287b525a26a
--- /dev/null
+++ b/server/web_app/public/css/insights.css
@@ -0,0 +1 @@
+@import url('global.css');
diff --git a/server/web_app/public/css/login.css b/server/web_app/public/css/login.css
new file mode 100644
index 0000000000000000000000000000000000000000..20d32d76fcd3da6fc04a81066945a287b525a26a
--- /dev/null
+++ b/server/web_app/public/css/login.css
@@ -0,0 +1 @@
+@import url('global.css');
diff --git a/server/web_app/public/css/menu.css b/server/web_app/public/css/menu.css
new file mode 100644
index 0000000000000000000000000000000000000000..f47392a260800e4cb6f68a5b12c2fd563bdba957
--- /dev/null
+++ b/server/web_app/public/css/menu.css
@@ -0,0 +1,42 @@
+@import url('global.css');
+
+nav {
+  background-color: var(--color-hover);
+  width: 100%;
+}
+
+nav ul {
+  list-style-type: none;
+  padding: 0;
+  margin: 0;
+  display: flex;
+  flex-direction: row;
+}
+
+nav ul li {
+  margin: var(--margin-space-xsmall) 0;
+}
+
+nav ul li a {
+  color: var(--color-complementary);
+  text-decoration: none;
+  font-size: var(--font-size-normal);
+  display: block;
+  padding: var(--padding-space-normal);
+  border-radius: var(--padding-space-small) var(--border-thick);
+  transition: background-color 0.3s, color 0.3s;
+}
+
+nav ul li a:hover {
+  background-color: var(--color-secondary);
+}
+
+.login {
+  margin-left: auto;
+}
+
+h3 {
+  margin: var(--margin-space-small) auto;
+  text-align: center;
+  font-size: var(--font-size-extrabig);
+}
diff --git a/server/web_app/public/css/users.css b/server/web_app/public/css/users.css
new file mode 100644
index 0000000000000000000000000000000000000000..ace1e04072466a8f47b640b533029a44db6d04e6
--- /dev/null
+++ b/server/web_app/public/css/users.css
@@ -0,0 +1,67 @@
+@import url('global.css');
+
+table {
+  width: 100%;
+  border-collapse: collapse;
+  background-color: var(--color-complementary);
+}
+
+table th, table td {
+  border: var(--border-thin) solid var(--color-hover);
+  padding: var(--padding-space-small);
+  text-align: left;
+}
+
+table th {
+  background-color: var(--color-hover);
+  color: var(--color-complementary);
+}
+
+button {
+  padding: 6px 12px;
+  margin: var(--margin-space-xsmall);
+  border: none;
+  border-radius: var(--border-thick);
+  color: var(--color-complementary);
+  cursor: pointer;
+  background-color: var(--color-basic);
+}
+
+button:hover {
+  background-color: var(--color-hover);
+  color: var(--color-complementary);
+}
+
+button:disabled {
+  background-color: var(--color-light);
+  color: black;
+}
+
+/* Basic Styles for the Popup */
+.popup {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000;
+}
+
+.popup p, .popup h4 {
+  margin: var(--margin-space-xsmall) 0;
+}
+
+.popup-content {
+  background-color: #fff;
+  padding: 20px;
+  border-radius: 5px;
+  text-align: center;
+}
+
+.popup button {
+  margin: 10px;
+}
diff --git a/server/web_app/public/img/gifts.png b/server/web_app/public/img/gifts.png
new file mode 100644
index 0000000000000000000000000000000000000000..7db1ba5883eecbb7abe073eb98118e88568d8808
Binary files /dev/null and b/server/web_app/public/img/gifts.png differ
diff --git a/server/web_app/public/img/users.png b/server/web_app/public/img/users.png
new file mode 100644
index 0000000000000000000000000000000000000000..d4a17a125919cecb86df413b2d58453b074490b4
Binary files /dev/null and b/server/web_app/public/img/users.png differ
diff --git a/server/web_app/public/js/insights.js b/server/web_app/public/js/insights.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/web_app/public/js/login.js b/server/web_app/public/js/login.js
new file mode 100644
index 0000000000000000000000000000000000000000..2739a137af27ff6ae936cebdca6917a73908a096
--- /dev/null
+++ b/server/web_app/public/js/login.js
@@ -0,0 +1,31 @@
+ROUTE='http://localhost';
+PORT='8080';
+
+const loginForm = document.getElementById('login-form');
+loginForm.addEventListener('submit', async function(event) {
+    event.preventDefault();
+
+    try {
+        const response = await fetch(`${ROUTE}:${PORT}/users/authenticate`, {
+            method: 'POST',
+            headers: {
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify({
+                username: username,
+                password: password
+            })
+        });
+
+        console.log(response)
+
+        if (response.ok) {
+            window.location.href = '/dashboard';
+        } else {
+            const error = await response.json();
+            alert('Login failed: ' + error.message);
+        }
+    } catch (error) {
+        console.error('Error:', error);
+    }
+});
diff --git a/server/web_app/public/js/users.js b/server/web_app/public/js/users.js
new file mode 100644
index 0000000000000000000000000000000000000000..c5ee46131284e3b99013c4b33fa7b1d6cb55fdb9
--- /dev/null
+++ b/server/web_app/public/js/users.js
@@ -0,0 +1,112 @@
+const ROUTE = 'http://localhost';
+const PORT = '8080';
+let currentAction = null;
+let currentUserId = null;
+let actionType = null; // New variable to track whether it's block or unblock
+
+async function fetchUsers() {
+  const response = await fetch(`${ROUTE}:${PORT}/users`);
+  const data = await response.json();
+  const tableBody = document.querySelector('#usersTable tbody');
+  tableBody.innerHTML = ''; // Clear current table rows
+
+  data.users.forEach(user => {
+      const row = document.createElement('tr');
+      row.innerHTML = `
+          <td>${user.username}</td>
+          <td>${user.name} ${user.surname}</td>
+          <td>${user.mail}</td>
+          <td>
+              <button onclick="toggleBlock(${user.id}, ${user.isBlocked})">
+                  ${user.isBlocked ? 'Unblock' : 'Block'}
+              </button>
+              <button onclick="prepareDeleteUser(${user.id})">Delete</button>
+              <button>Details</button>
+          </td>
+      `;
+      tableBody.appendChild(row);
+  });
+}
+
+// Toggle block/unblock
+async function toggleBlock(userId, isBlocked) {
+  actionType = isBlocked ? 'Unblock' : 'Block'; // Set action type based on block status
+  showConfirmationPopup(actionType, () => {
+    updateBlockStatus(userId, !isBlocked);
+  });
+}
+
+// Prepare for user deletion
+function prepareDeleteUser(userId) {
+  actionType = 'Delete';
+  showConfirmationPopup("Delete this user", () => {
+    deleteUser(userId);
+  });
+}
+
+function disabledButtons() {
+  const button = document.getElementById('confirmBtn');
+  const buttonCancel = document.getElementById('cancelBtn');
+  button.disabled = true;
+  buttonCancel.disabled = true;
+  button.textContent = "Loading...";
+}
+
+// Show confirmation pop-up
+function showConfirmationPopup(message, action) {
+  document.getElementById('popupMessage').innerText = message;
+  document.getElementById('confirmationPopup').style.display = 'flex';
+  currentAction = action;
+}
+
+// Confirm the action
+document.getElementById('confirmBtn').addEventListener('click', () => {
+  if (currentAction) {
+    currentAction();
+    disabledButtons();
+  }
+});
+
+// Cancel the action
+document.getElementById('cancelBtn').addEventListener('click', hideConfirmationPopup);
+
+// Hide the pop-up
+function hideConfirmationPopup() {
+  document.getElementById('confirmationPopup').style.display = 'none';
+}
+
+// Update block/unblock status
+async function updateBlockStatus(userId, isBlocked) {
+  try {
+    const response = await fetch(`${ROUTE}:${PORT}/users/${userId}`, {
+      method: 'PATCH',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify({ isBlocked }),
+    });
+    const data = await response.json();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    hideConfirmationPopup();
+    location.reload();
+  }
+}
+
+// Delete user
+async function deleteUser(userId) {
+  try {
+    const response = await fetch(`${ROUTE}:${PORT}/users/${userId}`, {
+      method: 'DELETE'
+    });
+    const data = await response.json();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    hideConfirmationPopup();
+    location.reload();
+  }
+}
+// Fetch users when the page loads
+window.onload = fetchUsers;
diff --git a/server/web_app/src/Controller/DashboardController.php b/server/web_app/src/Controller/DashboardController.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c9a0ec0b15f678b56c6c5a1887063f446048990
--- /dev/null
+++ b/server/web_app/src/Controller/DashboardController.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Attribute\Route;
+
+#[Route('/dashboard')]
+class DashboardController extends AbstractController
+{
+    #[Route('', name: 'dashboard')]
+    public function index(): Response
+    {
+        if (!$this->isGranted('ROLE_ADMIN')) {
+            return $this->redirectToRoute('error');
+        }
+
+        return $this->render('dashboard.html.twig');
+    }
+
+    #[Route('/users', name: 'manageUsers')]
+    public function users(): Response
+    {
+        if (!$this->isGranted('ROLE_ADMIN')) {
+            return $this->redirectToRoute('error');
+        }
+
+        return $this->render('usersManagement.html.twig');
+    }
+
+    #[Route('/insights', name: 'manageInsights')]
+    public function items(): Response
+    {
+        if (!$this->isGranted('ROLE_ADMIN')) {
+            return $this->redirectToRoute('error');
+        }
+
+        return $this->render('insights.html.twig');
+    }
+}
diff --git a/server/web_app/src/Controller/ErrorController.php b/server/web_app/src/Controller/ErrorController.php
new file mode 100644
index 0000000000000000000000000000000000000000..c94d3ec3bb2fffda2e050165c58ce7504ee30c6b
--- /dev/null
+++ b/server/web_app/src/Controller/ErrorController.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Attribute\Route;
+
+
+class ErrorController extends AbstractController
+{
+    #[Route('/error', name: 'error')]
+    public function index(): Response
+    {
+        return $this->render('error.html.twig');
+    }
+}
diff --git a/server/web_app/src/Controller/MainController.php b/server/web_app/src/Controller/MainController.php
new file mode 100644
index 0000000000000000000000000000000000000000..9296ac25c7ebdf365262db70ed8c6d5e1a18e0a8
--- /dev/null
+++ b/server/web_app/src/Controller/MainController.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Attribute\Route;
+use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
+
+class MainController extends AbstractController
+{
+    #[Route('/', name: 'home')]
+    public function index(): Response
+    {
+        return $this->render('home.html.twig');
+    }
+
+    #[Route('/login', name: 'app_login')]
+    public function login(AuthenticationUtils $authenticationUtils): Response
+    {
+        $error = $authenticationUtils->getLastAuthenticationError();
+        $lastUsername = $authenticationUtils->getLastUsername();
+        return $this->render('login.html.twig', [
+            'last_username' => $lastUsername,
+            'error' => $error,
+        ]);
+    }
+
+    #[Route('/logout', name: 'app_logout')]
+    public function logout(): void
+    {
+
+    }
+}
diff --git a/server/web_app/src/Controller/UserController.php b/server/web_app/src/Controller/UserController.php
index 2cca27f8b8df67f622635e42a7fc186b2701ce9a..346ca5fccad990b1a37935ca87c93260d330695a 100644
--- a/server/web_app/src/Controller/UserController.php
+++ b/server/web_app/src/Controller/UserController.php
@@ -106,7 +106,12 @@ final class UserController extends AbstractController implements UserControllerI
             $userRole = UserRole::from($roleParam);
         }
 
-        $isBlocked = filter_var($req->query->get('isBlocked', null), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+        $isBlockedRaw = $req->query->get('isBlocked', null);
+        if ($isBlockedRaw === null) {
+            $isBlocked = null;
+        } else {
+            $isBlocked = filter_var($isBlockedRaw, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+        }
         
         // Validate "sortBy" to allow only 'createdAt' or 'username'
         $allowedSortBy = ['createdAt', 'username'];
@@ -137,6 +142,8 @@ final class UserController extends AbstractController implements UserControllerI
 
         $userArray = array_map(fn($user) => [
             'id' => $user->getId(),
+            'name' => $user->getName(),
+            'surname' => $user->getSurname(),
             'username' => $user->getUserName(),
             'mail' => $user->getEmail(),
             'role' => $user->getRoles(),
@@ -268,15 +275,6 @@ final class UserController extends AbstractController implements UserControllerI
         ]);
     }
 
-    #[Route('/authenticate', methods: ['POST'])]
-    public function authenticateUser(string $username, string $password): JsonResponse
-    {
-        return $this->json([
-            'message' => 'Welcome to your new controller!',
-            'path' => 'src/Controller/UserController.php',
-        ]);
-    }
-
     #[Route('/authenticate/changePassword', methods: ['POST'])]
     public function changePassword(int $userId, string $oldPassword, string $newPassword): JsonResponse
     {
diff --git a/server/web_app/src/Entity/Item.php b/server/web_app/src/Entity/Item.php
index 84d0437096d340d7d109ac3a6c77b773e8038791..2de51983b9744e0b3badca30a8010327874d9362 100644
--- a/server/web_app/src/Entity/Item.php
+++ b/server/web_app/src/Entity/Item.php
@@ -15,7 +15,7 @@ class Item
     private ?int $id = null;
 
     #[ORM\ManyToOne(targetEntity: WishList::class)]
-    #[ORM\JoinColumn(nullable: false)]
+    #[ORM\JoinColumn(nullable: false, onDelete: "CASCADE")]
     #[Assert\NotNull(message: "WishList must be selected.")]
     private ?WishList $wishList = null;
 
diff --git a/server/web_app/src/Entity/Purchase.php b/server/web_app/src/Entity/Purchase.php
index edb95c7c14e3f8f5fb51f9ee54c829f4618a4535..0640329e5ed7653be406c6b06db16596ecf66e55 100644
--- a/server/web_app/src/Entity/Purchase.php
+++ b/server/web_app/src/Entity/Purchase.php
@@ -11,12 +11,12 @@ class Purchase
 {
     #[ORM\Id]
     #[ORM\ManyToOne(targetEntity: User::class)]
-    #[ORM\JoinColumn(nullable: false)]
+    #[ORM\JoinColumn(nullable: false, onDelete: "CASCADE")]
     private ?User $user = null;
 
     #[ORM\id]
     #[ORM\ManyToOne(targetEntity: Item::class)]
-    #[ORM\JoinColumn(nullable: false)]
+    #[ORM\JoinColumn(nullable: false, onDelete: "CASCADE")]
     private ?Item $item = null;
 
     #[ORM\Column(length: 255, nullable: true)]
diff --git a/server/web_app/src/Entity/User.php b/server/web_app/src/Entity/User.php
index c7dc58636082b26da39926b8273b0496a9df4767..7ecc797216da40c9b2ade8941a977e173d86baaf 100644
--- a/server/web_app/src/Entity/User.php
+++ b/server/web_app/src/Entity/User.php
@@ -154,7 +154,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
     //Methods neeeded to be implemented here because of the extension of UserInterface, PasswordAuthenticatedUserInterface
     public function getRoles(): array
     {
-        return [$this->role->value]; // Assuming UserRole is an enum with string values
+        return ['ROLE_' . strtoupper($this->role->value)]; // Assuming UserRole is an enum with string values
     }
 
     public function getUserIdentifier(): string
diff --git a/server/web_app/src/Entity/WishList.php b/server/web_app/src/Entity/WishList.php
index 8849ca9b43b3bce5f2ef5bb33057fce6ef77a19c..3566b69e30e533bba255e1118535058b14b3f3c7 100644
--- a/server/web_app/src/Entity/WishList.php
+++ b/server/web_app/src/Entity/WishList.php
@@ -18,7 +18,7 @@ class WishList
     private ?int $id = null;
 
     #[ORM\ManyToOne(targetEntity: User::class)]
-    #[ORM\JoinColumn(nullable: false)]
+    #[ORM\JoinColumn(nullable: false, onDelete: "CASCADE")]
     #[Assert\NotNull(message: "User must be provided.")]
     private ?User $user = null;
 
diff --git a/server/web_app/src/Entity/WishListMember.php b/server/web_app/src/Entity/WishListMember.php
index 0d4deabd41ebfbc859fc2e7e816eea97723b8e1e..6c3e35e25ce4c534feb0ad4ba65f17d032b74147 100644
--- a/server/web_app/src/Entity/WishListMember.php
+++ b/server/web_app/src/Entity/WishListMember.php
@@ -15,12 +15,12 @@ class WishListMember
     private ?int $id = null;
 
     #[ORM\ManyToOne(targetEntity: WishList::class)]
-    #[ORM\JoinColumn(nullable: false)]
+    #[ORM\JoinColumn(nullable: false, onDelete: "CASCADE")]
     #[Assert\NotNull(message: "WishList must be provided.")]
     private ?WishList $wishList = null;
 
     #[ORM\ManyToOne(targetEntity: User::class)]
-    #[ORM\JoinColumn(nullable: false)]
+    #[ORM\JoinColumn(nullable: false, onDelete: "CASCADE")]
     #[Assert\NotNull(message: "User must be provided.")]
     private ?User $user = null;
 
diff --git a/server/web_app/src/Interface/UserControllerInterface.php b/server/web_app/src/Interface/UserControllerInterface.php
index 92a41838ddc07c2083948d10982a3d3160436dbb..fc77f16a020b3af3a3e4abfb6f430dbca368a8aa 100644
--- a/server/web_app/src/Interface/UserControllerInterface.php
+++ b/server/web_app/src/Interface/UserControllerInterface.php
@@ -16,7 +16,5 @@ interface UserControllerInterface
 
     public function deleteUser(int $userId): Response;
 
-    public function authenticateUser(string $username, string $password): Response;
-
     public function changePassword(int $userId, string $oldPassword, string $newPassword): Response;
 }
diff --git a/server/web_app/symfony.lock b/server/web_app/symfony.lock
index 4ddf444e42085914d334d9b5aff511569e222a5a..a0a4776bd1ea97edbf7854c11b7c2eb53a9fd8a6 100644
--- a/server/web_app/symfony.lock
+++ b/server/web_app/symfony.lock
@@ -117,6 +117,19 @@
             "config/routes/security.yaml"
         ]
     },
+    "symfony/twig-bundle": {
+        "version": "7.2",
+        "recipe": {
+            "repo": "github.com/symfony/recipes",
+            "branch": "main",
+            "version": "6.4",
+            "ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877"
+        },
+        "files": [
+            "config/packages/twig.yaml",
+            "templates/base.html.twig"
+        ]
+    },
     "symfony/validator": {
         "version": "7.2",
         "recipe": {
@@ -128,5 +141,8 @@
         "files": [
             "config/packages/validator.yaml"
         ]
+    },
+    "twig/extra-bundle": {
+        "version": "v3.20.0"
     }
 }
diff --git a/server/web_app/templates/base.html.twig b/server/web_app/templates/base.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..68d3bc31b9010af25e98a9d6b137450d1a8e272f
--- /dev/null
+++ b/server/web_app/templates/base.html.twig
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  {% block styles %}{% endblock %}
+  <title>{% block title %}Wishlist app{% endblock %}</title>
+</head>
+<body>
+  {% include 'menu.html.twig' %}
+  {% block body %}{% endblock %}
+</body>
+</html>
\ No newline at end of file
diff --git a/server/web_app/templates/dashboard.html.twig b/server/web_app/templates/dashboard.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..75ab75c400a85f2ce1b8480f041808c8ecd164cc
--- /dev/null
+++ b/server/web_app/templates/dashboard.html.twig
@@ -0,0 +1,24 @@
+{% extends 'base.html.twig' %}
+
+{% block styles %}
+  <link rel="stylesheet" href="{{ asset('css/dashboard.css') }}">
+{% endblock %}
+
+{% block body %}
+  <section class="container">
+    <a class="card" href="{{ path('manageInsights') }}">
+      <article>
+        <img src="{{ asset('img/gifts.png') }}" alt="">
+        <h4>Insights</h4>
+        <p>View insights about system's lists and system's items.</p>
+      </article>
+    </a>
+    <a class="card" href="{{ path('manageUsers') }}">
+      <article>
+        <img src="{{ asset('img/users.png') }}" alt="">
+        <h4>Users</h4>
+          <p>Administrate users.</p>
+      </article>
+    </a>
+  </section>
+{% endblock %}
diff --git a/server/web_app/templates/error.html.twig b/server/web_app/templates/error.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..f17a6b72a569ff2ebaa3e0119345b2d9bc9671e5
--- /dev/null
+++ b/server/web_app/templates/error.html.twig
@@ -0,0 +1 @@
+{% block body %} This page does not exist or you do not have rigths to see {% endblock %}
\ No newline at end of file
diff --git a/server/web_app/templates/home.html.twig b/server/web_app/templates/home.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..06d07ac7e2611893faa199e9a9867c77c5078bb5
--- /dev/null
+++ b/server/web_app/templates/home.html.twig
@@ -0,0 +1,3 @@
+{% extends 'base.html.twig' %}
+
+{% block body %} Welcome {% endblock %}
diff --git a/server/web_app/templates/insights.html.twig b/server/web_app/templates/insights.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..f682d0e2ad52b5b4f7114c4dca850b0f4d3f3992
--- /dev/null
+++ b/server/web_app/templates/insights.html.twig
@@ -0,0 +1,9 @@
+{% extends 'base.html.twig' %}
+
+{% block styles %}
+  <link rel="stylesheet" href="{{ asset('css/insights.css') }}">
+{% endblock %}
+
+{% block body %}
+
+{% endblock %}
diff --git a/server/web_app/templates/login.html.twig b/server/web_app/templates/login.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..7bb685f0d2a021aec66977f46866fb2e72d8de59
--- /dev/null
+++ b/server/web_app/templates/login.html.twig
@@ -0,0 +1,26 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}Log in!{% endblock %}
+
+{% block styles %}
+  <link rel="stylesheet" href="{{ asset('css/login.css') }}">
+{% endblock %}
+
+{% block body %}
+    <form action="{{ path('app_login_check') }}" method="post">
+
+        <h3>Please sign in</h3>
+        <label for="username">User Name</label>
+        <input type="text" value="{{ last_username }}" name="_username" id="username" class="form-control" autocomplete="username" required autofocus>
+        <label for="password">Password</label>
+        <input type="password" name="_password" id="password" class="form-control" autocomplete="current-password" required>
+
+        <input type="hidden" name="_csrf_token"
+            value="{{ csrf_token('authenticate') }}"
+        >
+
+        <button>
+            Sign in
+        </button>
+    </form>
+{% endblock %}
diff --git a/server/web_app/templates/menu.html.twig b/server/web_app/templates/menu.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..253cf91836820b5bc5c53f8cd8045ef7576e2605
--- /dev/null
+++ b/server/web_app/templates/menu.html.twig
@@ -0,0 +1,19 @@
+{% block styles %}
+  <link rel="stylesheet" href="{{ asset('css/menu.css') }}">
+{% endblock %}
+
+<nav>
+    <ul>
+        <li><a href=#>My wishlists</a></li>
+        <li><a href=#>Shared wishlists</a></li>
+        {% if is_granted('ROLE_ADMIN') %}
+            <li><a href="{{ path('dashboard') }}">Dashboard </a></li>
+        {% endif %}
+
+        {% if app.user %}
+            <li class="login"><a href="{{ path('app_logout') }}">Logout</a></li>
+        {% else %}
+            <li class="login"><a href="{{ path('app_login') }}">Login</a></li>
+        {% endif %}
+    </ul>
+</nav>
\ No newline at end of file
diff --git a/server/web_app/templates/usersManagement.html.twig b/server/web_app/templates/usersManagement.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..1c168895ed9450edd3d99d1175a393901a0e693c
--- /dev/null
+++ b/server/web_app/templates/usersManagement.html.twig
@@ -0,0 +1,36 @@
+{% extends 'base.html.twig' %}
+
+{% block styles %}
+  <link rel="stylesheet" href="{{ asset('css/users.css') }}">
+{% endblock %}
+
+{% block body %}
+    <h3>User control panel</h3>
+
+    <article class="container">
+        <table id="usersTable">
+            <thead>
+                <tr>
+                    <th>Username</th>
+                    <th>Name</th>
+                    <th>Email</th>
+                    <th>Actions</th>
+                </tr>
+            </thead>
+            <tbody>
+            </tbody>     
+        </table>
+    </article>
+
+    <!-- Popup Modal -->
+    <div id="confirmationPopup" class="popup" style="display: none;">
+        <div class="popup-content">
+            <h4>Are you sure?</h4>
+            <p id="popupMessage"></p>
+            <button id="confirmBtn" class="btn btn-danger">Yes</button>
+            <button id="cancelBtn" class="btn btn-secondary">Cancel</button>
+        </div>
+    </div>
+
+    <script src="{{ asset('js/users.js') }}"></script>
+{% endblock %}