Если ты думаешь, что интернет-магазин — это «таблица продуктов и таблица заказов», то добро пожаловать в ад. Здесь у тебя появятся корзины, адреса, статусы заказов, оплаты, возвраты и прочая дрянь. И пока всё это не соберёшь в нормальную схему, проект будет трупом.

Laravel — штука удобная, но интернет-магазин на нём без чёткой структуры базы — как бар без бухла: вроде вывеска есть, а заходить смысла нет. Забей на красивые туториалы «как за 5 минут поднять e-shop», потому что реальная жизнь быстро покажет: без нормальной схемы заказов, корзин и платежей ты утонешь в хаосе.

Ниже — скелет базы, от которого реально можно оттолкнуться. Не «идеал», а рабочая база, где не будет превращения таблиц в свалку.

users

Пользователи — они же клиенты, они же менеджеры, они же админы, если ты слишком ленив и решил пихнуть всех в одну таблицу.

  • id (PK)
  • name
  • email
  • password
  • role (admin, manager, customer)

Подлянка: забудь про ENUM на роль, если хочешь жить. Лучше связать с отдельной таблицей ролей, иначе будешь потом орать, когда добавишь «moderator» или «support».

products

Товары. На бумаге всё красиво: название, описание, цена, картинка. В жизни — головняк с опциями и вариациями.

  • id (PK)
  • name
  • description
  • price
  • image_path
  • category_id (FK)

Подлянка: готовься, что тебе прилетят «цвет», «размер», «склад» и прочее. Значит, придётся городить таблицы опций и стоков. Если оставишь как есть — магазин умрёт на первом же заказе XL-футболки.

categories

Да, категории нужны. Нет, не пытайся засунуть их в JSON в products.

  • id (PK)
  • name

Подлянка: рано или поздно тебе прилетит «подкатегории». Так что сразу думай в сторону parent_id и деревьев.

orders

Тут вся магия.

  • id (PK)
  • user_id (FK)
  • status (pending, processing, shipped, delivered, cancelled)
  • created_at
  • updated_at

Подлянка: забудь про ENUM. Нормальный магазин = 20+ статусов: возврат, отказ, «ждём оплату», «собран», «отправлен», «потерялся».

order_items

Что именно заказали.

  • id (PK)
  • order_id (FK)
  • product_id (FK)
  • quantity
  • price

Подлянка: цена должна храниться тут, а не в products. Иначе при изменении цены у тебя история заказов превратится в трэш.

addresses

Адреса доставки.

  • id (PK)
  • user_id (FK)
  • street, city, state, zip_code, country

Подлянка: забудь про «один адрес». Клиенту надо в офис, домой, бабушке. И в ПВЗ.

payments

Без них твой «магазин» просто список товаров.

  • id (PK)
  • order_id (FK)
  • method (credit_card, paypal, bank_transfer)
  • status (pending, completed, failed)
  • amount

Подлянка: добавишь возвраты — придётся городить таблицу refunds.

reviews

Отчаянные отзывы клиентов.

  • id (PK)
  • user_id (FK)
  • product_id (FK)
  • rating
  • comment

Подлянка: готовься к войне со спамом. Либо модерация, либо тонешь.

carts & cart_items

Корзина — твой личный ад.

  • carts: id, user_id, created_at, updated_at
  • cart_items: id, cart_id, product_id, quantity

Подлянка: корзина должна уметь жить без авторизации. Иначе 90% людей уйдут. Значит, придётся хранить guest_cart через токены или сессии.

Связи

  • Один юзер → много заказов.
  • Один заказ → много order_items.
  • Один продукт → одна категория, но у категории продуктов дохрена.
  • Один заказ → один платёж.
  • Один юзер → много адресов.
  • Один юзер → одна корзина (а если гость — ещё веселее).

На практике

На бумаге всё просто. В коде — реки боли.

  • Миграции: php artisan make:model Product -m и дальше руками описываешь все поля.
  • Контроллеры: php artisan make:controller ProductController --resource — и дальше CRUD.
  • Роуты: Route::apiResource('products', ProductController::class); — да, красиво, пока не полезешь в кастомные фильтры.
  • Реальность: к третьей неделе у тебя уже 50+ миграций, потому что бизнес внезапно решил «а давайте ещё скидки, купоны и программы лояльности».

Итог

Интернет-магазин на Laravel — не «пять таблиц и пара контроллеров». Это десятки взаимосвязанных сущностей, которые будут обрастать костылями, если ты не продумаешь схему с самого начала.

Пофиг, какие контроллеры и модели ты генерируешь artisan’ом. Главное — это структура базы. Если она кривая, проект умрёт задолго до того, как ты прикрутишь корзину.