# AETERNA - Интернет-магазин мебели и интерьера ``` ___ ________________ _ _____ / | / ____/_ __/ __ \/ | / / | / /| | / __/ / / / /_/ / |/ / /| | / ___ |/ /___ / / / _, _/ /| / ___ | /_/ |_/_____/ /_/ /_/ |_/_/ |_/_/ |_| Мебель, которая создает атмосферу ``` Полнофункциональный интернет-магазин мебели с административной панелью, системой авторизации, корзиной покупок и оформлением заказов. Проект разработан на PHP с использованием PostgreSQL в качестве базы данных. --- ## Оглавление - [Возможности](#возможности) - [Технологический стек](#технологический-стек) - [Структура проекта](#структура-проекта) - [База данных](#база-данных) - [Установка и настройка](#установка-и-настройка) - [Запуск проекта](#запуск-проекта) - [Аутентификация и авторизация](#аутентификация-и-авторизация) - [Функционал](#функционал) - [API Endpoints](#api-endpoints) - [Административная панель](#административная-панель) - [Функции и утилиты](#функции-и-утилиты) - [Безопасность](#безопасность) - [Тестовые аккаунты](#тестовые-аккаунты) - [Разработка](#разработка) - [Лицензия](#лицензия) --- ## Возможности ### Для покупателей - Просмотр каталога товаров с фильтрацией по категориям, цене, цвету и материалу - Поиск товаров по названию - Детальная страница товара с характеристиками - Корзина покупок с возможностью изменения количества - Оформление заказа с выбором способа доставки и оплаты - Личный кабинет с историей заказов - Регистрация и авторизация ### Для администраторов - Полное управление каталогом товаров (CRUD) - Управление категориями и подкатегориями - Просмотр и обработка заказов - Управление пользователями - Статистика продаж --- ## Технологический стек | Компонент | Технология | |-----------|------------| | Backend | PHP 7.4+ | | База данных | PostgreSQL 12+ | | Стилизация | LESS (компилируется в CSS) | | JavaScript | jQuery 3.6+ | | Иконки | Font Awesome 5.15 | | ORM/DB | PDO (PHP Data Objects) | ### Зависимости - PHP расширения: `pdo`, `pdo_pgsql`, `mbstring`, `json` - Браузерная компиляция LESS (less.js) --- ## Структура проекта ``` cite_practica1/ ├── admin/ # Административная панель │ └── index.php # Главная страница админки │ ├── api/ # API endpoints (дублируются в public/api/) │ ├── auth.php # Аутентификация пользователя │ ├── add_to_cart.php # Добавление товара в корзину │ ├── cart.php # Управление корзиной (add/update/remove/get/count) │ ├── get_cart.php # Получение содержимого корзины │ ├── get_cart_count.php # Количество товаров в корзине │ ├── get_product.php # Получение информации о товаре │ ├── process_order.php # Оформление заказа │ ├── register_handler.php # Регистрация пользователя │ └── update_cart.php # Обновление количества в корзине │ ├── assets/ # Статические ресурсы │ ├── css/ # Скомпилированные CSS файлы │ ├── img/ # Изображения товаров и интерфейса │ ├── js/ # JavaScript файлы │ │ ├── checkout.js # Логика оформления заказа │ │ └── profile.js # Логика профиля пользователя │ └── less/ # LESS исходники стилей │ ├── style.less # Основные стили │ ├── checkout.less # Стили страницы оформления │ └── mixins.less # LESS миксины │ ├── config/ # Конфигурация │ ├── database.php # Подключение к PostgreSQL │ └── check_auth.js # Клиентская проверка авторизации │ ├── includes/ # Общие компоненты │ ├── auth.php # Функции авторизации │ ├── footer.php # Футер сайта │ ├── functions.php # Вспомогательные функции │ └── header.php # Шапка сайта │ ├── migrations/ # SQL миграции базы данных │ ├── 001_initial_schema.sql # Начальная схема (users, categories, products) │ ├── 002_add_cart_orders.sql # Корзина и заказы │ ├── 003_add_product_fields.sql # Дополнительные поля товаров │ ├── 004_grant_admin_to_admin_mail.sql # Права администратора │ ├── grant_admin.php # Скрипт назначения админа │ ├── migrate.php # Раннер миграций │ └── seed_data.sql # Тестовые данные │ ├── public/ # Публичная директория (точка входа веб-сервера) │ ├── index.php # Главная страница │ ├── catalog.php # Каталог товаров │ ├── product.php # Страница товара │ ├── checkout.php # Оформление заказа / корзина │ ├── login.php # Страница входа │ ├── logout.php # Выход из аккаунта │ ├── register.php # Регистрация │ ├── services.php # Страница услуг │ ├── delivery.php # Доставка и оплата │ ├── warranty.php # Гарантия │ ├── header_common.php # Общий header │ ├── footer.php # Footer │ ├── api/ # API endpoints │ ├── config/ # Конфигурация │ ├── includes/ # Общие компоненты │ ├── img/ # Изображения │ └── assets/ # Статические ресурсы │ ├── uploads/ # Загруженные файлы │ └── products/ # Изображения товаров │ ├── setup.sh # Скрипт первоначальной настройки ├── style_for_cite.less # Основной файл стилей └── README.md # Этот файл ``` --- ## База данных ### Схема базы данных ```mermaid erDiagram users ||--o{ cart : has users ||--o{ orders : places categories ||--o{ products : contains categories ||--o{ subcategories : has products ||--o{ cart : added_to products ||--o{ order_items : included_in orders ||--|{ order_items : contains users { int user_id PK varchar email UK varchar password_hash varchar full_name varchar phone varchar city timestamp created_at timestamp updated_at timestamp last_login boolean is_active boolean is_admin } categories { int category_id PK varchar name varchar slug UK int parent_id FK text description int sort_order boolean is_active timestamp created_at timestamp updated_at } subcategories { int subcategory_id PK int category_id FK varchar name varchar slug UK text description int sort_order boolean is_active timestamp created_at } products { int product_id PK int category_id FK varchar name varchar slug UK text description decimal price decimal old_price varchar sku UK int stock_quantity boolean is_available boolean is_featured decimal rating int review_count varchar image_url varchar color varchar material varchar card_size timestamp created_at timestamp updated_at } cart { int cart_id PK int user_id FK int product_id FK int quantity timestamp created_at timestamp updated_at } orders { int order_id PK varchar order_number UK int user_id FK varchar customer_name varchar customer_email varchar customer_phone text delivery_address varchar delivery_region varchar postal_code varchar delivery_method varchar payment_method decimal subtotal decimal discount_amount decimal delivery_price decimal final_amount varchar promo_code varchar status text notes timestamp created_at timestamp updated_at timestamp completed_at } order_items { int item_id PK int order_id FK int product_id FK varchar product_name decimal product_price int quantity decimal total_price timestamp created_at } ``` ### Описание таблиц | Таблица | Описание | |---------|----------| | `users` | Пользователи системы (покупатели и администраторы) | | `categories` | Категории товаров (Диваны, Кресла, Кровати и т.д.) | | `subcategories` | Подкатегории для более детальной классификации | | `products` | Товары с ценами, описанием и характеристиками | | `cart` | Корзина покупок (связь пользователь-товар-количество) | | `orders` | Заказы с информацией о доставке и оплате | | `order_items` | Позиции заказа (товары в заказе) | | `migrations` | Служебная таблица для отслеживания миграций | ### Миграции Миграции выполняются в следующем порядке: 1. `001_initial_schema.sql` - Создание таблиц users, categories, subcategories, products 2. `002_add_cart_orders.sql` - Добавление таблиц cart, orders, order_items 3. `003_add_product_fields.sql` - Дополнительные поля для товаров (color, material, card_size) 4. `004_grant_admin_to_admin_mail.sql` - Назначение прав администратора --- ## Установка и настройка ### Требования - PHP 7.4 или выше - PostgreSQL 12 или выше - Веб-сервер (Apache/Nginx) или встроенный PHP сервер для разработки ### Шаг 1: Клонирование репозитория ```bash git clone cd cite_practica1 ``` ### Шаг 2: Настройка базы данных Отредактируйте файл `config/database.php`: ```php connection = new PDO( "pgsql:host=ВАШ_ХОСТ;port=5432;dbname=ВАШ_DBNAME", "ВАШ_ЛОГИН", "ВАШ_ПАРОЛЬ" ); $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->connection->exec("SET NAMES 'utf8'"); } catch(PDOException $e) { die("Ошибка подключения: " . $e->getMessage()); } } public static function getInstance() { if (self::$instance == null) { self::$instance = new Database(); } return self::$instance; } public function getConnection() { return $this->connection; } } ``` ### Шаг 3: Запуск миграций **Вариант 1: Автоматическая настройка** ```bash chmod +x setup.sh ./setup.sh ``` **Вариант 2: Ручной запуск миграций** ```bash php migrations/migrate.php ``` **Вариант 3: Загрузка тестовых данных** ```bash php migrations/migrate.php --seed ``` ### Шаг 4: Настройка прав доступа ```bash chmod -R 755 public/ chmod -R 777 uploads/ ``` --- ## Запуск проекта ### Разработка (встроенный PHP сервер) ```bash cd public php -S localhost:8000 ``` Затем откройте в браузере: http://localhost:8000 ### Production (Apache) Пример конфигурации Virtual Host: ```apache ServerName aeterna.local DocumentRoot /path/to/cite_practica1/public AllowOverride All Require all granted ErrorLog ${APACHE_LOG_DIR}/aeterna_error.log CustomLog ${APACHE_LOG_DIR}/aeterna_access.log combined ``` ### Production (Nginx) ```nginx server { listen 80; server_name aeterna.local; root /path/to/cite_practica1/public; index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(ht|git) { deny all; } } ``` --- ## Аутентификация и авторизация ### Архитектура аутентификации ```mermaid flowchart TD A[Пользователь] --> B{Авторизован?} B -->|Нет| C[Страница входа] B -->|Да| D{Роль?} C --> E[Ввод email/пароль] E --> F[API: auth.php] F --> G{Проверка в БД} G -->|Успех| H[Создание сессии] G -->|Ошибка| I[Сообщение об ошибке] H --> J[Сохранение в SESSION] J --> K[Редирект на каталог] D -->|Пользователь| L[Доступ к каталогу, корзине, заказам] D -->|Админ| M[Доступ к админ-панели] ``` ### Система сессий При успешной авторизации в сессию сохраняются: ```php $_SESSION['user_id'] // ID пользователя $_SESSION['user_email'] // Email $_SESSION['full_name'] // Полное имя $_SESSION['isLoggedIn'] // true $_SESSION['isAdmin'] // true/false $_SESSION['login_time'] // Время входа ``` ### Защита страниц ```php // Требовать авторизацию if (!isset($_SESSION['isLoggedIn']) || $_SESSION['isLoggedIn'] !== true) { header('Location: login.php?error=auth_required'); exit(); } // Требовать права администратора if (!isset($_SESSION['isAdmin']) || $_SESSION['isAdmin'] !== true) { header('Location: login.php?error=admin_required'); exit(); } ``` ### Роли пользователей | Роль | Доступ | |------|--------| | Гость | Главная страница, услуги, доставка, гарантия | | Пользователь | + Каталог, корзина, оформление заказов, личный кабинет | | Администратор | + Админ-панель, управление товарами, заказами, пользователями | --- ## Функционал ### Пользовательский интерфейс ```mermaid flowchart LR subgraph pages [Страницы] A[Главная] --> B[Каталог] B --> C[Товар] C --> D[Корзина] D --> E[Оформление] E --> F[Успех] end subgraph auth [Авторизация] G[Вход] --> H[Регистрация] end subgraph info [Информация] I[Услуги] J[Доставка] K[Гарантия] L[Контакты] end ``` #### Главная страница (`public/index.php`) - Hero-секция с призывом к действию - Преимущества компании - Промо-блоки с акциями - Секция "О нас" - Слайдер с готовыми решениями - Статистика компании - FAQ (частые вопросы) #### Каталог товаров (`public/catalog.php`) - Сетка товаров с изображениями - Фильтрация по: - Категориям - Диапазону цен - Цвету - Материалу - Поиск по названию - Добавление в корзину #### Страница товара (`public/product.php`) - Галерея изображений - Описание и характеристики - Цена и скидка - Наличие на складе - Кнопка добавления в корзину - Рекомендуемые товары #### Корзина (`public/checkout.php`) - Список товаров в корзине - Изменение количества - Удаление товаров - Расчет итоговой суммы - Применение промокода - Форма оформления заказа --- ## API Endpoints ### Аутентификация #### POST `/api/auth.php` Авторизация пользователя **Запрос:** ```json { "email": "user@example.com", "password": "password123" } ``` **Ответ (успех):** ```json { "success": true, "redirect": "catalog.php" } ``` **Ответ (ошибка):** ```json { "success": false, "message": "Неверный пароль" } ``` --- ### Корзина #### POST `/api/cart.php?action=add` Добавление товара в корзину **Запрос:** ```json { "product_id": 1, "quantity": 2 } ``` **Ответ:** ```json { "success": true, "message": "Товар добавлен в корзину" } ``` --- #### POST `/api/cart.php?action=update` Обновление количества товара **Запрос:** ```json { "product_id": 1, "quantity": 3 } ``` --- #### POST `/api/cart.php?action=remove` Удаление товара из корзины **Запрос:** ```json { "product_id": 1 } ``` --- #### GET `/api/cart.php?action=get` Получение содержимого корзины **Ответ:** ```json { "success": true, "items": [ { "cart_id": 1, "product_id": 5, "quantity": 2, "name": "Диван ROYALTY", "price": 78999, "image_url": "img2/6_6.png" } ], "total": 157998 } ``` --- #### GET `/api/cart.php?action=count` Количество товаров в корзине **Ответ:** ```json { "success": true, "count": 3 } ``` --- ### Товары #### GET `/api/get_product.php?id=1` Получение информации о товаре **Ответ:** ```json { "success": true, "product": { "product_id": 1, "name": "Светильник MINNIGHT", "description": "Настольный светильник в современном стиле", "price": 7999, "old_price": 9999, "image_url": "img2/1_2.png", "color": "Черный", "material": "Металл", "stock_quantity": 15, "is_available": true } } ``` --- ### Заказы #### POST `/api/process_order.php` Оформление заказа **Запрос:** ```json { "customer_name": "Иван Иванов", "customer_email": "ivan@example.com", "customer_phone": "+79001234567", "delivery_address": "г. Москва, ул. Примерная, д. 1", "delivery_method": "courier", "payment_method": "card" } ``` **Ответ:** ```json { "success": true, "order_number": "AET-20251216-ABC123", "message": "Заказ успешно оформлен" } ``` --- ## Административная панель ### Доступ URL: `/admin/index.php` или `/public/catalog_admin.php` Требуется авторизация с правами администратора (`is_admin = TRUE`) ### Функции ```mermaid flowchart TD A[Админ-панель] --> B[Dashboard] A --> C[Категории] A --> D[Товары] A --> E[Заказы] A --> F[Пользователи] C --> C1[Список категорий] C --> C2[Добавить категорию] C --> C3[Редактировать] C --> C4[Удалить] D --> D1[Список товаров] D --> D2[Добавить товар] D --> D3[Редактировать] D --> D4[Удалить] D --> D5[Загрузка изображений] E --> E1[Список заказов] E --> E2[Детали заказа] E --> E3[Изменить статус] ``` ### Управление категориями - Создание категорий и подкатегорий - Редактирование названия и описания - Установка порядка сортировки - Активация/деактивация ### Управление товарами - Добавление новых товаров - Редактирование характеристик - Загрузка изображений - Установка цен и скидок - Управление наличием ### Управление заказами Статусы заказов: | Статус | Описание | |--------|----------| | `pending` | Ожидает обработки | | `processing` | В обработке | | `shipped` | Отправлен | | `delivered` | Доставлен | | `cancelled` | Отменен | --- ## Функции и утилиты ### `includes/functions.php` #### Проверка авторизации ```php /** * Проверка авторизации пользователя */ function isLoggedIn(): bool { return isset($_SESSION['isLoggedIn']) && $_SESSION['isLoggedIn'] === true; } /** * Проверка прав администратора */ function isAdmin(): bool { return isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === true; } ``` #### Защита страниц ```php /** * Требовать авторизацию - редирект на login если не авторизован */ function requireAuth(string $redirectUrl = 'login.php'): void { if (!isLoggedIn()) { header('Location: ' . $redirectUrl . '?error=auth_required'); exit(); } } /** * Требовать права администратора */ function requireAdmin(string $redirectUrl = 'login.php'): void { if (!isAdmin()) { header('Location: ' . $redirectUrl . '?error=admin_required'); exit(); } } ``` #### Получение текущего пользователя ```php /** * Получить текущего пользователя */ function getCurrentUser(): ?array { if (!isLoggedIn()) { return null; } return [ 'user_id' => $_SESSION['user_id'] ?? 0, 'email' => $_SESSION['user_email'] ?? '', 'full_name' => $_SESSION['full_name'] ?? '', 'is_admin' => isAdmin() ]; } ``` #### Форматирование ```php /** * Форматирование цены */ function formatPrice(float $price): string { return number_format($price, 0, '', ' ') . ' ₽'; } /** * Безопасный вывод HTML */ function e(string $str): string { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); } ``` #### Генерация идентификаторов ```php /** * Генерация номера заказа */ function generateOrderNumber(): string { return 'AET-' . date('Ymd') . '-' . strtoupper(substr(uniqid(), -6)); } /** * Создание slug из строки */ function createSlug(string $str): string { $slug = transliterate($str); $slug = strtolower($slug); $slug = preg_replace('/[^a-z0-9]+/', '-', $slug); return trim($slug, '-'); } ``` #### Транслитерация ```php /** * Транслитерация кириллицы в латиницу */ function transliterate(string $str): string { $converter = [ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', // ... и т.д. ]; return strtr($str, $converter); } ``` #### Flash-сообщения ```php /** * Установить flash-сообщение */ function setFlashMessage(string $type, string $message): void { $_SESSION['flash_message'] = [ 'type' => $type, 'message' => $message ]; } /** * Получить и удалить flash-сообщение */ function getFlashMessage(): ?array { if (isset($_SESSION['flash_message'])) { $message = $_SESSION['flash_message']; unset($_SESSION['flash_message']); return $message; } return null; } ``` --- ## Безопасность ### Защита от SQL-инъекций Все запросы к базе данных используют подготовленные выражения (Prepared Statements): ```php // ПРАВИЛЬНО - безопасно $stmt = $db->prepare("SELECT * FROM users WHERE email = ?"); $stmt->execute([$email]); // НЕПРАВИЛЬНО - уязвимо для SQL-инъекций $result = $db->query("SELECT * FROM users WHERE email = '$email'"); ``` ### Хеширование паролей Пароли хешируются с использованием bcrypt: ```php // Хеширование при регистрации $password_hash = password_hash($password, PASSWORD_DEFAULT); // Проверка при авторизации if (password_verify($password, $user['password_hash'])) { // Пароль верный } ``` ### Защита от XSS Все пользовательские данные экранируются при выводе: ```php // Безопасный вывод echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8'); // Или используя функцию-хелпер echo e($user_input); ``` ### Защита сессий ```php // Регенерация ID сессии после авторизации session_regenerate_id(true); // Проверка авторизации на каждой странице if (!isset($_SESSION['isLoggedIn']) || $_SESSION['isLoggedIn'] !== true) { header('Location: login.php'); exit(); } ``` ### CSRF-защита Рекомендуется добавить токены для форм: ```php // Генерация токена $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // В форме // Проверка if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) { die('CSRF token mismatch'); } ``` ### Проверка прав доступа ```php // Проверка на каждой защищенной странице if (!isset($_SESSION['isLoggedIn']) || $_SESSION['isLoggedIn'] !== true) { header('Location: login.php?error=auth_required'); exit(); } // Проверка прав администратора if (!isset($_SESSION['isAdmin']) || $_SESSION['isAdmin'] !== true) { die('Доступ запрещен'); } ``` --- ## Тестовые аккаунты После выполнения `seed_data.sql` доступны следующие аккаунты: ### Администратор | Поле | Значение | |------|----------| | Email | `admin@aeterna.ru` | | Пароль | `admin123` | | Имя | Администратор AETERNA | | Права | Полный доступ к админ-панели | ### Пользователь | Поле | Значение | |------|----------| | Email | `user@test.com` | | Пароль | `user123` | | Имя | Тестовый Пользователь | | Права | Доступ к каталогу, корзине, заказам | --- ## Разработка ### Создание новой миграции 1. Создайте файл `migrations/XXX_название.sql` (где XXX - следующий номер) 2. Напишите SQL-код 3. Запустите `php migrations/migrate.php` Пример миграции: ```sql -- 005_add_reviews.sql -- Добавление таблицы отзывов CREATE TABLE IF NOT EXISTS reviews ( review_id SERIAL PRIMARY KEY, product_id INTEGER REFERENCES products(product_id) ON DELETE CASCADE, user_id INTEGER REFERENCES users(user_id) ON DELETE SET NULL, rating INTEGER CHECK (rating >= 1 AND rating <= 5), comment TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_reviews_product ON reviews(product_id); ``` ### Стиль кода - Используйте PSR-12 для PHP - Именование переменных: `snake_case` - Именование функций: `camelCase` или `snake_case` - Именование классов: `PascalCase` - Комментируйте сложную логику - Используйте типизацию где возможно ### Структура API endpoint ```php false, 'message' => 'Требуется авторизация']); exit(); } try { $db = Database::getInstance()->getConnection(); // Ваша логика здесь echo json_encode(['success' => true, 'data' => $result]); } catch (PDOException $e) { echo json_encode(['success' => false, 'message' => 'Ошибка базы данных']); } ``` ### Добавление новой страницы 1. Создайте файл в `public/` 2. Подключите header и footer 3. Добавьте проверку авторизации если нужно 4. Используйте единый стиль оформления ```php AETERNA - Название страницы
``` --- ## Диаграмма архитектуры ```mermaid flowchart TB subgraph client [Клиент] Browser[Браузер] end subgraph server [Сервер] subgraph public [Public Directory] Index[index.php] Catalog[catalog.php] Product[product.php] Checkout[checkout.php] Login[login.php] end subgraph api [API Layer] Auth[auth.php] Cart[cart.php] Order[process_order.php] end subgraph core [Core] Config[database.php] Functions[functions.php] Includes[header/footer] end subgraph admin [Admin Panel] AdminIndex[admin/index.php] end end subgraph database [База данных] PostgreSQL[(PostgreSQL)] end Browser <--> Index Browser <--> Catalog Browser <--> Product Browser <--> Checkout Browser <--> Login Browser <--> Auth Browser <--> Cart Browser <--> Order Browser <--> AdminIndex Index --> Config Catalog --> Config Product --> Config Checkout --> Config Login --> Config Auth --> Config Cart --> Config Order --> Config AdminIndex --> Config Config <--> PostgreSQL ``` --- ## Поток оформления заказа ```mermaid sequenceDiagram participant U as Пользователь participant B as Браузер participant C as checkout.php participant API as process_order.php participant DB as PostgreSQL U->>B: Открывает корзину B->>C: GET /checkout.php C->>DB: SELECT cart items DB-->>C: Товары корзины C-->>B: HTML страница корзины U->>B: Заполняет форму заказа U->>B: Нажимает "Оформить" B->>API: POST /api/process_order.php API->>DB: BEGIN TRANSACTION API->>DB: INSERT INTO orders DB-->>API: order_id loop Для каждого товара API->>DB: INSERT INTO order_items API->>DB: UPDATE products (stock) end API->>DB: DELETE FROM cart API->>DB: COMMIT API-->>B: JSON success + order_number B-->>U: Страница успеха ``` --- ## Лицензия Этот проект создан в учебных целях. --- ## Контакты - **Email:** aeterna@mail.ru - **Телефон:** +7(912)999-12-23 - **Telegram:** @aeterna_shop --- ``` © 2025 AETERNA. Все права защищены. ```