From 420e67c9bdbc0c1bf46928dc9186c570f5717b0c Mon Sep 17 00:00:00 2001 From: Alisa Date: Wed, 3 Jun 2026 23:24:10 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BD=20=D1=88?= =?UTF-8?q?=D0=B0=D0=B3=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 1 + database/schema.sql | 373 ++++++++++++++++++++++++++++++++++- database/seed.sql | 37 ++++ docs/ШАГ_2_БАЗА_ДАННЫХ.md | 160 +++++++++++++++ public/assets/css/app.css | 27 +++ public/install.php | 85 ++++++++ ПЛАН_ДЕЙСТВИЙ_РЫБСТОК.md | 3 +- ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md | 12 +- 8 files changed, 688 insertions(+), 10 deletions(-) create mode 100644 database/seed.sql create mode 100644 docs/ШАГ_2_БАЗА_ДАННЫХ.md create mode 100644 public/install.php diff --git a/.env.example b/.env.example index 9b9e44c..62b9627 100644 --- a/.env.example +++ b/.env.example @@ -12,3 +12,4 @@ DB_CHARSET=utf8mb4 MAIL_FROM=orders@loveriba.ru ADMIN_EMAIL= +INSTALL_TOKEN=change-this-token diff --git a/database/schema.sql b/database/schema.sql index 90b890d..baac768 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -1,2 +1,371 @@ --- RybStock database schema will be designed on step 2. --- Database: alice_ro2 +-- RybStock database schema +-- MariaDB/MySQL, charset utf8mb4 + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +DROP TABLE IF EXISTS order_status_history; +DROP TABLE IF EXISTS order_items; +DROP TABLE IF EXISTS orders; +DROP TABLE IF EXISTS delivery_calculations; +DROP TABLE IF EXISTS promocode_targets; +DROP TABLE IF EXISTS promocodes; +DROP TABLE IF EXISTS product_search_terms; +DROP TABLE IF EXISTS product_images; +DROP TABLE IF EXISTS product_variants; +DROP TABLE IF EXISTS popular_products; +DROP TABLE IF EXISTS promo_block_items; +DROP TABLE IF EXISTS products; +DROP TABLE IF EXISTS categories; +DROP TABLE IF EXISTS reviews; +DROP TABLE IF EXISTS customer_login_codes; +DROP TABLE IF EXISTS customer_email_tokens; +DROP TABLE IF EXISTS site_settings; +DROP TABLE IF EXISTS holidays; +DROP TABLE IF EXISTS admins; + +CREATE TABLE admins ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + name VARCHAR(120) NOT NULL, + email VARCHAR(190) NOT NULL, + password_hash VARCHAR(255) NOT NULL, + role ENUM('owner', 'manager', 'content') NOT NULL DEFAULT 'owner', + is_active TINYINT(1) NOT NULL DEFAULT 1, + last_login_at DATETIME NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_admins_email (email) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE categories ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + parent_id BIGINT UNSIGNED NULL, + name VARCHAR(190) NOT NULL, + slug VARCHAR(220) NOT NULL, + description TEXT NULL, + seo_title VARCHAR(255) NULL, + seo_description TEXT NULL, + image_path VARCHAR(255) NULL, + sort_order INT NOT NULL DEFAULT 100, + is_active TINYINT(1) NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_categories_slug (slug), + KEY idx_categories_parent (parent_id), + KEY idx_categories_active_sort (is_active, sort_order), + CONSTRAINT fk_categories_parent + FOREIGN KEY (parent_id) REFERENCES categories(id) + ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE products ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + category_id BIGINT UNSIGNED NULL, + name VARCHAR(220) NOT NULL, + slug VARCHAR(240) NOT NULL, + sku VARCHAR(100) NULL, + short_description TEXT NULL, + description MEDIUMTEXT NULL, + product_info MEDIUMTEXT NULL, + main_image_path VARCHAR(255) NULL, + base_unit ENUM('kg', 'g', 'l', 'ml', 'pcs', 'pack') NOT NULL DEFAULT 'kg', + package_display_mode ENUM('auto', 'base_and_package', 'package_only') NOT NULL DEFAULT 'auto', + is_weight_product TINYINT(1) NOT NULL DEFAULT 1, + is_published TINYINT(1) NOT NULL DEFAULT 0, + is_available TINYINT(1) NOT NULL DEFAULT 1, + is_new TINYINT(1) NOT NULL DEFAULT 0, + is_hit TINYINT(1) NOT NULL DEFAULT 0, + is_promo TINYINT(1) NOT NULL DEFAULT 0, + sort_order INT NOT NULL DEFAULT 100, + sales_count INT UNSIGNED NOT NULL DEFAULT 0, + last_sold_at DATETIME NULL, + published_at DATETIME NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_products_slug (slug), + UNIQUE KEY uq_products_sku (sku), + KEY idx_products_category (category_id), + KEY idx_products_public (is_published, is_available, sort_order), + KEY idx_products_sales (sales_count, last_sold_at), + FULLTEXT KEY ft_products_text (name, short_description, description, product_info), + CONSTRAINT fk_products_category + FOREIGN KEY (category_id) REFERENCES categories(id) + ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE product_variants ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + product_id BIGINT UNSIGNED NOT NULL, + name VARCHAR(190) NOT NULL, + unit ENUM('kg', 'g', 'l', 'ml', 'pcs', 'pack') NOT NULL DEFAULT 'kg', + package_quantity DECIMAL(10,3) NOT NULL DEFAULT 1.000, + step_quantity DECIMAL(10,3) NOT NULL DEFAULT 1.000, + price_per_unit DECIMAL(12,2) NULL, + package_price DECIMAL(12,2) NOT NULL, + old_package_price DECIMAL(12,2) NULL, + min_order_quantity DECIMAL(10,3) NOT NULL DEFAULT 1.000, + stock_quantity DECIMAL(12,3) NULL, + is_default TINYINT(1) NOT NULL DEFAULT 0, + is_published TINYINT(1) NOT NULL DEFAULT 1, + is_available TINYINT(1) NOT NULL DEFAULT 1, + sort_order INT NOT NULL DEFAULT 100, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_variants_product (product_id), + KEY idx_variants_public (product_id, is_published, is_available, sort_order), + CONSTRAINT fk_variants_product + FOREIGN KEY (product_id) REFERENCES products(id) + ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE product_images ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + product_id BIGINT UNSIGNED NOT NULL, + path VARCHAR(255) NOT NULL, + alt VARCHAR(255) NULL, + sort_order INT NOT NULL DEFAULT 100, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_product_images_product (product_id, sort_order), + CONSTRAINT fk_product_images_product + FOREIGN KEY (product_id) REFERENCES products(id) + ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE product_search_terms ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + product_id BIGINT UNSIGNED NOT NULL, + term VARCHAR(190) NOT NULL, + weight TINYINT UNSIGNED NOT NULL DEFAULT 5, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_search_terms_term (term), + KEY idx_search_terms_product (product_id), + CONSTRAINT fk_search_terms_product + FOREIGN KEY (product_id) REFERENCES products(id) + ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE promocodes ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + code VARCHAR(80) NOT NULL, + title VARCHAR(190) NOT NULL, + discount_type ENUM('fixed', 'percent') NOT NULL, + discount_value DECIMAL(12,2) NOT NULL, + min_order_amount DECIMAL(12,2) NOT NULL DEFAULT 0.00, + applies_to ENUM('order', 'category', 'product') NOT NULL DEFAULT 'order', + payment_note VARCHAR(255) NULL DEFAULT 'Действует при наличном расчете', + starts_at DATETIME NULL, + ends_at DATETIME NULL, + usage_limit INT UNSIGNED NULL, + used_count INT UNSIGNED NOT NULL DEFAULT 0, + is_active TINYINT(1) NOT NULL DEFAULT 1, + is_featured TINYINT(1) NOT NULL DEFAULT 0, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_promocodes_code (code), + KEY idx_promocodes_active (is_active, starts_at, ends_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE promocode_targets ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + promocode_id BIGINT UNSIGNED NOT NULL, + target_type ENUM('category', 'product') NOT NULL, + target_id BIGINT UNSIGNED NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_promocode_target (promocode_id, target_type, target_id), + KEY idx_promocode_targets_lookup (target_type, target_id), + CONSTRAINT fk_promocode_targets_promocode + FOREIGN KEY (promocode_id) REFERENCES promocodes(id) + ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE delivery_calculations ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + delivery_type ENUM('inside_mkad', 'outside_mkad', 'pickup') NOT NULL, + address VARCHAR(500) NULL, + order_amount DECIMAL(12,2) NOT NULL DEFAULT 0.00, + distance_from_mkad_km DECIMAL(8,2) NULL, + free_delivery_threshold DECIMAL(12,2) NULL, + delivery_price DECIMAL(12,2) NOT NULL DEFAULT 0.00, + lift_price DECIMAL(12,2) NOT NULL DEFAULT 0.00, + total_delivery_price DECIMAL(12,2) NOT NULL DEFAULT 0.00, + provider VARCHAR(80) NULL, + provider_payload MEDIUMTEXT NULL, + explanation TEXT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_delivery_type_created (delivery_type, created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE orders ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + order_number VARCHAR(40) NOT NULL, + customer_name VARCHAR(120) NOT NULL, + phone VARCHAR(40) NOT NULL, + email VARCHAR(190) NULL, + delivery_type ENUM('inside_mkad', 'outside_mkad', 'pickup') NOT NULL, + address VARCHAR(500) NULL, + desired_date DATE NULL, + customer_comment TEXT NULL, + admin_comment TEXT NULL, + status ENUM('new', 'confirmed', 'assembling', 'ready', 'delivering', 'completed', 'cancelled') NOT NULL DEFAULT 'new', + subtotal_amount DECIMAL(12,2) NOT NULL DEFAULT 0.00, + discount_amount DECIMAL(12,2) NOT NULL DEFAULT 0.00, + delivery_amount DECIMAL(12,2) NOT NULL DEFAULT 0.00, + total_amount DECIMAL(12,2) NOT NULL DEFAULT 0.00, + promocode_id BIGINT UNSIGNED NULL, + promocode_code VARCHAR(80) NULL, + delivery_calculation_id BIGINT UNSIGNED NULL, + client_ip VARCHAR(45) NULL, + user_agent VARCHAR(255) NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_orders_number (order_number), + KEY idx_orders_status_created (status, created_at), + KEY idx_orders_email (email), + KEY idx_orders_phone (phone), + CONSTRAINT fk_orders_promocode + FOREIGN KEY (promocode_id) REFERENCES promocodes(id) + ON DELETE SET NULL, + CONSTRAINT fk_orders_delivery_calculation + FOREIGN KEY (delivery_calculation_id) REFERENCES delivery_calculations(id) + ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE order_items ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + order_id BIGINT UNSIGNED NOT NULL, + product_id BIGINT UNSIGNED NULL, + variant_id BIGINT UNSIGNED NULL, + product_name VARCHAR(220) NOT NULL, + variant_name VARCHAR(190) NOT NULL, + unit VARCHAR(20) NOT NULL, + package_quantity DECIMAL(10,3) NOT NULL, + quantity DECIMAL(10,3) NOT NULL, + price_per_unit DECIMAL(12,2) NULL, + package_price DECIMAL(12,2) NOT NULL, + line_total DECIMAL(12,2) NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_order_items_order (order_id), + KEY idx_order_items_product (product_id), + CONSTRAINT fk_order_items_order + FOREIGN KEY (order_id) REFERENCES orders(id) + ON DELETE CASCADE, + CONSTRAINT fk_order_items_product + FOREIGN KEY (product_id) REFERENCES products(id) + ON DELETE SET NULL, + CONSTRAINT fk_order_items_variant + FOREIGN KEY (variant_id) REFERENCES product_variants(id) + ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE order_status_history ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + order_id BIGINT UNSIGNED NOT NULL, + old_status VARCHAR(40) NULL, + new_status VARCHAR(40) NOT NULL, + comment TEXT NULL, + admin_id BIGINT UNSIGNED NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_status_history_order (order_id, created_at), + CONSTRAINT fk_status_history_order + FOREIGN KEY (order_id) REFERENCES orders(id) + ON DELETE CASCADE, + CONSTRAINT fk_status_history_admin + FOREIGN KEY (admin_id) REFERENCES admins(id) + ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE customer_login_codes ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + email VARCHAR(190) NOT NULL, + code_hash VARCHAR(255) NOT NULL, + expires_at DATETIME NOT NULL, + used_at DATETIME NULL, + attempts TINYINT UNSIGNED NOT NULL DEFAULT 0, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_customer_codes_email (email), + KEY idx_customer_codes_expires (expires_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE reviews ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + source ENUM('yandex', 'manual') NOT NULL DEFAULT 'manual', + author_name VARCHAR(160) NOT NULL, + rating TINYINT UNSIGNED NOT NULL DEFAULT 5, + text TEXT NOT NULL, + external_url VARCHAR(500) NULL, + reviewed_at DATE NULL, + is_published TINYINT(1) NOT NULL DEFAULT 1, + sort_order INT NOT NULL DEFAULT 100, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_reviews_public (is_published, rating, sort_order), + CONSTRAINT chk_reviews_rating CHECK (rating BETWEEN 1 AND 5) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE promo_block_items ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + product_id BIGINT UNSIGNED NOT NULL, + title VARCHAR(190) NULL, + is_active TINYINT(1) NOT NULL DEFAULT 1, + sort_order INT NOT NULL DEFAULT 100, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + KEY idx_promo_block_active (is_active, sort_order), + CONSTRAINT fk_promo_block_product + FOREIGN KEY (product_id) REFERENCES products(id) + ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE popular_products ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + product_id BIGINT UNSIGNED NOT NULL, + mode ENUM('manual', 'pinned') NOT NULL DEFAULT 'manual', + is_active TINYINT(1) NOT NULL DEFAULT 1, + sort_order INT NOT NULL DEFAULT 100, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_popular_product (product_id), + KEY idx_popular_products_active (is_active, sort_order), + CONSTRAINT fk_popular_product + FOREIGN KEY (product_id) REFERENCES products(id) + ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE site_settings ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + setting_key VARCHAR(120) NOT NULL, + setting_value MEDIUMTEXT NULL, + value_type ENUM('string', 'text', 'number', 'bool', 'json') NOT NULL DEFAULT 'string', + group_name VARCHAR(80) NOT NULL DEFAULT 'general', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_site_settings_key (setting_key), + KEY idx_site_settings_group (group_name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE holidays ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + holiday_date DATE NOT NULL, + title VARCHAR(190) NOT NULL, + is_working_day TINYINT(1) NOT NULL DEFAULT 0, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id), + UNIQUE KEY uq_holidays_date (holiday_date) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/database/seed.sql b/database/seed.sql new file mode 100644 index 0000000..3c0e91e --- /dev/null +++ b/database/seed.sql @@ -0,0 +1,37 @@ +-- RybStock starter data +-- Run after database/schema.sql + +SET NAMES utf8mb4; + +INSERT INTO categories (name, slug, sort_order, is_active) VALUES +('Рыба', 'fish', 10, 1), +('Готовая продукция', 'gotovaya-produkciya', 20, 1), +('Полуфабрикаты', 'polufabrikaty', 30, 1), +('Мясо', 'myaso', 40, 1), +('Сыры', 'syry', 50, 1), +('Ягоды', 'yagody', 60, 1), +('Овощи', 'ovoschi', 70, 1); + +INSERT INTO promocodes + (code, title, discount_type, discount_value, min_order_amount, applies_to, is_active, is_featured) +VALUES + ('Рыбсток7000', '300 руб. при заказе от 7000 руб.', 'fixed', 300.00, 7000.00, 'order', 1, 1), + ('Рыбсток20000', '5% при заказе от 20000 руб.', 'percent', 5.00, 20000.00, 'order', 1, 1), + ('Рыбсток50000', '7% при заказе от 50000 руб.', 'percent', 7.00, 50000.00, 'order', 1, 1); + +INSERT INTO site_settings (setting_key, setting_value, value_type, group_name) VALUES +('site_phone', '+7-977-736-33-63', 'string', 'contacts'), +('admin_email', '', 'string', 'mail'), +('inside_mkad_free_from', '5000', 'number', 'delivery'), +('inside_mkad_paid_price', '599', 'number', 'delivery'), +('outside_mkad_base_price', '199', 'number', 'delivery'), +('outside_mkad_km_price', '60', 'number', 'delivery'), +('outside_mkad_free_km_multiplier', '1000', 'number', 'delivery'), +('outside_mkad_free_under_10km', '10000', 'number', 'delivery'), +('lift_price', '390', 'number', 'delivery'), +('freezer_temp_min', '-20', 'number', 'freshness'), +('freezer_temp_max', '-18', 'number', 'freshness'), +('fridge_temp_min', '-2', 'number', 'freshness'), +('fridge_temp_max', '1', 'number', 'freshness'), +('freezer_area_text', 'более 1800 кв. м', 'string', 'freshness'), +('fridge_area_text', 'более 500 кв. м', 'string', 'freshness'); diff --git a/docs/ШАГ_2_БАЗА_ДАННЫХ.md b/docs/ШАГ_2_БАЗА_ДАННЫХ.md new file mode 100644 index 0000000..cc7959f --- /dev/null +++ b/docs/ШАГ_2_БАЗА_ДАННЫХ.md @@ -0,0 +1,160 @@ +# Шаг 2. База данных и связи + +## Что сделано + +Создана SQL-схема `database/schema.sql` для MariaDB/MySQL и стартовые данные `database/seed.sql`. + +Также создана локальная страница установки `public/install.php`. + +Она применяет: + +- `database/schema.sql`; +- `database/seed.sql`. + +Важно: установка пересоздает таблицы, поэтому использовать ее только на старте или в локальной разработке. + +Схема покрывает основные части проекта: + +- администраторы; +- категории и подкатегории; +- товары; +- фасовки и цены; +- изображения товаров; +- поисковые термины; +- промокоды и их привязки; +- расчеты доставки; +- заказы и позиции заказов; +- история статусов заказа; +- вход клиента по email-коду; +- отзывы; +- акции; +- популярные товары; +- настройки сайта; +- праздничные/нерабочие дни. + +## Главная логика связей + +### Категории + +Таблица `categories` поддерживает вложенность через `parent_id`. + +Это позволяет хранить: + +- главные категории; +- подкатегории; +- меню каталога; +- SEO-текст для страниц категорий. + +### Товары + +Таблица `products` хранит основную карточку товара: + +- название; +- slug; +- категорию; +- описание; +- основное фото; +- базовую единицу; +- режим отображения цены; +- публикацию; +- доступность; +- признаки "новинка", "хит", "акция". + +### Фасовки + +Таблица `product_variants` хранит отдельные фасовки товара. + +Именно фасовка попадает в корзину, а не просто товар. + +Пример: + +- товар: горбуша неразделанная; +- фасовка: пласт 10 кг; +- `package_quantity`: 10; +- `step_quantity`: 10; +- `price_per_unit`: 600; +- `package_price`: 6000. + +Так можно корректно сделать плюс/минус кратно фасовке. + +### Заказы + +Таблица `orders` хранит заказ целиком: + +- имя; +- телефон; +- email; +- тип получения; +- адрес; +- суммы; +- промокод; +- расчет доставки; +- статус. + +Таблица `order_items` хранит снимок каждой позиции заказа. + +Снимок нужен, чтобы старые заказы не менялись при изменении цены или названия товара в каталоге. + +### Промокоды + +Таблица `promocodes` хранит сам промокод. + +Таблица `promocode_targets` хранит ограничения: + +- на категорию; +- на товар. + +Если промокод действует на весь заказ, targets не нужны. + +### Доставка + +Таблица `delivery_calculations` хранит результат расчета: + +- тип доставки; +- адрес; +- сумма заказа; +- расстояние от МКАД; +- порог бесплатной доставки; +- стоимость доставки; +- стоимость подъема; +- объяснение расчета. + +Это нужно, чтобы в заказе сохранялся расчет, который видел клиент. + +### История заказов по email + +Таблица `customer_login_codes` хранит одноразовые коды входа по email. + +SMS не используются. + +### Настройки + +Таблица `site_settings` хранит настройки сайта: + +- телефон; +- email администратора; +- правила доставки; +- температуры камер; +- тексты и числовые параметры. + +## Как применить схему + +1. Открыть в браузере `/install.php?token=rybstock-local-install`. +2. Нажать кнопку "Создать таблицы и стартовые данные". +3. После успешной установки база будет содержать таблицы проекта и стартовые категории/настройки. + +Страница работает только при `APP_ENV=local` и правильном `INSTALL_TOKEN` из `.env`. + +## Что нужно сделать следующим шагом + +Шаг 3: + +1. Создать базовые PHP-классы для работы с таблицами: + - `CategoryRepository`; + - `ProductRepository`; + - `ProductVariantRepository`; + - `OrderRepository`; + - `PromocodeRepository`; + - `SettingRepository`. +2. Сделать первый вывод категорий на главной странице. +3. Подготовить основу админки: вход администратора и список разделов. diff --git a/public/assets/css/app.css b/public/assets/css/app.css index 6f09c2f..9cc26e9 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -51,3 +51,30 @@ p { border-radius: 8px; background: #eef4ea; } + +.status-box.success { + background: #e8f5ec; + color: #145a2a; +} + +.status-box.danger { + background: #fff0ee; + color: #8a1f11; +} + +.primary-button { + appearance: none; + border: 0; + border-radius: 8px; + padding: 14px 18px; + margin-top: 18px; + font-size: 16px; + font-weight: 700; + color: #ffffff; + background: #1d5d3b; + cursor: pointer; +} + +.primary-button:hover { + background: #16492e; +} diff --git a/public/install.php b/public/install.php new file mode 100644 index 0000000..7fee3e0 --- /dev/null +++ b/public/install.php @@ -0,0 +1,85 @@ +getMessage() + : 'Ошибка установки базы данных.'; + } + } +} + +function run_sql_file(PDO $pdo, string $path): void +{ + if (!is_file($path)) { + throw new RuntimeException('SQL file not found: ' . $path); + } + + $sql = file_get_contents($path); + + if ($sql === false) { + throw new RuntimeException('Cannot read SQL file: ' . $path); + } + + $pdo->exec($sql); +} +?> + + + + + + Установка базы Рыбсток + + + +
+
+

Шаг 2

+

Установка базы

+

Эта страница применяет `database/schema.sql` и `database/seed.sql`. Таблицы будут пересозданы.

+ + +
Установка доступна только при APP_ENV=local.
+ +
Добавьте токен в адрес страницы: ?token=...
+ +
+ +
+ + + +
+ + + +
+ +
+
+ + diff --git a/ПЛАН_ДЕЙСТВИЙ_РЫБСТОК.md b/ПЛАН_ДЕЙСТВИЙ_РЫБСТОК.md index 9553ccd..0036b68 100644 --- a/ПЛАН_ДЕЙСТВИЙ_РЫБСТОК.md +++ b/ПЛАН_ДЕЙСТВИЙ_РЫБСТОК.md @@ -628,4 +628,5 @@ ## 11. Статус выполнения - Шаг 1 выполнен: выбрана техническая связка на чистом PHP, создан стартовый каркас проекта, подключение к MariaDB через `.env`, базовые папки и файл `ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md`. -- Следующий шаг: спроектировать базу данных, модели, связи и структуру собственной админки. +- Шаг 2 выполнен: создана SQL-схема базы `database/schema.sql`, стартовые данные `database/seed.sql`, страница установки `public/install.php` и документ `docs/ШАГ_2_БАЗА_ДАННЫХ.md`. +- Следующий шаг: применить схему через `/install.php?token=rybstock-local-install`, затем сделать первые PHP-классы для чтения категорий, товаров, фасовок и настроек. diff --git a/ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md b/ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md index 7fe9133..4b67455 100644 --- a/ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md +++ b/ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md @@ -251,21 +251,19 @@ loveriba.ru/ ## Второй шаг -Следующий шаг: спроектировать базу данных и модели проекта под чистый PHP. +Второй шаг выполнен: база данных спроектирована в файле `database/schema.sql`, стартовые данные добавлены в `database/seed.sql`, описание связей создано в `docs/ШАГ_2_БАЗА_ДАННЫХ.md`. -Нужно подготовить: +Подготовлено: 1. Список таблиц. 2. Поля каждой таблицы. 3. Связи между таблицами. 4. Правила расчета цены фасовки. 5. Правила расчета доставки. -6. Структуру собственной админки. -7. Первичный SQL-файл `database/schema.sql`. +6. Первичный SQL-файл `database/schema.sql`. +7. Стартовые данные `database/seed.sql`. -После второго шага можно будет создавать файловую структуру проекта и начинать код. - -Файловая структура уже создана на шаге 1, поэтому на шаге 2 можно сразу перейти к SQL-схеме, таблицам и первичным PHP-моделям. +Следующий шаг: сделать применение SQL-схемы и первичные PHP-классы для чтения данных. ## Что нужно уточнить перед кодом