вот мой фрон адаптируй его под бек и напиши структуру фронта куда что создать и написать 
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Хика Морi - АнимеСообщество</title>
    <!-- Подключение Google Fonts -->
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">
    <style>
        /* Переменные для цветовой схемы */
        :root {
            --primary-color: #ff4081;
            --secondary-color: #e62770;
            --background-color: #f0f0f0;
            --navbar-bg-color: rgba(255, 64, 129, 0.95);
            --navbar-hover-bg-color: rgba(255, 64, 129, 1);
            --text-color: #333;
            --light-text-color: #666;
            --card-bg-color: rgba(255, 255, 255, 0.95);
            --modal-bg-color: rgba(255, 255, 255, 0.95);
            --shadow-color: rgba(0, 0, 0, 0.1);
            --transition-speed: 0.3s;
        }

        /* Основные стили */
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Roboto', sans-serif;
            background-color: var(--background-color);
            overflow-x: hidden;
            background-image: url('https://i.imgur.com/oPz4cZC.jpg'); /* Замените на вашу ссылку */
            background-size: cover;
            background-repeat: no-repeat;
            background-attachment: fixed;
            transition: background-color 0.5s ease;
            /* Анимированный градиентный фон */
            animation: gradientBackground 15s ease infinite;
        }

        @keyframes gradientBackground {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }

        /* Навигационная панель */
        .navbar {
            display: flex;
            align-items: center;
            justify-content: space-between;
            background-color: var(--navbar-bg-color);
            padding: 15px 30px;
            color: white;
            position: sticky;
            top: 0;
            z-index: 1000;
            box-shadow: 0 4px 6px var(--shadow-color);
            transition: background-color var(--transition-speed), box-shadow var(--transition-speed);
        }

        .navbar:hover {
            background-color: var(--navbar-hover-bg-color);
            box-shadow: 0 6px 12px rgba(0,0,0,0.2);
        }

        .navbar .logo {
            font-family: 'Noto Sans JP', sans-serif;
            font-size: 28px;
            font-weight: 700;
            cursor: pointer;
            transition: transform var(--transition-speed), color var(--transition-speed);
        }

        .navbar .logo:hover {
            transform: scale(1.1);
            color: #ffe6f0;
        }

        .navbar .nav-icons {
            display: flex;
            gap: 25px;
            cursor: pointer;
            font-size: 20px;
        }

        .navbar .nav-icons span {
            display: flex;
            align-items: center;
            gap: 5px;
            transition: color var(--transition-speed), transform var(--transition-speed);
        }

        .navbar .nav-icons span:hover {
            color: var(--secondary-color);
            transform: scale(1.1);
        }

        /* Секции */
        .section {
            display: none;
            padding: 30px 50px;
            animation: fadeIn 0.5s ease-in;
            background-color: rgba(255, 255, 255, 0.85);
            border-radius: 12px;
            margin: 30px auto;
            max-width: 1200px;
            box-shadow: 0 4px 8px var(--shadow-color);
            backdrop-filter: blur(10px);
            transition: all var(--transition-speed) ease;
        }

        .active {
            display: block;
        }

        /* Улучшенные стили для постов */
        .feed .post {
            background-color: var(--card-bg-color);
            padding: 20px;
            margin-bottom: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 8px var(--shadow-color);
            animation: fadeInUp 0.5s ease-out;
            display: flex;
            flex-direction: column;
            transition: transform var(--transition-speed), box-shadow var(--transition-speed), background-color var(--transition-speed);
        }

        .feed .post:hover {
            transform: translateY(-5px) scale(1.02);
            box-shadow: 0 8px 16px rgba(0,0,0,0.2);
            background-color: #ffffff;
        }

        .feed .post .post-header {
            display: flex;
            align-items: center;
            gap: 15px;
        }

        .feed .post .post-header img {
            width: 50px;
            height: 50px;
            border-radius: 50%;
            transition: transform var(--transition-speed), filter var(--transition-speed);
            filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
        }

        .feed .post .post-header img:hover {
            transform: scale(1.1) rotate(5deg);
            filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
        }

        .feed .post .post-header strong {
            font-size: 18px;
            color: var(--text-color);
            font-weight: 500;
        }

        .feed .post .post-content {
            margin-top: 15px;
            animation: slideIn 0.3s ease-out;
            position: relative;
            font-size: 16px;
            color: var(--text-color);
        }

        .feed .post .post-content img {
            width: 100%;
            max-height: 350px;
            object-fit: cover;
            border-radius: 8px;
            margin-top: 15px;
            transition: transform var(--transition-speed), filter var(--transition-speed);
            filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
        }

        .feed .post .post-content img:hover {
            transform: scale(1.05);
            filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
        }

        .feed .post .post-actions {
            display: flex;
            align-items: center;
            gap: 20px;
            margin-top: 15px;
        }

        .feed .post .post-actions span {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
            color: #555;
            transition: color var(--transition-speed), transform var(--transition-speed), background-color var(--transition-speed);
            padding: 5px 15px;
            border-radius: 25px;
            background-color: rgba(255, 255, 255, 0.3);
        }

        .feed .post .post-actions span:hover {
            color: #fff;
            background-color: var(--primary-color);
            transform: scale(1.1);
        }

        /* Форма создания поста */
        .create-post h2,
        .anime-watch h2,
        .profile h2,
        .community h2 {
            margin-top: 0;
            color: var(--primary-color);
            font-family: 'Noto Sans JP', sans-serif;
            font-size: 28px;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
        }

        .create-post textarea,
        .anime-watch .search-bar input,
        .comments-section .comment-input,
        .modal-content input,
        .modal-content textarea {
            width: 100%;
            padding: 15px;
            border-radius: 8px;
            border: 1px solid #ccc;
            resize: none;
            font-size: 16px;
            box-sizing: border-box;
            transition: border-color var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
            background-color: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(5px);
            margin-bottom: 15px;
            font-family: 'Roboto', sans-serif;
        }

        .create-post textarea:focus,
        .anime-watch .search-bar input:focus,
        .comments-section .comment-input:focus,
        .modal-content input:focus,
        .modal-content textarea:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 5px rgba(255, 64, 129, 0.5);
            outline: none;
        }

        .create-post button,
        .anime-watch .search-bar button,
        .comments-section button,
        .modal-content button {
            padding: 12px 25px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            transition: background-color var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
            font-size: 16px;
            font-family: 'Roboto', sans-serif;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }

        .create-post button:hover,
        .anime-watch .search-bar button:hover,
        .comments-section button:hover,
        .modal-content button:hover {
            background-color: var(--secondary-color);
            transform: scale(1.05);
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
        }

        /* Профиль пользователя */
        .profile .profile-header {
            display: flex;
            align-items: center;
            gap: 25px;
            margin-bottom: 20px;
        }

        .profile .profile-header img {
            width: 120px;
            height: 120px;
            border-radius: 50%;
            transition: transform var(--transition-speed) ease, filter var(--transition-speed) ease;
            filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
        }

        .profile .profile-header img:hover {
            transform: scale(1.1) rotate(5deg);
            filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
        }

        .profile .profile-header h2 {
            margin: 0;
            color: var(--text-color);
            font-size: 24px;
        }

        .profile .profile-header p {
            color: var(--light-text-color);
            font-size: 16px;
        }

        .profile .profile-content h3 {
            margin-bottom: 10px;
            color: var(--primary-color);
            text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
            font-size: 22px;
        }

        .profile .profile-content p {
            line-height: 1.6;
            font-size: 16px;
            color: var(--text-color);
        }

        /* Раздел просмотра аниме */
        .anime-watch .anime-list {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 25px;
            animation: fadeIn 0.5s ease-in;
        }

        .anime-watch .anime-item {
            background-color: var(--card-bg-color);
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 4px 8px var(--shadow-color);
            display: flex;
            flex-direction: column;
            transition: transform var(--transition-speed), box-shadow var(--transition-speed), background-color var(--transition-speed);
            cursor: pointer;
        }

        .anime-watch .anime-item:hover {
            transform: scale(1.02);
            box-shadow: 0 8px 16px rgba(0,0,0,0.2);
            background-color: #ffffff;
        }

        .anime-watch .anime-item img {
            width: 100%;
            height: 300px;
            object-fit: cover;
            transition: transform var(--transition-speed) ease;
        }

        .anime-watch .anime-item:hover img {
            transform: scale(1.05);
        }

        .anime-watch .anime-info {
            padding: 15px;
            display: flex;
            flex-direction: column;
            flex-grow: 1;
        }

        .anime-watch .anime-info h3 {
            margin: 0 0 10px 0;
            font-size: 20px;
            color: var(--text-color);
            transition: color var(--transition-speed) ease;
        }

        .anime-watch .anime-info h3:hover {
            color: var(--primary-color);
        }

        .anime-watch .anime-info p {
            flex-grow: 1;
            font-size: 14px;
            color: var(--light-text-color);
            margin-bottom: 15px;
        }

        .anime-watch .anime-actions {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .anime-watch .anime-actions span {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
            color: #555;
            transition: color var(--transition-speed) ease, transform var(--transition-speed) ease;
            padding: 5px 15px;
            border-radius: 25px;
            background-color: rgba(255, 255, 255, 0.3);
            font-size: 14px;
        }

        .anime-watch .anime-actions span:hover {
            color: #fff;
            background-color: var(--primary-color);
            transform: scale(1.1);
        }

        /* Видео-плеер */
        .video-player {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.8);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 2000;
            animation: fadeIn 0.5s ease-in;
        }

        .video-player .player-content {
            background-color: var(--modal-bg-color);
            padding: 25px;
            border-radius: 10px;
            width: 90%;
            max-width: 800px;
            position: relative;
            animation: slideIn 0.5s ease-out;
            box-shadow: 0 4px 8px var(--shadow-color);
            backdrop-filter: blur(5px);
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .video-player .player-content video {
            width: 100%;
            height: auto;
            border-radius: 8px;
            transition: transform var(--transition-speed) ease;
        }

        .video-player .player-content video:hover {
            transform: scale(1.02);
        }

        .video-player .player-content .close-btn {
            position: absolute;
            top: -15px;
            right: -15px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 50%;
            width: 35px;
            height: 35px;
            font-size: 18px;
            cursor: pointer;
            transition: background-color var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
        }

        .video-player .player-content .close-btn:hover {
            background-color: var(--secondary-color);
            transform: scale(1.1);
            box-shadow: 0 2px 4px rgba(0,0,0,0.3);
        }

        /* Поиск аниме */
        .anime-watch .search-bar {
            display: flex;
            gap: 10px;
            margin-bottom: 25px;
            animation: fadeIn 0.5s ease-in;
        }

        .anime-watch .search-bar input {
            flex: 1;
            border: 1px solid #ccc;
            border-radius: 8px;
            padding: 12px 15px;
            font-size: 16px;
            background-color: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(5px);
            transition: border-color var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
        }

        .anime-watch .search-bar input:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 5px rgba(255, 64, 129, 0.5);
            outline: none;
        }

        .anime-watch .search-bar button {
            padding: 12px 20px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            transition: background-color var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
            font-size: 16px;
        }

        .anime-watch .search-bar button:hover {
            background-color: var(--secondary-color);
            transform: scale(1.05);
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
        }

        /* Рейтинги */
        .rating {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
            transition: transform var(--transition-speed) ease;
        }

        .rating:hover {
            transform: scale(1.1);
        }

        .rating .star {
            font-size: 20px;
            color: #ccc;
            transition: color var(--transition-speed) ease;
        }

        .rating .star.hover,
        .rating .star.selected {
            color: var(--primary-color);
        }

        /* Избранные аниме */
        .favorite {
            color: var(--primary-color);
            transition: color var(--transition-speed) ease;
        }

        .favorite:hover {
            color: var(--secondary-color);
        }

        /* Сообщества */
        .community-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 25px;
        }

        .community-header h2 {
            font-family: 'Noto Sans JP', sans-serif;
            font-size: 28px;
            color: var(--primary-color);
            text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
        }

        .community-header button {
            padding: 12px 25px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            transition: background-color var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
            font-size: 16px;
            font-family: 'Roboto', sans-serif;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }

        .community-header button:hover {
            background-color: var(--secondary-color);
            transform: scale(1.05);
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
        }

        .groups-list {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 25px;
        }

        .group-item {
            background-color: var(--card-bg-color);
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 4px 8px var(--shadow-color);
            transition: transform var(--transition-speed), box-shadow var(--transition-speed), background-color var(--transition-speed);
            cursor: pointer;
            position: relative;
        }

        .group-item:hover {
            transform: scale(1.02);
            box-shadow: 0 8px 16px rgba(0,0,0,0.2);
            background-color: #ffffff;
        }

        .group-item h3 {
            margin-top: 0;
            font-size: 22px;
            color: var(--text-color);
            font-family: 'Noto Sans JP', sans-serif;
            margin-bottom: 10px;
        }

        .group-item p {
            color: var(--light-text-color);
            font-size: 16px;
            margin-bottom: 15px;
        }

        .group-item .group-actions {
            position: absolute;
            top: 15px;
            right: 15px;
        }

        .group-item .group-actions span {
            font-size: 20px;
            color: #555;
            transition: color var(--transition-speed) ease, transform var(--transition-speed) ease;
        }

        .group-item .group-actions span:hover {
            color: var(--primary-color);
            transform: scale(1.2);
        }

        /* Модальные окна */
        .modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.8);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 3000;
            animation: fadeIn 0.5s ease-in;
        }

        .modal-content {
            background-color: var(--modal-bg-color);
            padding: 30px 40px;
            border-radius: 12px;
            width: 90%;
            max-width: 600px;
            position: relative;
            animation: slideIn 0.5s ease-out;
            box-shadow: 0 4px 8px var(--shadow-color);
            backdrop-filter: blur(5px);
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .modal-content h2 {
            margin-top: 0;
            color: var(--primary-color);
            font-family: 'Noto Sans JP', sans-serif;
            font-size: 26px;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
            margin-bottom: 20px;
        }

        .modal-content input,
        .modal-content textarea {
            width: 100%;
            padding: 12px 15px;
            border-radius: 8px;
            border: 1px solid #ccc;
            margin-bottom: 20px;
            font-size: 16px;
            transition: border-color var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
            background-color: rgba(255, 255, 255, 0.9);
            backdrop-filter: blur(5px);
            font-family: 'Roboto', sans-serif;
        }

        .modal-content input:focus,
        .modal-content textarea:focus {
            border-color: var(--primary-color);
            box-shadow: 0 0 5px rgba(255, 64, 129, 0.5);
            outline: none;
        }

        .modal-content button {
            padding: 12px 25px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            transition: background-color var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
            font-size: 16px;
            font-family: 'Roboto', sans-serif;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }

        .modal-content button:hover {
            background-color: var(--secondary-color);
            transform: scale(1.05);
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
        }

        .modal-content .cancel-btn {
            background-color: #ccc;
            color: #333;
            margin-left: 10px;
        }

        /* Секция группы */
        .group-section {
            display: none;
        }

        .group-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 25px;
        }

        .group-header h2 {
            font-family: 'Noto Sans JP', sans-serif;
            font-size: 28px;
            color: var(--primary-color);
            text-shadow: 1px 1px 2px rgba(0,0,0,0.2);
        }

        .group-header button {
            padding: 12px 25px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            transition: background-color var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
            font-size: 16px;
            font-family: 'Roboto', sans-serif;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }

        .group-header button:hover {
            background-color: var(--secondary-color);
            transform: scale(1.05);
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
        }

        #groupPosts .post {
            background-color: var(--card-bg-color);
            padding: 20px;
            margin-bottom: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 8px var(--shadow-color);
            animation: fadeInUp 0.5s ease-out;
            display: flex;
            flex-direction: column;
            transition: transform var(--transition-speed), box-shadow var(--transition-speed), background-color var(--transition-speed);
        }

        #groupPosts .post:hover {
            transform: translateY(-5px) scale(1.02);
            box-shadow: 0 8px 16px rgba(0,0,0,0.2);
            background-color: #ffffff;
        }

        #groupPosts .post .post-header {
            display: flex;
            align-items: center;
            gap: 15px;
        }

        #groupPosts .post .post-header img {
            width: 50px;
            height: 50px;
            border-radius: 50%;
            transition: transform var(--transition-speed), filter var(--transition-speed);
            filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
        }

        #groupPosts .post .post-header img:hover {
            transform: scale(1.1) rotate(5deg);
            filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
        }

        #groupPosts .post .post-header strong {
            font-size: 18px;
            color: var(--text-color);
            font-weight: 500;
        }

        #groupPosts .post .post-content {
            margin-top: 15px;
            animation: slideIn 0.3s ease-out;
            position: relative;
            font-size: 16px;
            color: var(--text-color);
        }

        #groupPosts .post .post-content img {
            width: 100%;
            max-height: 350px;
            object-fit: cover;
            border-radius: 8px;
            margin-top: 15px;
            transition: transform var(--transition-speed), filter var(--transition-speed);
            filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
        }

        #groupPosts .post .post-content img:hover {
            transform: scale(1.05);
            filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
        }

        #groupPosts .post .post-actions {
            display: flex;
            align-items: center;
            gap: 20px;
            margin-top: 15px;
        }

        #groupPosts .post .post-actions span {
            display: flex;
            align-items: center;
            gap: 5px;
            cursor: pointer;
            color: #555;
            transition: color var(--transition-speed) ease, transform var(--transition-speed) ease, background-color var(--transition-speed) ease;
            padding: 5px 15px;
            border-radius: 25px;
            background-color: rgba(255, 255, 255, 0.3);
        }

        #groupPosts .post .post-actions span:hover {
            color: #fff;
            background-color: var(--primary-color);
            transform: scale(1.1);
        }

        /* События */
        .events-list {
            display: flex;
            flex-direction: column;
            gap: 20px;
            margin-bottom: 30px;
        }

        .event-item {
            background-color: var(--card-bg-color);
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 8px var(--shadow-color);
            transition: transform var(--transition-speed), box-shadow var(--transition-speed), background-color var(--transition-speed);
        }

        .event-item:hover {
            transform: scale(1.01);
            box-shadow: 0 6px 12px rgba(0,0,0,0.2);
            background-color: #ffffff;
        }

        .event-item h3 {
            margin-top: 0;
            font-size: 20px;
            color: var(--text-color);
            font-family: 'Noto Sans JP', sans-serif;
        }

        .event-item p {
            color: var(--light-text-color);
            font-size: 16px;
            margin-bottom: 10px;
        }

        .event-map iframe {
            width: 100%;
            height: 400px;
            border: none;
            border-radius: 10px;
            box-shadow: 0 4px 8px var(--shadow-color);
        }

        /* Адаптивные стили */
        @media (max-width: 1200px) {
            .navbar {
                padding: 15px 20px;
            }

            .navbar .logo {
                font-size: 24px;
            }

            .navbar .nav-icons {
                gap: 15px;
                font-size: 18px;
            }

            .section {
                padding: 25px 30px;
                margin: 25px auto;
            }

            .community-header h2,
            .group-header h2,
            .feed .post .post-header strong {
                font-size: 24px;
            }

            .community-header button,
            .group-header button,
            .create-post button,
            .anime-watch .search-bar button,
            .comments-section button,
            .modal-content button {
                padding: 10px 20px;
                font-size: 14px;
            }

            .groups-list {
                grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            }

            .anime-watch .anime-list {
                grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
            }

            #eventMap iframe {
                height: 300px;
            }
        }

        @media (max-width: 768px) {
            .navbar {
                flex-direction: column;
                align-items: flex-start;
                gap: 10px;
            }

            .navbar .logo {
                font-size: 20px;
            }

            .navbar .nav-icons {
                gap: 10px;
                font-size: 16px;
            }

            .section {
                padding: 20px 15px;
                margin: 20px auto;
            }

            .community-header h2,
            .group-header h2 {
                font-size: 22px;
            }

            .groups-list,
            .anime-watch .anime-list {
                grid-template-columns: 1fr;
            }

            #eventMap iframe {
                height: 250px;
            }
        }

        @media (max-width: 480px) {
            .navbar {
                padding: 10px 15px;
            }

            .navbar .logo {
                font-size: 18px;
            }

            .navbar .nav-icons {
                gap: 8px;
                font-size: 14px;
            }

            .section {
                padding: 15px 10px;
                margin: 15px auto;
            }

            .community-header h2,
            .group-header h2 {
                font-size: 20px;
            }

            .modal-content {
                padding: 20px 25px;
            }

            .modal-content h2 {
                font-size: 24px;
            }

            .modal-content button {
                padding: 10px 20px;
                font-size: 14px;
            }

            .anime-watch .anime-list {
                grid-template-columns: 1fr;
            }

            #groupPosts .post .post-content img,
            .feed .post .post-content img {
                max-height: 250px;
            }

            #eventMap iframe {
                height: 200px;
            }
        }

        /* Анимации */
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes fadeInUp {
            from { opacity: 0; transform: translateY(20px); }
            to { opacity: 1; transform: translateY(0); }
        }

        @keyframes slideIn {
            from { transform: translateY(-50px); opacity: 0; }
            to { transform: translateY(0); opacity: 1; }
        }

        @keyframes popIn {
            from { transform: scale(0.8); opacity: 0; }
            to { transform: scale(1); opacity: 1; }
        }

        /* Кастомные скроллы */
        ::-webkit-scrollbar {
            width: 8px;
        }

        ::-webkit-scrollbar-track {
            background: #f1f1f1; 
        }

        ::-webkit-scrollbar-thumb {
            background: var(--primary-color); 
            border-radius: 4px;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: var(--secondary-color); 
        }

    </style>
</head>
<body>

    <!-- Навигационная панель -->
    <div class="navbar">
        <div class="logo" onclick="showSection('feed')">Хика Морi</div>
        <div class="nav-icons">
            <span onclick="showSection('feed')">🏠 Лента</span>
            <span onclick="showSection('createPost')">➕ Создать</span>
            <span onclick="showSection('animeWatch')">🎥 Просмотр</span>
            <span onclick="showSection('community')">👥 Сообщества</span>
            <span onclick="showSection('profile')">👤 Профиль</span>
        </div>
    </div>

    <!-- Главная лента -->
    <div id="feed" class="section active feed">
        <!-- Пример поста -->
        <div class="post">
            <div class="post-header">
                <img src="https://i.imgur.com/8Km9tLL.jpg" alt="Аватар">
                <strong>Anko_Lover</strong>
            </div>
            <div class="post-content">
                <img src="https://cdn.myanimelist.net/images/anime/10/47347.jpg" alt="Attack on Titan">
                Обожаю новый сезон "Attack on Titan"! Как вам развитие сюжета?
            </div>
            <div class="post-actions">
                <span onclick="likePost(this)">👍 <span class="like-count">0</span></span>
                <span onclick="toggleComments(this)">💬 Комментарии</span>
            </div>
            <div class="comments-section" style="display: none; margin-top: 15px;">
                <input type="text" placeholder="Написать комментарий..." class="comment-input">
                <button onclick="addComment(this)">Отправить</button>
                <div class="comments-list"></div>
            </div>
        </div>
        <!-- Дополнительные посты -->
        <div class="post">
            <div class="post-header">
                <img src="https://i.imgur.com/8Km9tLL.jpg" alt="Аватар">
                <strong>Otaku_Girl</strong>
            </div>
            <div class="post-content">
                <img src="https://cdn.myanimelist.net/images/anime/1322/128099.jpg" alt="Naruto Shippuden">
                Новые серии "Naruto Shippuden" просто супер! Нравится ли вам развитие сюжета?
            </div>
            <div class="post-actions">
                <span onclick="likePost(this)">👍 <span class="like-count">0</span></span>
                <span onclick="toggleComments(this)">💬 Комментарии</span>
            </div>
            <div class="comments-section" style="display: none; margin-top: 15px;">
                <input type="text" placeholder="Написать комментарий..." class="comment-input">
                <button onclick="addComment(this)">Отправить</button>
                <div class="comments-list"></div>
            </div>
        </div>
        <!-- Добавьте больше постов по необходимости -->
    </div>

    <!-- Форма создания поста -->
    <div id="createPost" class="section create-post">
        <h2>Создать новый пост</h2>
        <textarea id="postContent" placeholder="Что у вас на уме?"></textarea>
        <input type="file" id="postImage" accept="image/*">
        <button onclick="createPost()">Опубликовать</button>
    </div>

    <!-- Раздел просмотра аниме -->
    <div id="animeWatch" class="section anime-watch">
        <h2>Просмотр Аниме</h2>
        <!-- Поиск аниме -->
        <div class="search-bar">
            <input type="text" id="searchAnime" placeholder="Поиск аниме...">
            <button onclick="searchAnime()">🔍</button>
        </div>
        <!-- Список аниме -->
        <div class="anime-list" id="animeList">
            <!-- Пример аниме -->
            <div class="anime-item">
                <img src="https://cdn.myanimelist.net/images/anime/1552/108717.jpg" alt="Attack on Titan">
                <div class="anime-info">
                    <h3>Attack on Titan</h3>
                    <p>Эпическая история о борьбе человечества за выживание против титанических существ.</p>
                    <div class="anime-actions">
                        <span onclick="toggleFavorite(this)">⭐ <span class="favorite-count">0</span></span>
                        <span onclick="showEpisodes(this)">📺 Серии</span>
                        <div class="rating" onclick="rateAnime(event, this)">
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                        </div>
                    </div>
                </div>
            </div>
            <!-- Другие аниме -->
            <div class="anime-item">
                <img src="https://cdn.myanimelist.net/images/anime/13/17405.jpg" alt="Naruto Shippuden">
                <div class="anime-info">
                    <h3>Naruto Shippuden</h3>
                    <p>Продолжение приключений Наруто Узумаки и его друзей в мире ниндзя.</p>
                    <div class="anime-actions">
                        <span onclick="toggleFavorite(this)">⭐ <span class="favorite-count">0</span></span>
                        <span onclick="showEpisodes(this)">📺 Серии</span>
                        <div class="rating" onclick="rateAnime(event, this)">
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                        </div>
                    </div>
                </div>
            </div>
            <div class="anime-item">
                <img src="https://cdn.myanimelist.net/images/anime/5/73245.jpg" alt="One Piece">
                <div class="anime-info">
                    <h3>One Piece</h3>
                    <p>Эпическое путешествие Лаффи и его команды в поисках легендарного сокровища - One Piece.</p>
                    <div class="anime-actions">
                        <span onclick="toggleFavorite(this)">⭐ <span class="favorite-count">0</span></span>
                        <span onclick="showEpisodes(this)">📺 Серии</span>
                        <div class="rating" onclick="rateAnime(event, this)">
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                            <span class="star">&#9734;</span>
                        </div>
                    </div>
                </div>
            </div>
            <!-- Добавьте больше аниме по необходимости -->
        </div>

        <!-- Видео-плеер -->
        <div class="video-player" id="videoPlayer">
            <div class="player-content">
                <button class="close-btn" onclick="closeVideoPlayer()">✖</button>
                <video controls id="animeVideo">
                    <source src="" type="video/mp4">
                    Ваш браузер не поддерживает видео.
                </video>
            </div>
        </div>
    </div>

    <!-- Раздел Сообщества -->
    <div id="community" class="section community">
        <div class="community-header">
            <h2>Сообщества</h2>
            <button onclick="openModal('createGroupModal')">Создать сообщество</button>
        </div>
        <div class="groups-list" id="groupsList">
            <!-- Пример сообщества -->
            <div class="group-item" onclick="openGroup('Атака титанов')">
                <h3>Атака титанов</h3>
                <p>Обсуждаем всё, что связано с "Атакой Титанов"!</p>
                <div class="group-actions">
                    <span title="Подробнее">🔍</span>
                </div>
            </div>
            <div class="group-item" onclick="openGroup('Наруто Шиппуден')">
                <h3>Наруто Шиппуден</h3>
                <p>Приключения Наруто и его друзей в мире ниндзя.</p>
                <div class="group-actions">
                    <span title="Подробнее">🔍</span>
                </div>
            </div>
            <!-- Добавьте больше сообществ по необходимости -->
        </div>
    </div>

    <!-- Форма создания сообщества (Модальное окно) -->
    <div class="modal" id="createGroupModal">
        <div class="modal-content">
            <h2>Создать новое сообщество</h2>
            <input type="text" id="groupName" placeholder="Название сообщества">
            <textarea id="groupDescription" placeholder="Описание сообщества"></textarea>
            <div style="display: flex; justify-content: flex-end; width: 100%;">
                <button onclick="createGroup()">Создать</button>
                <button onclick="closeModal('createGroupModal')" class="cancel-btn">Отмена</button>
            </div>
        </div>
    </div>

    <!-- Секция группы -->
    <div id="groupSection" class="section group-section">
        <div class="group-header">
            <h2 id="currentGroupName">Название Сообщества</h2>
            <button id="createEventBtn" onclick="openModal('createEventModal')">Создать событие</button>
        </div>
        <div id="groupPosts" class="feed">
            <!-- Посты внутри группы будут добавляться здесь -->
            <!-- Пример поста внутри группы -->
            <div class="post">
                <div class="post-header">
                    <img src="https://i.imgur.com/8Km9tLL.jpg" alt="Аватар">
                    <strong>Админ группы</strong>
                </div>
                <div class="post-content">
                    Добро пожаловать в сообщество "Название Сообщества"! Давайте обсудим всё, что связано с этим аниме.
                </div>
                <div class="post-actions">
                    <span onclick="likePost(this)">👍 <span class="like-count">0</span></span>
                    <span onclick="toggleComments(this)">💬 Комментарии</span>
                </div>
                <div class="comments-section" style="display: none; margin-top: 15px;">
                    <input type="text" placeholder="Написать комментарий..." class="comment-input">
                    <button onclick="addComment(this)">Отправить</button>
                    <div class="comments-list"></div>
                </div>
            </div>
            <!-- Добавьте больше постов по необходимости -->
        </div>
        <h3>События</h3>
        <div class="events-list" id="groupEvents">
            <!-- События будут добавляться здесь -->
        </div>
        <!-- Карта события -->
        <div id="eventMap" class="event-map">
            <!-- Встроенная карта будет отображаться здесь -->
        </div>
    </div>

    <!-- Форма создания события (Модальное окно) -->
    <div class="modal" id="createEventModal">
        <div class="modal-content">
            <h2>Создать событие</h2>
            <input type="text" id="eventName" placeholder="Название события">
            <textarea id="eventDescription" placeholder="Описание события"></textarea>
            <input type="text" id="eventLocation" placeholder="Местоположение (адрес)">
            <div style="display: flex; justify-content: flex-end; width: 100%;">
                <button onclick="createEvent()">Создать</button>
                <button onclick="closeModal('createEventModal')" class="cancel-btn">Отмена</button>
            </div>
        </div>
    </div>

    <!-- Профиль пользователя -->
    <div id="profile" class="section profile">
        <h2>Профиль</h2>
        <div class="profile-header">
            <img src="https://i.imgur.com/8Km9tLL.jpg" alt="Аватар">
            <div>
                <h2>Имя Пользователя</h2>
                <p>@nik_name</p>
            </div>
        </div>
        <div class="profile-content">
            <h3>О себе</h3>
            <p>Любитель аниме, манги и всего японского! 🎌</p>
            <h3>Мои посты</h3>
            <!-- Пользовательские посты будут отображаться здесь -->
            <!-- Пример поста пользователя -->
            <div class="post">
                <div class="post-header">
                    <img src="https://i.imgur.com/8Km9tLL.jpg" alt="Аватар">
                    <strong>Вы</strong>
                </div>
                <div class="post-content">
                    <p>Сегодня посмотрел новый эпизод "One Piece" — невероятно!</p>
                </div>
                <div class="post-actions">
                    <span onclick="likePost(this)">👍 <span class="like-count">0</span></span>
                    <span onclick="toggleComments(this)">💬 Комментарии</span>
                </div>
                <div class="comments-section" style="display: none; margin-top: 15px;">
                    <input type="text" placeholder="Написать комментарий..." class="comment-input">
                    <button onclick="addComment(this)">Отправить</button>
                    <div class="comments-list"></div>
                </div>
            </div>
            <!-- Добавьте больше постов по необходимости -->
        </div>
    </div>

    <!-- Видео-плеер -->
    <div class="video-player" id="videoPlayer">
        <div class="player-content">
            <button class="close-btn" onclick="closeVideoPlayer()">✖</button>
            <video controls id="animeVideo">
                <source src="" type="video/mp4">
                Ваш браузер не поддерживает видео.
            </video>
        </div>
    </div>

    <!-- JavaScript для взаимодействия -->
    <script>
        // Функция для переключения секций
        function showSection(sectionId) {
            const sections = document.querySelectorAll('.section');
            sections.forEach(section => {
                if (section.id === sectionId || (sectionId === 'groupSection' && section.id === 'community')) {
                    section.classList.add('active');
                } else {
                    section.classList.remove('active');
                }
            });

            // Скрываем модальные окна при переключении секций
            const modals = document.querySelectorAll('.modal');
            modals.forEach(modal => {
                modal.style.display = 'none';
            });

            // Если не группа, скрываем секцию группы
            if (sectionId !== 'groupSection') {
                document.getElementById('groupSection').style.display = 'none';
            }
        }

        // Функция для открытия модального окна
        function openModal(modalId) {
            document.getElementById(modalId).style.display = 'flex';
        }

        // Функция для закрытия модального окна
        function closeModal(modalId) {
            document.getElementById(modalId).style.display = 'none';
        }

        // Функция для создания нового поста
        function createPost() {
            const content = document.getElementById('postContent').value.trim();
            const imageInput = document.getElementById('postImage');
            const imageFile = imageInput.files[0];

            if (content === "" && !imageFile) {
                alert("Пожалуйста, введите текст поста или выберите изображение.");
                return;
            }

            // Создание элементов поста
            const post = document.createElement('div');
            post.className = 'post';
            post.style.opacity = '0';

            const postHeader = document.createElement('div');
            postHeader.className = 'post-header';
            postHeader.innerHTML = `
                <img src="https://i.imgur.com/8Km9tLL.jpg" alt="Аватар">
                <strong>Вы</strong>
            `;

            const postContent = document.createElement('div');
            postContent.className = 'post-content';
            if (content !== "") {
                const text = document.createElement('p');
                text.textContent = content;
                postContent.appendChild(text);
            }

            if (imageFile) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    const img = document.createElement('img');
                    img.src = e.target.result;
                    img.alt = "Пользовательское изображение";
                    postContent.appendChild(img);
                }
                reader.readAsDataURL(imageFile);
            }

            const postActions = document.createElement('div');
            postActions.className = 'post-actions';
            postActions.innerHTML = `
                <span onclick="likePost(this)">👍 <span class="like-count">0</span></span>
                <span onclick="toggleComments(this)">💬 Комментарии</span>
            `;

            const commentsSection = document.createElement('div');
            commentsSection.className = 'comments-section';
            commentsSection.style.display = 'none';
            commentsSection.innerHTML = `
                <input type="text" placeholder="Написать комментарий..." class="comment-input">
                <button onclick="addComment(this)">Отправить</button>
                <div class="comments-list"></div>
            `;

            post.appendChild(postHeader);
            post.appendChild(postContent);
            post.appendChild(postActions);
            post.appendChild(commentsSection);

            // Добавление поста в начало ленты
            const feed = document.getElementById('feed');
            feed.insertBefore(post, feed.firstChild);

            // Анимация появления поста
            setTimeout(() => {
                post.style.opacity = '1';
            }, 100);

            // Очистка формы и переключение на ленту
            document.getElementById('postContent').value = "";
            imageInput.value = "";
            showSection('feed');
        }

        // Функция для лайка поста
        function likePost(element) {
            const likeCountSpan = element.querySelector('.like-count');
            let count = parseInt(likeCountSpan.textContent);
            count++;
            likeCountSpan.textContent = count;
            // Анимация увеличения сердца
            element.style.transform = 'scale(1.2)';
            setTimeout(() => {
                element.style.transform = 'scale(1)';
            }, 200);
        }

        // Функция для переключения секции комментариев
        function toggleComments(element) {
            const commentsSection = element.parentElement.nextElementSibling;
            if (commentsSection.style.display === 'none') {
                commentsSection.style.display = 'block';
                commentsSection.style.animation = 'fadeIn 0.5s ease-in';
            } else {
                commentsSection.style.display = 'none';
            }
        }

        // Функция для добавления комментария
        function addComment(button) {
            const commentsSection = button.parentElement;
            const commentInput = commentsSection.querySelector('.comment-input');
            const commentText = commentInput.value.trim();
            if (commentText === "") {
                alert("Пожалуйста, введите комментарий.");
                return;
            }

            const commentsList = commentsSection.querySelector('.comments-list');
            const comment = document.createElement('div');
            comment.style.padding = '10px 0';
            comment.style.borderBottom = '1px solid #eee';
            comment.textContent = commentText;
            comment.style.opacity = '0';
            comment.style.animation = 'fadeIn 0.3s forwards';
            commentsList.appendChild(comment);

            commentInput.value = "";
        }

        // Функция для поиска аниме
        function searchAnime() {
            const query = document.getElementById('searchAnime').value.toLowerCase();
            const animeItems = document.querySelectorAll('.anime-item');

            animeItems.forEach(item => {
                const title = item.querySelector('.anime-info h3').textContent.toLowerCase();
                if (title.includes(query)) {
                    item.style.display = 'flex';
                } else {
                    item.style.display = 'none';
                }
            });
        }

        // Функция для отображения списка серий
        function showEpisodes(element) {
            const animeItem = element.closest('.anime-item');
            const animeTitle = animeItem.querySelector('.anime-info h3').textContent;
            let episodes = [];

            // Пример данных серий, можно заменить на реальные данные
            if (animeTitle === "Attack on Titan") {
                episodes = [
                    {number: 1, title: "To You, in 2000 Years: The Fall of Shiganshina, Part 1", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    {number: 2, title: "That Day: The Fall of Shiganshina, Part 2", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    {number: 3, title: "A Dim Light Amid Despair: Humanity’s Comeback, Part 1", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    // Добавьте больше серий по необходимости
                ];
            } else if (animeTitle === "Naruto Shippuden") {
                episodes = [
                    {number: 1, title: "Homecoming", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    {number: 2, title: "The Akatsuki Makes Its Move", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    {number: 3, title: "The Results of Training", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    // Добавьте больше серий по необходимости
                ];
            } else if (animeTitle === "One Piece") {
                episodes = [
                    {number: 1, title: "I'm Luffy! The Man Who's Gonna Be King of the Pirates!", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    {number: 2, title: "Enter the Great Swordsman! Pirate Hunter Roronoa Zoro!", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    {number: 3, title: "Morgan vs. Luffy! Who’s the Mysterious Pretty Girl?", video: "https://www.w3schools.com/html/mov_bbb.mp4"},
                    // Добавьте больше серий по необходимости
                ];
            }

            // Создание всплывающего окна со списком серий
            const episodesModal = document.createElement('div');
            episodesModal.style.position = 'fixed';
            episodesModal.style.top = '0';
            episodesModal.style.left = '0';
            episodesModal.style.width = '100%';
            episodesModal.style.height = '100%';
            episodesModal.style.backgroundColor = 'rgba(0,0,0,0.8)';
            episodesModal.style.display = 'flex';
            episodesModal.style.justifyContent = 'center';
            episodesModal.style.alignItems = 'center';
            episodesModal.style.zIndex = '3000';
            episodesModal.style.animation = 'fadeIn 0.5s ease-in';

            const modalContent = document.createElement('div');
            modalContent.style.backgroundColor = 'var(--modal-bg-color)';
            modalContent.style.padding = '25px 30px';
            modalContent.style.borderRadius = '12px';
            modalContent.style.width = '90%';
            modalContent.style.maxWidth = '700px';
            modalContent.style.maxHeight = '80%';
            modalContent.style.overflowY = 'auto';
            modalContent.style.position = 'relative';
            modalContent.style.animation = 'slideIn 0.5s ease-out';
            modalContent.style.boxShadow = '0 4px 8px var(--shadow-color)';
            modalContent.style.backdropFilter = 'blur(5px)';

            const closeBtn = document.createElement('button');
            closeBtn.textContent = '✖';
            closeBtn.style.position = 'absolute';
            closeBtn.style.top = '15px';
            closeBtn.style.right = '15px';
            closeBtn.style.backgroundColor = 'var(--primary-color)';
            closeBtn.style.color = '#fff';
            closeBtn.style.border = 'none';
            closeBtn.style.borderRadius = '50%';
            closeBtn.style.width = '35px';
            closeBtn.style.height = '35px';
            closeBtn.style.fontSize = '18px';
            closeBtn.style.cursor = 'pointer';
            closeBtn.style.transition = 'background-color var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease';
            closeBtn.onclick = () => {
                document.body.removeChild(episodesModal);
            };

            closeBtn.onmouseover = () => {
                closeBtn.style.backgroundColor = 'var(--secondary-color)';
                closeBtn.style.transform = 'scale(1.1)';
                closeBtn.style.boxShadow = '0 2px 4px rgba(0,0,0,0.3)';
            }

            closeBtn.onmouseout = () => {
                closeBtn.style.backgroundColor = 'var(--primary-color)';
                closeBtn.style.transform = 'scale(1)';
                closeBtn.style.boxShadow = 'none';
            }

            modalContent.appendChild(closeBtn);

            const episodesList = document.createElement('ul');
            episodesList.style.listStyle = 'none';
            episodesList.style.padding = '0';
            episodesList.style.width = '100%';

            episodes.forEach(ep => {
                const li = document.createElement('li');
                li.style.marginBottom = '15px';

                const btn = document.createElement('button');
                btn.textContent = `Эпизод ${ep.number}: ${ep.title}`;
                btn.style.width = '100%';
                btn.style.padding = '15px';
                btn.style.border = 'none';
                btn.style.borderRadius = '8px';
                btn.style.backgroundColor = 'var(--primary-color)';
                btn.style.color = '#fff';
                btn.style.cursor = 'pointer';
                btn.style.transition = 'background-color var(--transition-speed) ease, transform var(--transition-speed) ease';
                btn.style.fontSize = '16px';
                btn.style.fontFamily = 'Roboto, sans-serif';

                btn.onclick = () => {
                    openVideoPlayer(ep.video);
                    document.body.removeChild(episodesModal);
                };

                btn.onmouseover = () => {
                    btn.style.backgroundColor = 'var(--secondary-color)';
                    btn.style.transform = 'scale(1.05)';
                }

                btn.onmouseout = () => {
                    btn.style.backgroundColor = 'var(--primary-color)';
                    btn.style.transform = 'scale(1)';
                }

                li.appendChild(btn);
                episodesList.appendChild(li);
            });

            modalContent.appendChild(episodesList);
            episodesModal.appendChild(modalContent);
            document.body.appendChild(episodesModal);
        }

        // Функция для открытия видео-плеера
        function openVideoPlayer(videoUrl) {
            const videoPlayer = document.getElementById('videoPlayer');
            const videoElement = document.getElementById('animeVideo');
            videoElement.src = videoUrl;
            videoPlayer.style.display = 'flex';
            videoElement.play();
            videoPlayer.style.animation = 'fadeIn 0.5s ease-in';
        }

        // Функция для закрытия видео-плеера
        function closeVideoPlayer() {
            const videoPlayer = document.getElementById('videoPlayer');
            const videoElement = document.getElementById('animeVideo');
            videoElement.pause();
            videoElement.src = '';
            videoPlayer.style.display = 'none';
        }

        // Функция для добавления аниме в избранное
        function toggleFavorite(element) {
            const favoriteCountSpan = element.querySelector('.favorite-count');
            let count = parseInt(favoriteCountSpan.textContent);
            const animeItem = element.closest('.anime-item');

            if (!element.classList.contains('favorite')) {
                count++;
                favoriteCountSpan.textContent = count;
                element.classList.add('favorite');
                // Анимация "звезды"
                element.style.transform = 'scale(1.2)';
                setTimeout(() => {
                    element.style.transform = 'scale(1)';
                }, 200);
            } else {
                if (count > 0) {
                    count--;
                    favoriteCountSpan.textContent = count;
                }
                element.classList.remove('favorite');
                // Анимация "звезды"
                element.style.transform = 'scale(0.8)';
                setTimeout(() => {
                    element.style.transform = 'scale(1)';
                }, 200);
            }
        }

        // Функция для рейтинга аниме
        function rateAnime(event, element) {
            const stars = element.querySelectorAll('.star');
            const rating = Array.from(stars).indexOf(event.target) + 1;

            stars.forEach((star, index) => {
                if (index < rating) {
                    star.classList.add('selected');
                } else {
                    star.classList.remove('selected');
                }
            });

            // Можно добавить сохранение рейтинга в базе данных или локальном хранилище
        }

        // Закрытие видео-плеера и модальных окон при нажатии вне контента
        window.onclick = function(event) {
            const videoPlayer = document.getElementById('videoPlayer');
            if (event.target == videoPlayer) {
                closeVideoPlayer();
            }

            const modals = document.querySelectorAll('.modal');
            modals.forEach(modal => {
                if (event.target == modal) {
                    modal.style.display = 'none';
                }
            });
        }

        // Функция для создания сообщества
        function createGroup() {
            const groupName = document.getElementById('groupName').value.trim();
            const groupDescription = document.getElementById('groupDescription').value.trim();

            if (groupName === "" || groupDescription === "") {
                alert("Пожалуйста, заполните все поля.");
                return;
            }

            // Проверка на существование группы с таким же названием
            const existingGroups = document.querySelectorAll('.group-item h3');
            for (let group of existingGroups) {
                if (group.textContent.toLowerCase() === groupName.toLowerCase()) {
                    alert("Сообщество с таким названием уже существует.");
                    return;
                }
            }

            // Создание элементов сообщества
            const groupItem = document.createElement('div');
            groupItem.className = 'group-item';
            groupItem.onclick = () => openGroup(groupName);
            groupItem.innerHTML = `
                <h3>${groupName}</h3>
                <p>${groupDescription}</p>
                <div class="group-actions">
                    <span title="Подробнее">🔍</span>
                </div>
            `;

            document.getElementById('groupsList').appendChild(groupItem);

            // Закрытие модального окна и очистка полей
            closeModal('createGroupModal');
            document.getElementById('groupName').value = "";
            document.getElementById('groupDescription').value = "";
        }

        // Функция для открытия группы
        function openGroup(groupName) {
            // Показываем секцию группы и скрываем другие секции
            const sections = document.querySelectorAll('.section');
            sections.forEach(section => {
                if (section.id === 'groupSection') {
                    section.classList.add('active');
                } else {
                    section.classList.remove('active');
                }
            });

            // Закрываем все модальные окна
            const modals = document.querySelectorAll('.modal');
            modals.forEach(modal => {
                modal.style.display = 'none';
            });

            // Заполняем название текущей группы
            document.getElementById('currentGroupName').textContent = groupName;

            // Очищаем предыдущие посты и события
            document.getElementById('groupPosts').innerHTML = "";
            document.getElementById('groupEvents').innerHTML = "";
            document.getElementById('eventMap').innerHTML = "";

            // Отображаем кнопку создания события, если пользователь является администратором
            // Для простоты считаем, что текущий пользователь является администратором
            document.getElementById('createEventBtn').style.display = 'block';

            // Пример постов внутри группы (можно заменить на реальные данные)
            const examplePost = document.createElement('div');
            examplePost.className = 'post';
            examplePost.innerHTML = `
                <div class="post-header">
                    <img src="https://i.imgur.com/8Km9tLL.jpg" alt="Аватар">
                    <strong>Админ группы</strong>
                </div>
                <div class="post-content">
                    Добро пожаловать в сообщество "${groupName}"! Давайте обсудим всё, что связано с этим аниме.
                </div>
                <div class="post-actions">
                    <span onclick="likePost(this)">👍 <span class="like-count">0</span></span>
                    <span onclick="toggleComments(this)">💬 Комментарии</span>
                </div>
                <div class="comments-section" style="display: none; margin-top: 15px;">
                    <input type="text" placeholder="Написать комментарий..." class="comment-input">
                    <button onclick="addComment(this)">Отправить</button>
                    <div class="comments-list"></div>
                </div>
            `;
            document.getElementById('groupPosts').appendChild(examplePost);
        }

        // Функция для создания события
        function createEvent() {
            const eventName = document.getElementById('eventName').value.trim();
            const eventDescription = document.getElementById('eventDescription').value.trim();
            const eventLocation = document.getElementById('eventLocation').value.trim();

            if (eventName === "" || eventDescription === "" || eventLocation === "") {
                alert("Пожалуйста, заполните все поля.");
                return;
            }

            // Создание элементов события
            const eventItem = document.createElement('div');
            eventItem.className = 'event-item';
            eventItem.innerHTML = `
                <h3>${eventName}</h3>
                <p>${eventDescription}</p>
                <p><strong>Место:</strong> ${eventLocation}</p>
            `;

            // Добавление события в список событий
            document.getElementById('groupEvents').appendChild(eventItem);

            // Отображение карты
            const map = document.createElement('iframe');
            map.src = `https://www.google.com/maps/embed/v1/place?key=YOUR_GOOGLE_MAPS_API_KEY&q=${encodeURIComponent(eventLocation)}`;
            map.width = "100%";
            map.height = "400";
            map.style.border = "0";
            map.allowFullscreen = "";
            map.loading = "lazy";
            map.referrerPolicy = "no-referrer-when-downgrade";
            map.style.borderRadius = '10px';
            map.style.marginTop = '15px';
            document.getElementById('eventMap').appendChild(map);

            // Закрытие модального окна и очистка полей
            closeModal('createEventModal');
            document.getElementById('eventName').value = "";
            document.getElementById('eventDescription').value = "";
            document.getElementById('eventLocation').value = "";
        }

        // Замена YOUR_GOOGLE_MAPS_API_KEY на ваш реальный API ключ
        // Вы можете получить его, зарегистрировавшись в Google Cloud Platform и включив Google Maps Embed API

    </script>

</body>
</html>
вот мой бэк  Конечно! Давайте перепишем ваш бэкенд, используя SQLite вместо MongoDB. Мы будем использовать Sequelize как ORM для упрощения взаимодействия с SQLite в Node.js. SQLite — лёгкая реляционная база данных, идеально подходящая для небольших и средних проектов.

План Действий
Настройка Проекта
Установка Необходимых Пакетов
Организация Структуры Каталогов
Настройка Подключения к SQLite с использованием Sequelize
Создание Моделей Данных (User, Group, Post, Event)
Реализация Маршрутов API
Создание Контроллеров
Мидлвары для Аутентификации
Запуск и Тестирование Проекта
Шаг 1: Настройка Проекта
Если у вас уже есть существующий проект с MongoDB, вы можете продолжить в нём, адаптируя его для SQLite. В противном случае, создайте новый каталог для бэкенда:


mkdir hika-mori-backend
cd hika-mori-backend
npm init -y
Шаг 2: Установка Необходимых Пакетов
Установите следующие пакеты:


npm install express sequelize sqlite3 dotenv bcryptjs jsonwebtoken cors
npm install --save-dev nodemon
Описание Пакетов:

express: Фреймворк для создания веб-приложений.
sequelize: ORM для Node.js, поддерживающий SQLite.
sqlite3: Библиотека для работы с SQLite.
dotenv: Управление переменными окружения.
bcryptjs: Хеширование паролей.
jsonwebtoken: Создание и проверка JWT токенов.
cors: Разрешение междоменных запросов.
nodemon: Автоматический перезапуск сервера при изменениях в коде.
Шаг 3: Организация Структуры Каталогов
Создайте следующую структуру каталогов:


hika-mori-backend/
├── config/
│   └── db.js
├── controllers/
│   ├── authController.js
│   ├── groupController.js
│   ├── postController.js
│   └── eventController.js
├── middlewares/
│   └── authMiddleware.js
├── models/
│   ├── User.js
│   ├── Group.js
│   ├── Post.js
│   └── Event.js
├── routes/
│   ├── authRoutes.js
│   ├── groupRoutes.js
│   ├── postRoutes.js
│   └── eventRoutes.js
├── .env
├── server.js
└── package.json
Теперь рассмотрим каждый из файлов.

Шаг 4: Настройка Подключения к SQLite с использованием Sequelize
Файл: config/db.js


// config/db.js
const { Sequelize } = require('sequelize');
const dotenv = require('dotenv');

dotenv.config();

// Инициализация Sequelize с использованием SQLite
const sequelize = new Sequelize({
    dialect: 'sqlite',
    storage: process.env.SQLITE_STORAGE || 'database.sqlite',
    logging: false, // Отключение логирования SQL-запросов
});

const connectDB = async () => {
    try {
        await sequelize.authenticate();
        console.log('✅ Подключение к SQLite успешно установлено.');
    } catch (error) {
        console.error('❌ Не удалось подключиться к SQLite:', error);
        process.exit(1);
    }
};

// Экспорт Sequelize и функции подключения
module.exports = { sequelize, connectDB };
Файл: .env

Создайте файл .env в корне проекта и добавьте следующие переменные окружения:


PORT=5000
JWT_SECRET=your_jwt_secret_key
SQLITE_STORAGE=./database.sqlite
Примечание:

JWT_SECRET: Используйте длинную и сложную строку для обеспечения безопасности токенов.
SQLITE_STORAGE: Путь к файлу SQLite. По умолчанию используется database.sqlite в корне проекта.
Шаг 5: Создание Моделей Данных
Мы создадим четыре модели: User (Пользователь), Group (Сообщество), Post (Пост), Event (Событие).

1. Модель Пользователя
Файл: models/User.js


// models/User.js
const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/db');
const bcrypt = require('bcryptjs');

const User = sequelize.define('User', {
    username: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true,
    },
    email: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true,
        validate: {
            isEmail: {
                msg: 'Неверный формат электронной почты',
            },
        },
    },
    password: {
        type: DataTypes.STRING,
        allowNull: false,
        minlength: 6,
    },
}, {
    timestamps: true,
    hooks: {
        beforeCreate: async (user) => {
            const salt = await bcrypt.genSalt(10);
            user.password = await bcrypt.hash(user.password, salt);
        },
        beforeUpdate: async (user) => {
            if (user.changed('password')) {
                const salt = await bcrypt.genSalt(10);
                user.password = await bcrypt.hash(user.password, salt);
            }
        },
    },
});

// Метод для проверки пароля
User.prototype.matchPassword = async function(enteredPassword) {
    return await bcrypt.compare(enteredPassword, this.password);
};

module.exports = User;
2. Модель Сообщества
Файл: models/Group.js


// models/Group.js
const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/db');
const User = require('./User');

const Group = sequelize.define('Group', {
    name: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true,
    },
    description: {
        type: DataTypes.TEXT,
        allowNull: false,
    },
}, {
    timestamps: true,
});

// Определение отношений
Group.belongsTo(User, { as: 'creator', foreignKey: 'createdBy' });
User.hasMany(Group, { foreignKey: 'createdBy' });

// Множественные отношения для участников сообщества
Group.belongsToMany(User, { through: 'GroupMembers', as: 'members', foreignKey: 'groupId' });
User.belongsToMany(Group, { through: 'GroupMembers', as: 'groups', foreignKey: 'userId' });

module.exports = Group;
3. Модель Поста
Файл: models/Post.js


// models/Post.js
const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/db');
const User = require('./User');
const Group = require('./Group');

const Post = sequelize.define('Post', {
    content: {
        type: DataTypes.TEXT,
        allowNull: false,
    },
    image: {
        type: DataTypes.STRING, // URL или путь к изображению
        allowNull: true,
    },
}, {
    timestamps: true,
});

// Определение отношений
Post.belongsTo(User, { as: 'author', foreignKey: 'authorId' });
User.hasMany(Post, { foreignKey: 'authorId' });

Post.belongsTo(Group, { as: 'group', foreignKey: 'groupId' });
Group.hasMany(Post, { foreignKey: 'groupId' });

// Множественные отношения для лайков
Post.belongsToMany(User, { through: 'PostLikes', as: 'likedBy', foreignKey: 'postId' });
User.belongsToMany(Post, { through: 'PostLikes', as: 'likedPosts', foreignKey: 'userId' });

module.exports = Post;
4. Модель События
Файл: models/Event.js


// models/Event.js
const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/db');
const User = require('./User');
const Group = require('./Group');

const Event = sequelize.define('Event', {
    name: {
        type: DataTypes.STRING,
        allowNull: false,
    },
    description: {
        type: DataTypes.TEXT,
        allowNull: false,
    },
    location: {
        type: DataTypes.STRING,
        allowNull: false,
    },
    date: {
        type: DataTypes.DATE,
        allowNull: false,
    },
}, {
    timestamps: true,
});

// Определение отношений
Event.belongsTo(Group, { as: 'group', foreignKey: 'groupId' });
Group.hasMany(Event, { foreignKey: 'groupId' });

Event.belongsTo(User, { as: 'creator', foreignKey: 'createdBy' });
User.hasMany(Event, { foreignKey: 'createdBy' });

// Множественные отношения для участников события
Event.belongsToMany(User, { through: 'EventAttendees', as: 'attendees', foreignKey: 'eventId' });
User.belongsToMany(Event, { through: 'EventAttendees', as: 'attendedEvents', foreignKey: 'userId' });

module.exports = Event;
Примечание: Sequelize автоматически создаст таблицы промежуточных связей (GroupMembers, PostLikes, EventAttendees) для belongsToMany отношений.

Шаг 6: Реализация Маршрутов API
Создайте файлы маршрутов для аутентификации, сообществ, постов и событий.

1. Маршруты Аутентификации
Файл: routes/authRoutes.js


// routes/authRoutes.js
const express = require('express');
const router = express.Router();
const { registerUser, loginUser, getMe } = require('../controllers/authController');
const { protect } = require('../middlewares/authMiddleware');

// Регистрация пользователя
router.post('/register', registerUser);

// Вход пользователя
router.post('/login', loginUser);

// Получение информации о текущем пользователе
router.get('/me', protect, getMe);

module.exports = router;
2. Маршруты Сообществ
Файл: routes/groupRoutes.js


// routes/groupRoutes.js
const express = require('express');
const router = express.Router();
const {
    createGroup,
    getGroups,
    getGroupById,
    updateGroup,
    deleteGroup,
    joinGroup,
    leaveGroup
} = require('../controllers/groupController');
const { protect } = require('../middlewares/authMiddleware');

// Создание нового сообщества
router.post('/', protect, createGroup);

// Получение всех сообществ
router.get('/', getGroups);

// Получение сообщества по ID
router.get('/:id', getGroupById);

// Обновление сообщества
router.put('/:id', protect, updateGroup);

// Удаление сообщества
router.delete('/:id', protect, deleteGroup);

// Присоединение к сообществу
router.post('/:id/join', protect, joinGroup);

// Покидание сообщества
router.post('/:id/leave', protect, leaveGroup);

module.exports = router;
3. Маршруты Постов
Файл: routes/postRoutes.js


// routes/postRoutes.js
const express = require('express');
const router = express.Router();
const {
    createPost,
    getPostsByGroup,
    getPostById,
    updatePost,
    deletePost,
    likePost,
    unlikePost
} = require('../controllers/postController');
const { protect } = require('../middlewares/authMiddleware');

// Создание нового поста
router.post('/', protect, createPost);

// Получение всех постов в сообществе
router.get('/group/:groupId', getPostsByGroup);

// Получение поста по ID
router.get('/:id', getPostById);

// Обновление поста
router.put('/:id', protect, updatePost);

// Удаление поста
router.delete('/:id', protect, deletePost);

// Лайк поста
router.post('/:id/like', protect, likePost);

// Удаление лайка поста
router.post('/:id/unlike', protect, unlikePost);

module.exports = router;
4. Маршруты Событий
Файл: routes/eventRoutes.js


// routes/eventRoutes.js
const express = require('express');
const router = express.Router();
const {
    createEvent,
    getEventsByGroup,
    getEventById,
    updateEvent,
    deleteEvent,
    attendEvent,
    unattendEvent
} = require('../controllers/eventController');
const { protect } = require('../middlewares/authMiddleware');

// Создание нового события
router.post('/', protect, createEvent);

// Получение всех событий в сообществе
router.get('/group/:groupId', getEventsByGroup);

// Получение события по ID
router.get('/:id', getEventById);

// Обновление события
router.put('/:id', protect, updateEvent);

// Удаление события
router.delete('/:id', protect, deleteEvent);

// Присоединение к событию
router.post('/:id/attend', protect, attendEvent);

// Отмена присоединения к событию
router.post('/:id/unattend', protect, unattendEvent);

module.exports = router;
5. Объединение Маршрутов
Файл: routes/index.js


// routes/index.js
const express = require('express');
const router = express.Router();

const authRoutes = require('./authRoutes');
const groupRoutes = require('./groupRoutes');
const postRoutes = require('./postRoutes');
const eventRoutes = require('./eventRoutes');

router.use('/api/auth', authRoutes);
router.use('/api/groups', groupRoutes);
router.use('/api/posts', postRoutes);
router.use('/api/events', eventRoutes);

module.exports = router;
Шаг 7: Создание Контроллеров
1. Контроллер Аутентификации
Файл: controllers/authController.js


// controllers/authController.js
const User = require('../models/User');
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');

dotenv.config();

// Генерация JWT токена
const generateToken = (id) => {
    return jwt.sign({ id }, process.env.JWT_SECRET, {
        expiresIn: '30d',
    });
};

// Регистрация пользователя
exports.registerUser = async (req, res) => {
    const { username, email, password } = req.body;

    try {
        // Проверка существования пользователя
        const userExists = await User.findOne({ where: { [User.sequelize.Op.or]: [{ email }, { username }] } });

        if (userExists) {
            return res.status(400).json({ message: 'Пользователь с таким email или именем уже существует' });
        }

        // Создание пользователя
        const user = await User.create({
            username,
            email,
            password,
        });

        if (user) {
            res.status(201).json({
                id: user.id,
                username: user.username,
                email: user.email,
                token: generateToken(user.id),
            });
        } else {
            res.status(400).json({ message: 'Некорректные данные пользователя' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

// Вход пользователя
exports.loginUser = async (req, res) => {
    const { email, password } = req.body;

    try {
        // Поиск пользователя по email
        const user = await User.findOne({ where: { email } });

        if (user && (await user.matchPassword(password))) {
            res.json({
                id: user.id,
                username: user.username,
                email: user.email,
                token: generateToken(user.id),
            });
        } else {
            res.status(401).json({ message: 'Неверный email или пароль' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

// Получение информации о текущем пользователе
exports.getMe = async (req, res) => {
    try {
        const user = await User.findByPk(req.user.id, {
            attributes: { exclude: ['password'] },
            include: [
                {
                    model: Group,
                    as: 'groups',
                    through: { attributes: [] },
                },
                {
                    model: Group,
                    as: 'createdGroups',
                },
                {
                    model: Post,
                    as: 'posts',
                },
            ],
        });

        if (user) {
            res.json(user);
        } else {
            res.status(404).json({ message: 'Пользователь не найден' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};
2. Контроллер Сообществ
Файл: controllers/groupController.js


// controllers/groupController.js
const Group = require('../models/Group');
const User = require('../models/User');

exports.createGroup = async (req, res) => {
    const { name, description } = req.body;

    try {
        // Проверка на существование сообщества с таким названием
        const groupExists = await Group.findOne({ where: { name } });

        if (groupExists) {
            return res.status(400).json({ message: 'Сообщество с таким названием уже существует' });
        }

        const group = await Group.create({
            name,
            description,
            createdBy: req.user.id,
        });

        // Добавление создателя в участников сообщества
        await group.addMember(req.user.id);

        res.status(201).json(group);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.getGroups = async (req, res) => {
    try {
        const groups = await Group.findAll({
            include: [
                { model: User, as: 'creator', attributes: ['id', 'username'] },
                { model: User, as: 'members', attributes: ['id', 'username'], through: { attributes: [] } },
            ],
            order: [['createdAt', 'DESC']],
        });
        res.json(groups);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.getGroupById = async (req, res) => {
    try {
        const group = await Group.findByPk(req.params.id, {
            include: [
                { model: User, as: 'creator', attributes: ['id', 'username'] },
                { model: User, as: 'members', attributes: ['id', 'username'], through: { attributes: [] } },
            ],
        });

        if (group) {
            res.json(group);
        } else {
            res.status(404).json({ message: 'Сообщество не найдено' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.updateGroup = async (req, res) => {
    const { name, description } = req.body;

    try {
        const group = await Group.findByPk(req.params.id);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        // Проверка, является ли текущий пользователь создателем сообщества
        if (group.createdBy !== req.user.id) {
            return res.status(401).json({ message: 'Неавторизованный доступ' });
        }

        group.name = name || group.name;
        group.description = description || group.description;

        const updatedGroup = await group.save();
        res.json(updatedGroup);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.deleteGroup = async (req, res) => {
    try {
        const group = await Group.findByPk(req.params.id);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        // Проверка, является ли текущий пользователь создателем сообщества
        if (group.createdBy !== req.user.id) {
            return res.status(401).json({ message: 'Неавторизованный доступ' });
        }

        await group.destroy();
        res.json({ message: 'Сообщество удалено' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.joinGroup = async (req, res) => {
    try {
        const group = await Group.findByPk(req.params.id);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        // Проверка, не является ли пользователь уже членом сообщества
        const isMember = await group.hasMember(req.user.id);
        if (isMember) {
            return res.status(400).json({ message: 'Вы уже являетесь членом этого сообщества' });
        }

        await group.addMember(req.user.id);
        res.json({ message: 'Вы присоединились к сообществу' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.leaveGroup = async (req, res) => {
    try {
        const group = await Group.findByPk(req.params.id);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        // Проверка, является ли пользователь членом сообщества
        const isMember = await group.hasMember(req.user.id);
        if (!isMember) {
            return res.status(400).json({ message: 'Вы не являетесь членом этого сообщества' });
        }

        await group.removeMember(req.user.id);
        res.json({ message: 'Вы покинули сообщество' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};
3. Контроллер Постов
Файл: controllers/postController.js


// controllers/postController.js
const Post = require('../models/Post');
const Group = require('../models/Group');
const User = require('../models/User');

exports.createPost = async (req, res) => {
    const { groupId, content, image } = req.body;

    try {
        // Проверка существования сообщества
        const group = await Group.findByPk(groupId);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        // Проверка, является ли пользователь членом сообщества
        const isMember = await group.hasMember(req.user.id);
        if (!isMember) {
            return res.status(401).json({ message: 'Вы не являетесь членом этого сообщества' });
        }

        const post = await Post.create({
            groupId,
            authorId: req.user.id,
            content,
            image,
        });

        res.status(201).json(post);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.getPostsByGroup = async (req, res) => {
    const { groupId } = req.params;

    try {
        const group = await Group.findByPk(groupId);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        const posts = await Post.findAll({
            where: { groupId },
            include: [
                { model: User, as: 'author', attributes: ['id', 'username'] },
                { model: User, as: 'likedBy', attributes: ['id', 'username'], through: { attributes: [] } },
            ],
            order: [['createdAt', 'DESC']],
        });

        res.json(posts);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.getPostById = async (req, res) => {
    try {
        const post = await Post.findByPk(req.params.id, {
            include: [
                { model: User, as: 'author', attributes: ['id', 'username'] },
                { model: Group, as: 'group', attributes: ['id', 'name'] },
                { model: User, as: 'likedBy', attributes: ['id', 'username'], through: { attributes: [] } },
            ],
        });

        if (post) {
            res.json(post);
        } else {
            res.status(404).json({ message: 'Пост не найден' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.updatePost = async (req, res) => {
    const { content, image } = req.body;

    try {
        const post = await Post.findByPk(req.params.id);

        if (!post) {
            return res.status(404).json({ message: 'Пост не найден' });
        }

        // Проверка, является ли текущий пользователь автором поста
        if (post.authorId !== req.user.id) {
            return res.status(401).json({ message: 'Неавторизованный доступ' });
        }

        post.content = content || post.content;
        post.image = image || post.image;

        const updatedPost = await post.save();
        res.json(updatedPost);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.deletePost = async (req, res) => {
    try {
        const post = await Post.findByPk(req.params.id);

        if (!post) {
            return res.status(404).json({ message: 'Пост не найден' });
        }

        // Проверка, является ли текущий пользователь автором поста
        if (post.authorId !== req.user.id) {
            return res.status(401).json({ message: 'Неавторизованный доступ' });
        }

        await post.destroy();
        res.json({ message: 'Пост удалён' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.likePost = async (req, res) => {
    try {
        const post = await Post.findByPk(req.params.id);

        if (!post) {
            return res.status(404).json({ message: 'Пост не найден' });
        }

        // Проверка, поставил ли пользователь лайк ранее
        const hasLiked = await post.hasLikedBy(req.user.id);
        if (hasLiked) {
            return res.status(400).json({ message: 'Вы уже поставили лайк этому посту' });
        }

        await post.addLikedBy(req.user.id);
        res.json({ message: 'Пост понравился' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.unlikePost = async (req, res) => {
    try {
        const post = await Post.findByPk(req.params.id);

        if (!post) {
            return res.status(404).json({ message: 'Пост не найден' });
        }

        // Проверка, поставил ли пользователь лайк ранее
        const hasLiked = await post.hasLikedBy(req.user.id);
        if (!hasLiked) {
            return res.status(400).json({ message: 'Вы не поставили лайк этому посту' });
        }

        await post.removeLikedBy(req.user.id);
        res.json({ message: 'Лайк удалён' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};
4. Контроллер Событий
Файл: controllers/eventController.js


// controllers/eventController.js
const Event = require('../models/Event');
const Group = require('../models/Group');
const User = require('../models/User');

exports.createEvent = async (req, res) => {
    const { groupId, name, description, location, date } = req.body;

    try {
        // Проверка существования сообщества
        const group = await Group.findByPk(groupId);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        // Проверка, является ли пользователь членом сообщества
        const isMember = await group.hasMember(req.user.id);
        if (!isMember) {
            return res.status(401).json({ message: 'Вы не являетесь членом этого сообщества' });
        }

        const event = await Event.create({
            groupId,
            name,
            description,
            location,
            date,
            createdBy: req.user.id,
        });

        res.status(201).json(event);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.getEventsByGroup = async (req, res) => {
    const { groupId } = req.params;

    try {
        const group = await Group.findByPk(groupId);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        const events = await Event.findAll({
            where: { groupId },
            include: [
                { model: User, as: 'creator', attributes: ['id', 'username'] },
                { model: User, as: 'attendees', attributes: ['id', 'username'], through: { attributes: [] } },
            ],
            order: [['date', 'DESC']],
        });

        res.json(events);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.getEventById = async (req, res) => {
    try {
        const event = await Event.findByPk(req.params.id, {
            include: [
                { model: Group, as: 'group', attributes: ['id', 'name'] },
                { model: User, as: 'creator', attributes: ['id', 'username'] },
                { model: User, as: 'attendees', attributes: ['id', 'username'], through: { attributes: [] } },
            ],
        });

        if (event) {
            res.json(event);
        } else {
            res.status(404).json({ message: 'Событие не найдено' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.updateEvent = async (req, res) => {
    const { name, description, location, date } = req.body;

    try {
        const event = await Event.findByPk(req.params.id);

        if (!event) {
            return res.status(404).json({ message: 'Событие не найдено' });
        }

        // Проверка, является ли текущий пользователь создателем события
        if (event.createdBy !== req.user.id) {
            return res.status(401).json({ message: 'Неавторизованный доступ' });
        }

        event.name = name || event.name;
        event.description = description || event.description;
        event.location = location || event.location;
        event.date = date || event.date;

        const updatedEvent = await event.save();
        res.json(updatedEvent);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.deleteEvent = async (req, res) => {
    try {
        const event = await Event.findByPk(req.params.id);

        if (!event) {
            return res.status(404).json({ message: 'Событие не найдено' });
        }

        // Проверка, является ли текущий пользователь создателем события
        if (event.createdBy !== req.user.id) {
            return res.status(401).json({ message: 'Неавторизованный доступ' });
        }

        await event.destroy();
        res.json({ message: 'Событие удалено' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.attendEvent = async (req, res) => {
    try {
        const event = await Event.findByPk(req.params.id);

        if (!event) {
            return res.status(404).json({ message: 'Событие не найдено' });
        }

        // Проверка, не присоединился ли пользователь ранее
        const isAttendee = await event.hasAttendee(req.user.id);
        if (isAttendee) {
            return res.status(400).json({ message: 'Вы уже присоединились к этому событию' });
        }

        await event.addAttendee(req.user.id);
        res.json({ message: 'Вы присоединились к событию' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};

exports.unattendEvent = async (req, res) => {
    try {
        const event = await Event.findByPk(req.params.id);

        if (!event) {
            return res.status(404).json({ message: 'Событие не найдено' });
        }

        // Проверка, присоединился ли пользователь ранее
        const isAttendee = await event.hasAttendee(req.user.id);
        if (!isAttendee) {
            return res.status(400).json({ message: 'Вы не присоединились к этому событию' });
        }

        await event.removeAttendee(req.user.id);
        res.json({ message: 'Вы отменили присоединение к событию' });
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};
Шаг 8: Мидлвары для Аутентификации
Файл: middlewares/authMiddleware.js


// middlewares/authMiddleware.js
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const dotenv = require('dotenv');

dotenv.config();

exports.protect = async (req, res, next) => {
    let token;

    // Проверка наличия токена в заголовках
    if (
        req.headers.authorization &&
        req.headers.authorization.startsWith('Bearer')
    ) {
        try {
            // Получение токена
            token = req.headers.authorization.split(' ')[1];

            // Верификация токена
            const decoded = jwt.verify(token, process.env.JWT_SECRET);

            // Получение пользователя по ID из токена
            req.user = await User.findByPk(decoded.id, { attributes: { exclude: ['password'] } });

            if (!req.user) {
                return res.status(401).json({ message: 'Пользователь не найден' });
            }

            next();
        } catch (error) {
            console.error(error);
            res.status(401).json({ message: 'Неавторизованный доступ, токен недействителен' });
        }
    }

    if (!token) {
        res.status(401).json({ message: 'Неавторизованный доступ, токен не предоставлен' });
    }
};
Шаг 9: Создание Основного Файла Сервера
Файл: server.js


// server.js
const express = require('express');
const dotenv = require('dotenv');
const { connectDB, sequelize } = require('./config/db');
const routes = require('./routes');
const cors = require('cors');

// Инициализация переменных окружения
dotenv.config();

// Подключение к базе данных
connectDB();

// Импорт моделей (для инициализации ассоциаций)
const User = require('./models/User');
const Group = require('./models/Group');
const Post = require('./models/Post');
const Event = require('./models/Event');

// Инициализация Express-приложения
const app = express();

// Middleware
app.use(express.json());
app.use(cors({
    origin: 'http://localhost:3000', // Замените на URL вашего фронтенда
    credentials: true,
}));

// Маршруты
app.use(routes);

// Обработка некорректных маршрутов
app.use((req, res, next) => {
    res.status(404).json({ message: `Маршрут ${req.originalUrl} не найден` });
});

// Обработка ошибок
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({ message: 'Внутренняя ошибка сервера', error: err.message });
});

// Синхронизация моделей и запуск сервера
const PORT = process.env.PORT || 5000;

sequelize.sync({ alter: true }).then(() => {
    app.listen(PORT, () => {
        console.log(`🚀 Сервер запущен на порту ${PORT}`);
    });
}).catch((error) => {
    console.error('❌ Не удалось синхронизировать базы данных:', error);
});
Примечание:

sequelize.sync({ alter: true }): Этот параметр синхронизирует модели с базой данных, автоматически внося необходимые изменения. Внимание: Используйте alter: true только в процессе разработки. Для продакшена рассмотрите использование миграций.
Шаг 10: Запуск и Тестирование Проекта
Создайте и Запустите Сервер:

npm run dev
Сервер должен вывести сообщение ✅ Подключение к SQLite успешно установлено. и 🚀 Сервер запущен на порту 5000.
Тестируйте API: Используйте такие инструменты, как Postman или Insomnia, для тестирования созданных маршрутов. Пример Регистрации Пользователя:
URL: http://localhost:5000/api/auth/register
Метод: POST
Тело (JSON):

{
  "username": "Otaku_Lover",
  "email": "otaku@example.com",
  "password": "password123"
}
Пример Входа Пользователя:
URL: http://localhost:5000/api/auth/login
Метод: POST
Тело (JSON):

{
  "email": "otaku@example.com",
  "password": "password123"
}
Свяжите Фронтенд с Бэкендом: Обновите ваш фронтенд код для взаимодействия с новым бэкендом. Например, используйте fetch или axios для отправки запросов к API. Пример Использования Axios для Регистрации:

// js/auth.js
import axios from 'axios';

const registerForm = document.getElementById('registerForm');

registerForm.addEventListener('submit', async (e) => {
    e.preventDefault();

    const username = document.getElementById('registerUsername').value;
    const email = document.getElementById('registerEmail').value;
    const password = document.getElementById('registerPassword').value;

    try {
        const response = await axios.post('http://localhost:5000/api/auth/register', { username, email, password });
        const data = response.data;

        // Сохранение токена в localStorage
        localStorage.setItem('token', data.token);

        // Перенаправление или обновление интерфейса
        alert('Регистрация успешна!');
    } catch (error) {
        if (error.response && error.response.data.message) {
            alert(error.response.data.message);
        } else {
            alert('Произошла ошибка при регистрации');
        }
    }
});
Пример Использования Axios для Входа:

// js/auth.js
import axios from 'axios';

const loginForm = document.getElementById('loginForm');

loginForm.addEventListener('submit', async (e) => {
    e.preventDefault();

    const email = document.getElementById('loginEmail').value;
    const password = document.getElementById('loginPassword').value;

    try {
        const response = await axios.post('http://localhost:5000/api/auth/login', { email, password });
        const data = response.data;

        // Сохранение токена в localStorage
        localStorage.setItem('token', data.token);

        // Перенаправление или обновление интерфейса
        alert('Вход успешен!');
    } catch (error) {
        if (error.response && error.response.data.message) {
            alert(error.response.data.message);
        } else {
            alert('Произошла ошибка при входе');
        }
    }
});
Добавление Аутентификации к Защищённым Маршрутам: При отправке запросов к защищённым маршрутам, добавьте заголовок Authorization с токеном. Пример Получения Информации о Пользователе:

// js/profile.js
import axios from 'axios';

document.addEventListener('DOMContentLoaded', async () => {
    const token = localStorage.getItem('token');

    if (!token) {
        // Перенаправление на страницу входа
        return;
    }

    try {
        const response = await axios.get('http://localhost:5000/api/auth/me', {
            headers: {
                'Authorization': `Bearer ${token}`,
            },
        });

        const user = response.data;

        // Отображение информации о пользователе
        document.getElementById('profileUsername').textContent = user.username;
        document.getElementById('profileEmail').textContent = user.email;
        // Другие элементы профиля
    } catch (error) {
        if (error.response && error.response.data.message) {
            alert(error.response.data.message);
        } else {
            alert('Произошла ошибка при получении профиля');
        }
    }
});
Дополнительные Рекомендации
Загрузка Изображений: Если пользователи смогут загружать изображения, вы можете использовать multer для обработки multipart/form-data запросов. Установка Multer:

npm install multer
Пример Использования Multer в Маршрутах Постов:

// routes/postRoutes.js
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const {
    createPost,
    getPostsByGroup,
    getPostById,
    updatePost,
    deletePost,
    likePost,
    unlikePost
} = require('../controllers/postController');
const { protect } = require('../middlewares/authMiddleware');

// Настройка хранения файлов
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
        cb(null, Date.now() + path.extname(file.originalname));
    }
});

const upload = multer({ storage: storage });

// Создание нового поста с изображением
router.post('/', protect, upload.single('image'), createPost);

// Остальные маршруты остаются прежними
Создайте Каталог для Загрузок:

mkdir uploads
Обновите Контроллер Постов для Обработки Изображений:

// controllers/postController.js
exports.createPost = async (req, res) => {
    const { groupId, content } = req.body;
    const image = req.file ? `/uploads/${req.file.filename}` : null;

    try {
        // Проверка существования сообщества
        const group = await Group.findByPk(groupId);

        if (!group) {
            return res.status(404).json({ message: 'Сообщество не найдено' });
        }

        // Проверка, является ли пользователь членом сообщества
        const isMember = await group.hasMember(req.user.id);
        if (!isMember) {
            return res.status(401).json({ message: 'Вы не являетесь членом этого сообщества' });
        }

        const post = await Post.create({
            groupId,
            authorId: req.user.id,
            content,
            image,
        });

        res.status(201).json(post);
    } catch (error) {
        res.status(500).json({ message: 'Серверная ошибка', error: error.message });
    }
};
Использование Транзакций: Для обеспечения целостности данных используйте транзакции при выполнении связанных операций.
Безопасность:
Helmet: Добавьте helmet для установки безопасных заголовков. Установка:

npm install helmet
Использование в server.js:

const helmet = require('helmet');
app.use(helmet());
Rate Limiting: Ограничьте количество запросов для предотвращения атак типа DDoS. Установка express-rate-limit:

npm install express-rate-limit
Использование:

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
    windowMs: 10 * 60 * 1000, // 10 минут
    max: 100, // максимум 100 запросов с одного IP
    message: 'Слишком много запросов с этого IP, попробуйте позже',
});

app.use(limiter);
Документация API: Рассмотрите использование инструментов, таких как Swagger, для документирования вашего API.
Тестирование: Пишите тесты для вашего API используя такие инструменты, как Jest и Supertest.
Заключение
Теперь ваш бэкенд переписан для использования SQLite с помощью Sequelize. Он поддерживает основные функции вашего сайта "Хика Морi": аутентификацию пользователей, управление сообществами, постами и событиями. Этот подход обеспечивает лёгкую настройку и управление базой данных, а также масштабируемость для будущих расширений.

Следующие Шаги:

Интеграция С Фронтендом: Обновите свой фронтенд код, чтобы взаимодействовать с новым бэкендом через API.
Деплой: Приготовьте ваш проект к развёртыванию на продакшн сервере. Убедитесь, что переменные окружения настроены корректно.
Дополнительные Функции: Добавьте новые функции по мере необходимости, такие как уведомления, личные сообщения и т.д.
Если у вас возникнут дополнительные вопросы или потребуется помощь с конкретными частями проекта, не стесняйтесь обращаться!