шаг 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. Вопросы, которые стоит уточнить перед разработкой
|
||||
|
||||
1. На какой платформе быстрее запускать проект: Laravel/Filament, WordPress/WooCommerce с доработками, 1C-Bitrix, Django, Next.js + готовая админка или другая связка?
|
||||
1. Какой локальный сервер и хостинг использовать для проекта на чистом PHP: Open Server Panel, Laragon, обычный хостинг, VPS или другой вариант?
|
||||
2. Есть ли уже текущий сайт, каталог, база товаров, Excel/CSV с товарами и фотографиями?
|
||||
3. Как сейчас хранятся товары: в Excel, 1С, МойСклад, вручную, в другой CMS?
|
||||
4. Нужно ли интегрироваться с 1С, МойСкладом или другой учетной системой?
|
||||
@@ -413,44 +413,36 @@
|
||||
- Импорт товаров из Excel/CSV.
|
||||
- Экспорт заказов в 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-выгрузку;
|
||||
- хорошо подходит для кастомной логики доставки и фасовок.
|
||||
Рекомендуемая структура проекта:
|
||||
|
||||
Минусы:
|
||||
|
||||
- больше разработки, чем на готовой CMS.
|
||||
|
||||
### Вариант B: WordPress + WooCommerce + доработки
|
||||
|
||||
Подходит, если важнее очень быстрый запуск на готовой базе.
|
||||
|
||||
Плюсы:
|
||||
|
||||
- быстро поднять витрину;
|
||||
- много готовых модулей;
|
||||
- понятная админка.
|
||||
|
||||
Минусы:
|
||||
|
||||
- сложная кастомная логика фасовок, доставки и промокодов может потребовать много доработок;
|
||||
- админка может стать менее аккуратной при большом количестве плагинов.
|
||||
|
||||
### Рекомендация
|
||||
|
||||
Для проекта Рыбсток лучше выбрать Laravel + Filament, если цель - надежный сайт с гибкой логикой и понятной админкой, который можно быстро дорабатывать. Если нужно запуститься максимально срочно любой ценой, можно рассмотреть WooCommerce, но сложность фасовок и доставки делает индивидуальную разработку предпочтительнее.
|
||||
- `public/` - входная точка сайта и публичные assets;
|
||||
- `app/` - основной PHP-код;
|
||||
- `app/Controllers/` - обработчики страниц;
|
||||
- `app/Models/` - модели данных;
|
||||
- `app/Repositories/` - запросы к базе;
|
||||
- `app/Services/` - бизнес-логика: доставка, промокоды, корзина, письма, прайс;
|
||||
- `views/` - шаблоны сайта;
|
||||
- `admin/` - собственная админка;
|
||||
- `storage/` - загрузки, экспорты, логи;
|
||||
- `database/` - SQL-схема, миграции или seed-файлы;
|
||||
- `docs/` - рабочие документы проекта.
|
||||
|
||||
## 8. Пошаговый план работ
|
||||
|
||||
@@ -631,4 +623,9 @@
|
||||
|
||||
## 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