шаг 1 сделан
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
APP_NAME=RybStock
|
||||||
|
APP_ENV=local
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost
|
||||||
|
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=database_name
|
||||||
|
DB_USERNAME=database_user
|
||||||
|
DB_PASSWORD="database_password"
|
||||||
|
DB_CHARSET=utf8mb4
|
||||||
|
|
||||||
|
MAIL_FROM=orders@loveriba.ru
|
||||||
|
ADMIN_EMAIL=
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
.env
|
||||||
|
/storage/logs/*.log
|
||||||
|
/storage/cache/*
|
||||||
|
/storage/exports/*
|
||||||
|
/storage/uploads/*
|
||||||
|
!/storage/cache/.gitkeep
|
||||||
|
!/storage/exports/.gitkeep
|
||||||
|
!/storage/uploads/.gitkeep
|
||||||
|
!/storage/logs/.gitkeep
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Рыбсток
|
||||||
|
|
||||||
|
Интернет-магазин продуктов питания на чистом PHP.
|
||||||
|
|
||||||
|
## Техническая основа
|
||||||
|
|
||||||
|
- PHP 8.2+ или PHP 8.3+
|
||||||
|
- MariaDB/MySQL
|
||||||
|
- PDO
|
||||||
|
- HTML/CSS/JavaScript
|
||||||
|
- Собственная админка на PHP
|
||||||
|
|
||||||
|
## Стартовая структура
|
||||||
|
|
||||||
|
- `public/` - публичная часть сайта и входная точка.
|
||||||
|
- `app/` - основной PHP-код.
|
||||||
|
- `views/` - шаблоны страниц.
|
||||||
|
- `admin/` - будущая админка.
|
||||||
|
- `database/` - SQL-схемы и данные.
|
||||||
|
- `storage/` - загрузки, экспорты, кеш и логи.
|
||||||
|
- `docs/` - проектная документация.
|
||||||
|
|
||||||
|
## База данных
|
||||||
|
|
||||||
|
Данные подключения хранятся в `.env`.
|
||||||
|
|
||||||
|
Для безопасности `.env` добавлен в `.gitignore`; пример настроек лежит в `.env.example`.
|
||||||
|
|
||||||
|
## Запуск локально
|
||||||
|
|
||||||
|
1. Установить Open Server Panel, Laragon или другой локальный сервер с PHP и MariaDB.
|
||||||
|
2. Направить корень сайта на папку `public/`.
|
||||||
|
3. Проверить настройки базы в `.env`.
|
||||||
|
4. Открыть сайт в браузере.
|
||||||
|
|
||||||
|
Если сервер смотрит не в `public/`, нужно настроить виртуальный хост, чтобы публичной была именно эта папка.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once dirname(__DIR__) . '/app/bootstrap.php';
|
||||||
|
|
||||||
|
echo 'RybStock admin panel will be created on the next steps.';
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Core;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
final class Database
|
||||||
|
{
|
||||||
|
private static ?PDO $pdo = null;
|
||||||
|
|
||||||
|
public static function pdo(): PDO
|
||||||
|
{
|
||||||
|
if (self::$pdo !== null) {
|
||||||
|
return self::$pdo;
|
||||||
|
}
|
||||||
|
|
||||||
|
$host = app_env('DB_HOST', 'localhost');
|
||||||
|
$port = app_env('DB_PORT', '3306');
|
||||||
|
$database = app_env('DB_DATABASE', '');
|
||||||
|
$charset = app_env('DB_CHARSET', 'utf8mb4');
|
||||||
|
$username = app_env('DB_USERNAME', '');
|
||||||
|
$password = app_env('DB_PASSWORD', '');
|
||||||
|
|
||||||
|
$dsn = "mysql:host={$host};port={$port};dbname={$database};charset={$charset}";
|
||||||
|
|
||||||
|
self::$pdo = new PDO($dsn, $username, $password, [
|
||||||
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
|
PDO::ATTR_EMULATE_PREPARES => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return self::$pdo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Core;
|
||||||
|
|
||||||
|
final class Env
|
||||||
|
{
|
||||||
|
public static function load(string $path): void
|
||||||
|
{
|
||||||
|
if (!is_file($path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
|
||||||
|
if ($lines === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$line = trim($line);
|
||||||
|
|
||||||
|
if ($line === '' || str_starts_with($line, '#')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[$key, $value] = array_pad(explode('=', $line, 2), 2, '');
|
||||||
|
$key = trim($key);
|
||||||
|
$value = self::normalizeValue(trim($value));
|
||||||
|
|
||||||
|
if ($key === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$_ENV[$key] = $value;
|
||||||
|
putenv($key . '=' . $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function normalizeValue(string $value): string
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
strlen($value) >= 2
|
||||||
|
&& (($value[0] === '"' && $value[-1] === '"') || ($value[0] === "'" && $value[-1] === "'"))
|
||||||
|
) {
|
||||||
|
return substr($value, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Core;
|
||||||
|
|
||||||
|
final class View
|
||||||
|
{
|
||||||
|
public static function render(string $template, array $data = []): void
|
||||||
|
{
|
||||||
|
$templatePath = base_path('views/' . trim($template, '/') . '.php');
|
||||||
|
|
||||||
|
if (!is_file($templatePath)) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo 'Template not found';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
extract($data, EXTR_SKIP);
|
||||||
|
|
||||||
|
require base_path('views/layouts/main.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
spl_autoload_register(static function (string $class): void {
|
||||||
|
$prefix = 'App\\';
|
||||||
|
|
||||||
|
if (!str_starts_with($class, $prefix)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$relativeClass = substr($class, strlen($prefix));
|
||||||
|
$path = __DIR__ . '/' . str_replace('\\', '/', $relativeClass) . '.php';
|
||||||
|
|
||||||
|
if (is_file($path)) {
|
||||||
|
require_once $path;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
require_once __DIR__ . '/helpers.php';
|
||||||
|
|
||||||
|
App\Core\Env::load(dirname(__DIR__) . '/.env');
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use App\Core\View;
|
||||||
|
|
||||||
|
function app_env(string $key, ?string $default = null): ?string
|
||||||
|
{
|
||||||
|
$value = $_ENV[$key] ?? getenv($key);
|
||||||
|
|
||||||
|
if ($value === false || $value === null) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function base_path(string $path = ''): string
|
||||||
|
{
|
||||||
|
$base = dirname(__DIR__);
|
||||||
|
|
||||||
|
return $path === '' ? $base : $base . '/' . ltrim($path, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function view(string $template, array $data = []): void
|
||||||
|
{
|
||||||
|
View::render($template, $data);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- RybStock database schema will be designed on step 2.
|
||||||
|
-- Database: alice_ro2
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
color: #18201b;
|
||||||
|
background: #f7f8f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-screen {
|
||||||
|
width: min(760px, 100%);
|
||||||
|
padding: 32px;
|
||||||
|
border: 1px solid #d9dfd3;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #687466;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-box {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 24px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #eef4ea;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use App\Core\Database;
|
||||||
|
|
||||||
|
require_once dirname(__DIR__) . '/app/bootstrap.php';
|
||||||
|
|
||||||
|
$dbStatus = 'not_checked';
|
||||||
|
|
||||||
|
try {
|
||||||
|
Database::pdo()->query('SELECT 1');
|
||||||
|
$dbStatus = 'connected';
|
||||||
|
} catch (Throwable $exception) {
|
||||||
|
$dbStatus = app_env('APP_DEBUG', 'false') === 'true'
|
||||||
|
? 'error: ' . $exception->getMessage()
|
||||||
|
: 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
view('pages/home', [
|
||||||
|
'title' => 'Рыбсток',
|
||||||
|
'dbStatus' => $dbStatus,
|
||||||
|
]);
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/** @var string $templatePath */
|
||||||
|
/** @var string $title */
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title><?= htmlspecialchars($title ?? 'Рыбсток', ENT_QUOTES, 'UTF-8') ?></title>
|
||||||
|
<link rel="stylesheet" href="/assets/css/app.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="page">
|
||||||
|
<?php require $templatePath; ?>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/** @var string $dbStatus */
|
||||||
|
?>
|
||||||
|
<section class="start-screen">
|
||||||
|
<p class="eyebrow">Старт проекта</p>
|
||||||
|
<h1>Рыбсток</h1>
|
||||||
|
<p>Чистый PHP-проект подготовлен. Следующий шаг - схема базы данных и таблицы для каталога, фасовок, заказов и админки.</p>
|
||||||
|
|
||||||
|
<div class="status-box">
|
||||||
|
<span>MariaDB:</span>
|
||||||
|
<strong><?= htmlspecialchars($dbStatus, ENT_QUOTES, 'UTF-8') ?></strong>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
+31
-34
@@ -356,7 +356,7 @@
|
|||||||
|
|
||||||
## 5. Вопросы, которые стоит уточнить перед разработкой
|
## 5. Вопросы, которые стоит уточнить перед разработкой
|
||||||
|
|
||||||
1. На какой платформе быстрее запускать проект: Laravel/Filament, WordPress/WooCommerce с доработками, 1C-Bitrix, Django, Next.js + готовая админка или другая связка?
|
1. Какой локальный сервер и хостинг использовать для проекта на чистом PHP: Open Server Panel, Laragon, обычный хостинг, VPS или другой вариант?
|
||||||
2. Есть ли уже текущий сайт, каталог, база товаров, Excel/CSV с товарами и фотографиями?
|
2. Есть ли уже текущий сайт, каталог, база товаров, Excel/CSV с товарами и фотографиями?
|
||||||
3. Как сейчас хранятся товары: в Excel, 1С, МойСклад, вручную, в другой CMS?
|
3. Как сейчас хранятся товары: в Excel, 1С, МойСклад, вручную, в другой CMS?
|
||||||
4. Нужно ли интегрироваться с 1С, МойСкладом или другой учетной системой?
|
4. Нужно ли интегрироваться с 1С, МойСкладом или другой учетной системой?
|
||||||
@@ -413,44 +413,36 @@
|
|||||||
- Импорт товаров из Excel/CSV.
|
- Импорт товаров из Excel/CSV.
|
||||||
- Экспорт заказов в Excel.
|
- Экспорт заказов в Excel.
|
||||||
|
|
||||||
## 7. Предлагаемый технический подход
|
## 7. Технический подход
|
||||||
|
|
||||||
Так как нужна быстрая сборка под ключ с логичной админкой, гибкими товарами и возможностью доработки программистом, оптимальные варианты:
|
Проект Рыбсток делаем на чистом PHP без фреймворка.
|
||||||
|
|
||||||
### Вариант A: Laravel + Filament
|
Базовая связка:
|
||||||
|
|
||||||
Подходит, если нужен индивидуальный проект с сильной админкой, гибкими фасовками, промокодами, заказами и прайсами.
|
- PHP 8.2+ или PHP 8.3+;
|
||||||
|
- MySQL или MariaDB;
|
||||||
|
- PDO для работы с базой;
|
||||||
|
- собственная админка на PHP;
|
||||||
|
- HTML, CSS и JavaScript для витрины;
|
||||||
|
- Яндекс.Карты для адресов и расчета доставки;
|
||||||
|
- email-отправка через SMTP;
|
||||||
|
- CSV/XLSX-выгрузка прайс-листа.
|
||||||
|
|
||||||
Плюсы:
|
Чистый PHP выбран потому, что проект должен быстро запускаться на обычном хостинге, легко передаваться программисту и не зависеть от тяжелых фреймворков. При этом код нужно писать структурно: отдельные папки для контроллеров, моделей/репозиториев, сервисов, шаблонов, админки, загрузок, экспортов и настроек.
|
||||||
|
|
||||||
- быстрая мощная админка;
|
Рекомендуемая структура проекта:
|
||||||
- гибкая база данных;
|
|
||||||
- удобно дорабатывать;
|
|
||||||
- легко сделать Excel-выгрузку;
|
|
||||||
- хорошо подходит для кастомной логики доставки и фасовок.
|
|
||||||
|
|
||||||
Минусы:
|
- `public/` - входная точка сайта и публичные assets;
|
||||||
|
- `app/` - основной PHP-код;
|
||||||
- больше разработки, чем на готовой CMS.
|
- `app/Controllers/` - обработчики страниц;
|
||||||
|
- `app/Models/` - модели данных;
|
||||||
### Вариант B: WordPress + WooCommerce + доработки
|
- `app/Repositories/` - запросы к базе;
|
||||||
|
- `app/Services/` - бизнес-логика: доставка, промокоды, корзина, письма, прайс;
|
||||||
Подходит, если важнее очень быстрый запуск на готовой базе.
|
- `views/` - шаблоны сайта;
|
||||||
|
- `admin/` - собственная админка;
|
||||||
Плюсы:
|
- `storage/` - загрузки, экспорты, логи;
|
||||||
|
- `database/` - SQL-схема, миграции или seed-файлы;
|
||||||
- быстро поднять витрину;
|
- `docs/` - рабочие документы проекта.
|
||||||
- много готовых модулей;
|
|
||||||
- понятная админка.
|
|
||||||
|
|
||||||
Минусы:
|
|
||||||
|
|
||||||
- сложная кастомная логика фасовок, доставки и промокодов может потребовать много доработок;
|
|
||||||
- админка может стать менее аккуратной при большом количестве плагинов.
|
|
||||||
|
|
||||||
### Рекомендация
|
|
||||||
|
|
||||||
Для проекта Рыбсток лучше выбрать Laravel + Filament, если цель - надежный сайт с гибкой логикой и понятной админкой, который можно быстро дорабатывать. Если нужно запуститься максимально срочно любой ценой, можно рассмотреть WooCommerce, но сложность фасовок и доставки делает индивидуальную разработку предпочтительнее.
|
|
||||||
|
|
||||||
## 8. Пошаговый план работ
|
## 8. Пошаговый план работ
|
||||||
|
|
||||||
@@ -631,4 +623,9 @@
|
|||||||
|
|
||||||
## 10. Ближайший следующий шаг
|
## 10. Ближайший следующий шаг
|
||||||
|
|
||||||
Перед кодом нужно выбрать платформу и получить исходные данные по каталогу. Рекомендуемый следующий шаг: принять решение по технической связке и подготовить структуру базы данных/моделей для товаров, фасовок, заказов, промокодов и доставки.
|
Перед кодом нужно получить исходные данные по каталогу и подготовить структуру базы данных/моделей для товаров, фасовок, заказов, промокодов и доставки.
|
||||||
|
|
||||||
|
## 11. Статус выполнения
|
||||||
|
|
||||||
|
- Шаг 1 выполнен: выбрана техническая связка на чистом PHP, создан стартовый каркас проекта, подключение к MariaDB через `.env`, базовые папки и файл `ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md`.
|
||||||
|
- Следующий шаг: спроектировать базу данных, модели, связи и структуру собственной админки.
|
||||||
|
|||||||
@@ -0,0 +1,280 @@
|
|||||||
|
# Шаг 1. Техническое решение для сайта Рыбсток
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
Проект Рыбсток делаем на чистом PHP без фреймворка.
|
||||||
|
|
||||||
|
Базовая связка:
|
||||||
|
|
||||||
|
- Backend: чистый PHP 8.2+ или PHP 8.3+
|
||||||
|
- База данных: MySQL или MariaDB
|
||||||
|
- Доступ к базе: PDO
|
||||||
|
- Frontend: HTML, CSS, JavaScript
|
||||||
|
- Админка: собственная админ-панель на PHP
|
||||||
|
- Шаблоны: обычные PHP-шаблоны
|
||||||
|
- Поиск на первом этапе: SQL-поиск с нормализацией русских слов и словарем синонимов
|
||||||
|
- Поиск на расширенном этапе: отдельный поисковый индекс или внешний движок, если понадобится
|
||||||
|
- Excel-выгрузка: CSV на первом этапе, XLSX через PHP-библиотеку или ручную генерацию позже
|
||||||
|
- Карты и адреса: Яндекс.Карты / Яндекс Геокодер / Яндекс Маршрутизация
|
||||||
|
- Email: SMTP-почта домена или внешний SMTP-сервис
|
||||||
|
|
||||||
|
## Почему чистый PHP подходит
|
||||||
|
|
||||||
|
Чистый PHP подходит, если важны:
|
||||||
|
|
||||||
|
- быстрый запуск на обычном хостинге;
|
||||||
|
- понятный код без тяжелого фреймворка;
|
||||||
|
- простая передача проекта другому программисту;
|
||||||
|
- полный контроль над логикой фасовок, корзины, доставки и админки;
|
||||||
|
- минимум зависимостей;
|
||||||
|
- возможность быстро править проект вручную.
|
||||||
|
|
||||||
|
Важно: чистый PHP нужно писать структурно. Даже без фреймворка проект должен иметь понятные слои: маршруты, контроллеры, модели/репозитории, сервисы, шаблоны и админку. Иначе большой каталог, фасовки, промокоды и доставка быстро станут трудными для поддержки.
|
||||||
|
|
||||||
|
## Что сейчас есть в папке проекта
|
||||||
|
|
||||||
|
В папке проекта создан стартовый каркас:
|
||||||
|
|
||||||
|
- `.git`
|
||||||
|
- `.vscode`
|
||||||
|
- `ПЛАН_ДЕЙСТВИЙ_РЫБСТОК.md`
|
||||||
|
- `ШАГ_1_ТЕХНИЧЕСКОЕ_РЕШЕНИЕ.md`
|
||||||
|
- `.env`
|
||||||
|
- `.env.example`
|
||||||
|
- `.gitignore`
|
||||||
|
- `README.md`
|
||||||
|
- `public/index.php`
|
||||||
|
- `public/assets/css/app.css`
|
||||||
|
- `app/bootstrap.php`
|
||||||
|
- `app/helpers.php`
|
||||||
|
- `app/Core/Env.php`
|
||||||
|
- `app/Core/Database.php`
|
||||||
|
- `app/Core/View.php`
|
||||||
|
- `views/layouts/main.php`
|
||||||
|
- `views/pages/home.php`
|
||||||
|
- `admin/index.php`
|
||||||
|
- `database/schema.sql`
|
||||||
|
- `storage/`
|
||||||
|
- `docs/`
|
||||||
|
|
||||||
|
В `.env` внесены данные подключения к базе MariaDB. Сам файл закрыт от git через `.gitignore`.
|
||||||
|
|
||||||
|
## Что нужно установить для разработки
|
||||||
|
|
||||||
|
На рабочем компьютере должны быть доступны:
|
||||||
|
|
||||||
|
- PHP 8.2 или новее, лучше PHP 8.3
|
||||||
|
- MySQL или MariaDB
|
||||||
|
- Веб-сервер: Apache или Nginx
|
||||||
|
- Git
|
||||||
|
|
||||||
|
Желательно:
|
||||||
|
|
||||||
|
- Open Server Panel, Laragon или другой локальный сервер для Windows
|
||||||
|
- phpMyAdmin или Adminer для работы с базой
|
||||||
|
- Composer только по желанию, если позже захотим подключить готовые библиотеки для SMTP, Excel или dotenv
|
||||||
|
|
||||||
|
Для чистого PHP Composer не обязателен на старте.
|
||||||
|
|
||||||
|
## Рекомендуемая структура проекта
|
||||||
|
|
||||||
|
```text
|
||||||
|
loveriba.ru/
|
||||||
|
app/
|
||||||
|
Config/
|
||||||
|
Controllers/
|
||||||
|
Core/
|
||||||
|
Models/
|
||||||
|
Repositories/
|
||||||
|
Services/
|
||||||
|
Validators/
|
||||||
|
admin/
|
||||||
|
controllers/
|
||||||
|
views/
|
||||||
|
public/
|
||||||
|
assets/
|
||||||
|
css/
|
||||||
|
js/
|
||||||
|
images/
|
||||||
|
index.php
|
||||||
|
storage/
|
||||||
|
uploads/
|
||||||
|
exports/
|
||||||
|
logs/
|
||||||
|
views/
|
||||||
|
layouts/
|
||||||
|
pages/
|
||||||
|
product/
|
||||||
|
catalog/
|
||||||
|
cart/
|
||||||
|
checkout/
|
||||||
|
emails/
|
||||||
|
database/
|
||||||
|
migrations/
|
||||||
|
seeders/
|
||||||
|
schema.sql
|
||||||
|
docs/
|
||||||
|
.env.example
|
||||||
|
README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Основные модули
|
||||||
|
|
||||||
|
- `Products` - товары
|
||||||
|
- `ProductVariants` - фасовки и цены
|
||||||
|
- `Categories` - категории и подкатегории
|
||||||
|
- `Cart` - корзина
|
||||||
|
- `Checkout` - оформление заказа
|
||||||
|
- `Orders` - заказы
|
||||||
|
- `Promocodes` - промокоды и ограничения
|
||||||
|
- `Delivery` - расчет доставки
|
||||||
|
- `CustomerAccess` - вход по email-коду и история заказов
|
||||||
|
- `CompareList` - список сравнения до 10 товаров
|
||||||
|
- `Search` - поиск и голосовой ввод
|
||||||
|
- `Reviews` - отзывы и рейтинг
|
||||||
|
- `PriceExport` - прайс-лист
|
||||||
|
- `AdminSettings` - настройки сайта, писем, доставки, счетчиков
|
||||||
|
|
||||||
|
## Базовая структура базы данных
|
||||||
|
|
||||||
|
На втором шаге нужно спроектировать таблицы:
|
||||||
|
|
||||||
|
- `admins` - администраторы
|
||||||
|
- `categories`
|
||||||
|
- `products`
|
||||||
|
- `product_variants`
|
||||||
|
- `orders`
|
||||||
|
- `order_items`
|
||||||
|
- `promocodes`
|
||||||
|
- `promocode_targets`
|
||||||
|
- `customer_login_codes`
|
||||||
|
- `reviews`
|
||||||
|
- `site_settings`
|
||||||
|
- `popular_products`
|
||||||
|
- `promo_blocks`
|
||||||
|
- `delivery_calculations`
|
||||||
|
- `product_images`
|
||||||
|
- `product_search_terms`
|
||||||
|
|
||||||
|
## Важные технические решения
|
||||||
|
|
||||||
|
### Фасовки
|
||||||
|
|
||||||
|
Фасовка должна быть отдельной таблицей, а не просто текстовым полем товара. Это важно, потому что у каждой фасовки своя цена, шаг количества, единица измерения и отображение в корзине.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
- товар: горбуша неразделанная;
|
||||||
|
- фасовка: пласт 10 кг;
|
||||||
|
- базовая единица: кг;
|
||||||
|
- цена за кг: 600 руб.;
|
||||||
|
- цена фасовки: 6000 руб.;
|
||||||
|
- шаг количества: 10 кг.
|
||||||
|
|
||||||
|
### Корзина
|
||||||
|
|
||||||
|
Корзина должна хранить не просто товар, а конкретную фасовку товара.
|
||||||
|
|
||||||
|
Пример позиции:
|
||||||
|
|
||||||
|
- `product_id`
|
||||||
|
- `variant_id`
|
||||||
|
- название товара
|
||||||
|
- название фасовки
|
||||||
|
- количество
|
||||||
|
- шаг количества
|
||||||
|
- цена за единицу
|
||||||
|
- цена за фасовку
|
||||||
|
- итог
|
||||||
|
|
||||||
|
### Заказы
|
||||||
|
|
||||||
|
Заказ должен сохранять снимок данных на момент оформления:
|
||||||
|
|
||||||
|
- название товара;
|
||||||
|
- выбранная фасовка;
|
||||||
|
- цена;
|
||||||
|
- количество;
|
||||||
|
- итог;
|
||||||
|
- расчет доставки;
|
||||||
|
- примененный промокод.
|
||||||
|
|
||||||
|
Это нужно, чтобы изменение цены в каталоге не ломало старые заказы.
|
||||||
|
|
||||||
|
### Доставка
|
||||||
|
|
||||||
|
Расчет доставки делаем отдельным PHP-сервисом `DeliveryCalculator`.
|
||||||
|
|
||||||
|
Он принимает:
|
||||||
|
|
||||||
|
- тип получения;
|
||||||
|
- адрес;
|
||||||
|
- сумму заказа;
|
||||||
|
- расстояние от МКАД;
|
||||||
|
- признак подъема.
|
||||||
|
|
||||||
|
И возвращает:
|
||||||
|
|
||||||
|
- стоимость доставки;
|
||||||
|
- порог бесплатной доставки;
|
||||||
|
- текстовое объяснение для клиента;
|
||||||
|
- технические данные для заказа.
|
||||||
|
|
||||||
|
### Админка
|
||||||
|
|
||||||
|
Админка должна быть собственной, без лишних плагинов.
|
||||||
|
|
||||||
|
Минимальные разделы:
|
||||||
|
|
||||||
|
- товары;
|
||||||
|
- категории;
|
||||||
|
- фасовки;
|
||||||
|
- заказы;
|
||||||
|
- промокоды;
|
||||||
|
- акции;
|
||||||
|
- популярные товары;
|
||||||
|
- отзывы;
|
||||||
|
- настройки доставки;
|
||||||
|
- настройки писем;
|
||||||
|
- прайс-лист;
|
||||||
|
- страницы и тексты сайта.
|
||||||
|
|
||||||
|
### Email вместо SMS
|
||||||
|
|
||||||
|
Все коды входа и письма отправляются только на email. SMS не используются.
|
||||||
|
|
||||||
|
### Прайс-лист
|
||||||
|
|
||||||
|
На первом этапе можно сделать выгрузку CSV, который открывается в Excel. Если нужен именно `.xlsx`, подключим отдельную библиотеку или сделаем генератор XLSX.
|
||||||
|
|
||||||
|
Прайс должен собираться из опубликованных товаров и опубликованных фасовок. Каждая фасовка должна быть отдельной строкой, чтобы покупатель видел все цены.
|
||||||
|
|
||||||
|
## Второй шаг
|
||||||
|
|
||||||
|
Следующий шаг: спроектировать базу данных и модели проекта под чистый PHP.
|
||||||
|
|
||||||
|
Нужно подготовить:
|
||||||
|
|
||||||
|
1. Список таблиц.
|
||||||
|
2. Поля каждой таблицы.
|
||||||
|
3. Связи между таблицами.
|
||||||
|
4. Правила расчета цены фасовки.
|
||||||
|
5. Правила расчета доставки.
|
||||||
|
6. Структуру собственной админки.
|
||||||
|
7. Первичный SQL-файл `database/schema.sql`.
|
||||||
|
|
||||||
|
После второго шага можно будет создавать файловую структуру проекта и начинать код.
|
||||||
|
|
||||||
|
Файловая структура уже создана на шаге 1, поэтому на шаге 2 можно сразу перейти к SQL-схеме, таблицам и первичным PHP-моделям.
|
||||||
|
|
||||||
|
## Что нужно уточнить перед кодом
|
||||||
|
|
||||||
|
Минимально важные вопросы:
|
||||||
|
|
||||||
|
1. Есть ли файл с товарами, ценами и фасовками: Excel, CSV или другая база?
|
||||||
|
2. Есть ли фотографии товаров и склада?
|
||||||
|
3. Какой email использовать для получения заказов?
|
||||||
|
4. Есть ли логотип Рыбсток?
|
||||||
|
5. Где будет размещаться сайт: обычный хостинг, VPS, Timeweb, Beget, Reg.ru, другой вариант?
|
||||||
|
6. Нужно ли сразу делать импорт из Excel или на старте можно заносить товары через админку?
|
||||||
|
7. Какой локальный сервер удобнее использовать: Open Server Panel, Laragon или другой?
|
||||||
Reference in New Issue
Block a user