Initial commit
This commit is contained in:
commit
38b382bdc9
190 files changed
+37216
No files matched your search
@@ -0,0 +1,385 @@
|
||||
-- Схема базы данных для интернет-магазина
|
||||
-- PostgreSQL
|
||||
|
||||
-- Таблица ресурсов
|
||||
CREATE TABLE IF NOT EXISTS resources (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
slug VARCHAR(50) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица действий
|
||||
CREATE TABLE IF NOT EXISTS actions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
slug VARCHAR(50) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица прав доступа
|
||||
CREATE TABLE IF NOT EXISTS permissions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
slug VARCHAR(100) UNIQUE NOT NULL,
|
||||
resource_id INTEGER NOT NULL REFERENCES resources(id) ON DELETE RESTRICT,
|
||||
action_id INTEGER NOT NULL REFERENCES actions(id) ON DELETE RESTRICT,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(resource_id, action_id)
|
||||
);
|
||||
|
||||
-- Таблица ролей
|
||||
CREATE TABLE IF NOT EXISTS roles (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
slug VARCHAR(50) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица связи ролей и прав (многие-ко-многим)
|
||||
CREATE TABLE IF NOT EXISTS role_permissions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
role_id INTEGER NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
|
||||
permission_id INTEGER NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(role_id, permission_id)
|
||||
);
|
||||
|
||||
-- Таблица пользователей
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
email VARCHAR(255) UNIQUE,
|
||||
password_hash VARCHAR(255),
|
||||
first_name VARCHAR(100),
|
||||
last_name VARCHAR(100),
|
||||
phone VARCHAR(20),
|
||||
telegram_id BIGINT UNIQUE,
|
||||
role_id INTEGER REFERENCES roles(id) ON DELETE SET NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица аватаров пользователей
|
||||
CREATE TABLE IF NOT EXISTS user_avatars (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
image_url TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id)
|
||||
);
|
||||
|
||||
-- Таблица категорий товаров
|
||||
CREATE TABLE IF NOT EXISTS categories (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(255) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
parent_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
|
||||
image_url VARCHAR(500),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица товаров
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(255) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
short_description TEXT,
|
||||
sku VARCHAR(100) UNIQUE NOT NULL,
|
||||
price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
|
||||
compare_at_price DECIMAL(10, 2) CHECK (compare_at_price >= 0),
|
||||
cost_price DECIMAL(10, 2) CHECK (cost_price >= 0),
|
||||
discount_percent DECIMAL(5, 2) DEFAULT 0 CHECK (discount_percent >= 0 AND discount_percent <= 100),
|
||||
category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
|
||||
stock_quantity INTEGER DEFAULT 0 CHECK (stock_quantity >= 0),
|
||||
weight DECIMAL(8, 2),
|
||||
dimensions VARCHAR(100),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
is_featured BOOLEAN DEFAULT FALSE,
|
||||
rating DECIMAL(3, 2) DEFAULT 0 CHECK (rating >= 0 AND rating <= 5),
|
||||
review_count INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица изображений товаров
|
||||
CREATE TABLE IF NOT EXISTS product_images (
|
||||
id SERIAL PRIMARY KEY,
|
||||
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE CASCADE,
|
||||
image_url TEXT NOT NULL,
|
||||
alt_text VARCHAR(255),
|
||||
is_primary BOOLEAN DEFAULT FALSE,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица адресов доставки
|
||||
CREATE TABLE IF NOT EXISTS addresses (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
first_name VARCHAR(100) NOT NULL,
|
||||
last_name VARCHAR(100) NOT NULL,
|
||||
phone VARCHAR(20),
|
||||
country VARCHAR(100) NOT NULL,
|
||||
city VARCHAR(100) NOT NULL,
|
||||
street VARCHAR(255) NOT NULL,
|
||||
building VARCHAR(50),
|
||||
apartment VARCHAR(50),
|
||||
postal_code VARCHAR(20),
|
||||
is_default BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица статусов заказов
|
||||
CREATE TABLE IF NOT EXISTS order_statuses (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
slug VARCHAR(50) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
color VARCHAR(20),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица способов оплаты
|
||||
CREATE TABLE IF NOT EXISTS payment_methods (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
slug VARCHAR(50) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица статусов платежей
|
||||
CREATE TABLE IF NOT EXISTS payment_statuses (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
slug VARCHAR(50) UNIQUE NOT NULL,
|
||||
description TEXT,
|
||||
color VARCHAR(20),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица заказов
|
||||
CREATE TABLE IF NOT EXISTS orders (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
order_number VARCHAR(50) UNIQUE NOT NULL,
|
||||
status_id INTEGER NOT NULL REFERENCES order_statuses(id) ON DELETE RESTRICT,
|
||||
subtotal DECIMAL(10, 2) NOT NULL CHECK (subtotal >= 0),
|
||||
tax_amount DECIMAL(10, 2) DEFAULT 0 CHECK (tax_amount >= 0),
|
||||
shipping_cost DECIMAL(10, 2) DEFAULT 0 CHECK (shipping_cost >= 0),
|
||||
discount_amount DECIMAL(10, 2) DEFAULT 0 CHECK (discount_amount >= 0),
|
||||
total_amount DECIMAL(10, 2) NOT NULL CHECK (total_amount >= 0),
|
||||
shipping_address_id INTEGER REFERENCES addresses(id) ON DELETE SET NULL,
|
||||
billing_address_id INTEGER REFERENCES addresses(id) ON DELETE SET NULL,
|
||||
payment_method_id INTEGER REFERENCES payment_methods(id) ON DELETE SET NULL,
|
||||
payment_status_id INTEGER REFERENCES payment_statuses(id) ON DELETE RESTRICT,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица элементов заказа
|
||||
CREATE TABLE IF NOT EXISTS order_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
order_id INTEGER NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
|
||||
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE RESTRICT,
|
||||
product_name VARCHAR(255) NOT NULL,
|
||||
product_sku VARCHAR(100) NOT NULL,
|
||||
quantity INTEGER NOT NULL CHECK (quantity > 0),
|
||||
price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
|
||||
subtotal DECIMAL(10, 2) NOT NULL CHECK (subtotal >= 0),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица корзины
|
||||
CREATE TABLE IF NOT EXISTS cart_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE CASCADE,
|
||||
quantity INTEGER NOT NULL CHECK (quantity > 0),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, product_id)
|
||||
);
|
||||
|
||||
-- Таблица отзывов
|
||||
CREATE TABLE IF NOT EXISTS reviews (
|
||||
id SERIAL PRIMARY KEY,
|
||||
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
|
||||
title VARCHAR(255),
|
||||
comment TEXT,
|
||||
is_approved BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(product_id, user_id)
|
||||
);
|
||||
|
||||
-- Таблица платежей
|
||||
CREATE TABLE IF NOT EXISTS payments (
|
||||
id SERIAL PRIMARY KEY,
|
||||
order_id INTEGER NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
|
||||
payment_method_id INTEGER NOT NULL REFERENCES payment_methods(id) ON DELETE RESTRICT,
|
||||
transaction_id VARCHAR(255) UNIQUE,
|
||||
amount DECIMAL(10, 2) NOT NULL CHECK (amount >= 0),
|
||||
status_id INTEGER NOT NULL REFERENCES payment_statuses(id) ON DELETE RESTRICT,
|
||||
payment_date TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Функция для автоматического обновления updated_at
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Функция для обновления рейтинга товара при добавлении/изменении отзыва
|
||||
CREATE OR REPLACE FUNCTION update_product_rating()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
UPDATE products
|
||||
SET
|
||||
rating = (
|
||||
SELECT COALESCE(AVG(rating), 0)
|
||||
FROM reviews
|
||||
WHERE product_id = COALESCE(NEW.product_id, OLD.product_id)
|
||||
AND is_approved = TRUE
|
||||
),
|
||||
review_count = (
|
||||
SELECT COUNT(*)
|
||||
FROM reviews
|
||||
WHERE product_id = COALESCE(NEW.product_id, OLD.product_id)
|
||||
AND is_approved = TRUE
|
||||
)
|
||||
WHERE id = COALESCE(NEW.product_id, OLD.product_id);
|
||||
|
||||
RETURN COALESCE(NEW, OLD);
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Функция для генерации номера заказа
|
||||
CREATE OR REPLACE FUNCTION generate_order_number()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF NEW.order_number IS NULL OR NEW.order_number = '' THEN
|
||||
NEW.order_number := 'ORD-' || TO_CHAR(NOW(), 'YYYYMMDD') || '-' || LPAD(NEW.id::TEXT, 6, '0');
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Функция для получения ID статуса заказа по slug
|
||||
CREATE OR REPLACE FUNCTION get_order_status_id(status_slug VARCHAR)
|
||||
RETURNS INTEGER AS $$
|
||||
DECLARE
|
||||
status_id INTEGER;
|
||||
BEGIN
|
||||
SELECT id INTO status_id
|
||||
FROM order_statuses
|
||||
WHERE slug = status_slug AND is_active = TRUE
|
||||
LIMIT 1;
|
||||
|
||||
RETURN status_id;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Функция для получения ID статуса платежа по slug
|
||||
CREATE OR REPLACE FUNCTION get_payment_status_id(status_slug VARCHAR)
|
||||
RETURNS INTEGER AS $$
|
||||
DECLARE
|
||||
status_id INTEGER;
|
||||
BEGIN
|
||||
SELECT id INTO status_id
|
||||
FROM payment_statuses
|
||||
WHERE slug = status_slug AND is_active = TRUE
|
||||
LIMIT 1;
|
||||
|
||||
RETURN status_id;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Функция для получения ID способа оплаты по slug
|
||||
CREATE OR REPLACE FUNCTION get_payment_method_id(method_slug VARCHAR)
|
||||
RETURNS INTEGER AS $$
|
||||
DECLARE
|
||||
method_id INTEGER;
|
||||
BEGIN
|
||||
SELECT id INTO method_id
|
||||
FROM payment_methods
|
||||
WHERE slug = method_slug AND is_active = TRUE
|
||||
LIMIT 1;
|
||||
|
||||
RETURN method_id;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Комментарии к таблицам
|
||||
COMMENT ON TABLE resources IS 'Ресурсы системы (products, orders, categories и т.д.)';
|
||||
COMMENT ON TABLE actions IS 'Действия над ресурсами (view, create, edit, delete и т.д.)';
|
||||
COMMENT ON TABLE permissions IS 'Права доступа к ресурсам системы';
|
||||
COMMENT ON TABLE roles IS 'Роли пользователей системы';
|
||||
COMMENT ON TABLE role_permissions IS 'Связь ролей и прав доступа (многие-ко-многим)';
|
||||
COMMENT ON TABLE users IS 'Пользователи системы (покупатели и администраторы)';
|
||||
COMMENT ON TABLE categories IS 'Категории товаров с поддержкой иерархии';
|
||||
COMMENT ON TABLE order_statuses IS 'Статусы заказов';
|
||||
COMMENT ON TABLE payment_methods IS 'Способы оплаты';
|
||||
COMMENT ON TABLE payment_statuses IS 'Статусы платежей';
|
||||
COMMENT ON TABLE products IS 'Товары магазина';
|
||||
COMMENT ON TABLE product_images IS 'Изображения товаров';
|
||||
COMMENT ON TABLE addresses IS 'Адреса доставки пользователей';
|
||||
COMMENT ON TABLE orders IS 'Заказы покупателей';
|
||||
COMMENT ON TABLE order_items IS 'Элементы заказа (товары в заказе)';
|
||||
COMMENT ON TABLE cart_items IS 'Корзина покупок';
|
||||
COMMENT ON TABLE reviews IS 'Отзывы на товары';
|
||||
COMMENT ON TABLE payments IS 'Платежи по заказам';
|
||||
|
||||
-- Таблица настроек системы
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
key VARCHAR(100) UNIQUE NOT NULL,
|
||||
value TEXT,
|
||||
description TEXT,
|
||||
type VARCHAR(50) DEFAULT 'string' CHECK (type IN ('string', 'boolean', 'number', 'json')),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
COMMENT ON TABLE settings IS 'Настройки системы';
|
||||
COMMENT ON COLUMN settings.key IS 'Уникальный ключ настройки';
|
||||
COMMENT ON COLUMN settings.value IS 'Значение настройки (текст)';
|
||||
COMMENT ON COLUMN settings.type IS 'Тип значения: string, boolean, number, json';
|
||||
|
||||
@@ -0,0 +1,678 @@
|
||||
-- Начальные данные для базы данных интернет-магазина
|
||||
-- PostgreSQL
|
||||
--
|
||||
-- ВАЖНО: Этот файл должен выполняться ПОСЛЕ schema.sql
|
||||
-- Сначала создайте структуру базы данных (schema.sql), затем заполните данными (seed_data.sql)
|
||||
-- Этот файл можно безопасно выполнять многократно - все INSERT используют ON CONFLICT
|
||||
|
||||
-- ============================================================================
|
||||
-- 1. РЕСУРСЫ (RESOURCES)
|
||||
-- ============================================================================
|
||||
|
||||
-- Основные ресурсы системы
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Товары', 'products', 'Управление товарами магазина')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Заказы', 'orders', 'Управление заказами покупателей')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Категории', 'categories', 'Управление категориями товаров')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Отзывы', 'reviews', 'Управление отзывами на товары')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Корзина', 'cart', 'Управление корзиной покупок')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Пользователи', 'users', 'Управление пользователями системы')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Все ресурсы', '*', 'Все ресурсы системы (для администратора)')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Дополнительные ресурсы
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Платежи', 'payments', 'Управление платежами по заказам')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Адреса', 'addresses', 'Управление адресами доставки')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Роли', 'roles', 'Управление ролями пользователей')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO resources (name, slug, description) VALUES
|
||||
('Права доступа', 'permissions', 'Управление правами доступа')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- ============================================================================
|
||||
-- 2. ДЕЙСТВИЯ (ACTIONS)
|
||||
-- ============================================================================
|
||||
|
||||
-- CRUD операции
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Просмотр', 'view', 'Просмотр списка и деталей записей (Read)')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Создание', 'create', 'Создание новых записей (Create)')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Редактирование', 'edit', 'Редактирование существующих записей (Update)')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Удаление', 'delete', 'Удаление записей (Delete)')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Дополнительные действия
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Модерация', 'moderate', 'Одобрение и отклонение записей')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Управление', 'manage', 'Полное управление ресурсом')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Просмотр своих', 'view_own', 'Просмотр только своих записей')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO actions (name, slug, description) VALUES
|
||||
('Все действия', '*', 'Все действия (для администратора)')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- ============================================================================
|
||||
-- 3. ПРАВА ДОСТУПА (PERMISSIONS)
|
||||
-- ============================================================================
|
||||
|
||||
-- Products
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT
|
||||
'Просмотр товаров',
|
||||
'products.view',
|
||||
r.id,
|
||||
a.id,
|
||||
'Просмотр списка и деталей товаров'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'products' AND a.slug = 'view'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Создание товаров', 'products.create', r.id, a.id, 'Создание новых товаров'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'products' AND a.slug = 'create'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Редактирование товаров', 'products.edit', r.id, a.id, 'Редактирование существующих товаров'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'products' AND a.slug = 'edit'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Удаление товаров', 'products.delete', r.id, a.id, 'Удаление товаров'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'products' AND a.slug = 'delete'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Orders
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Просмотр заказов', 'orders.view', r.id, a.id, 'Просмотр списка и деталей заказов'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'orders' AND a.slug = 'view'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Создание заказов', 'orders.create', r.id, a.id, 'Создание новых заказов'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'orders' AND a.slug = 'create'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Редактирование заказов', 'orders.edit', r.id, a.id, 'Редактирование заказов'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'orders' AND a.slug = 'edit'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Просмотр своих заказов', 'orders.view_own', r.id, a.id, 'Просмотр только своих заказов'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'orders' AND a.slug = 'view_own'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Categories
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Просмотр категорий', 'categories.view', r.id, a.id, 'Просмотр категорий'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'categories' AND a.slug = 'view'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Создание категорий', 'categories.create', r.id, a.id, 'Создание новых категорий'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'categories' AND a.slug = 'create'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Редактирование категорий', 'categories.edit', r.id, a.id, 'Редактирование категорий'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'categories' AND a.slug = 'edit'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Удаление категорий', 'categories.delete', r.id, a.id, 'Удаление категорий'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'categories' AND a.slug = 'delete'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Reviews
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Просмотр отзывов', 'reviews.view', r.id, a.id, 'Просмотр отзывов'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'reviews' AND a.slug = 'view'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Создание отзывов', 'reviews.create', r.id, a.id, 'Создание отзывов на товары'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'reviews' AND a.slug = 'create'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Модерация отзывов', 'reviews.moderate', r.id, a.id, 'Одобрение и отклонение отзывов'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'reviews' AND a.slug = 'moderate'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Удаление отзывов', 'reviews.delete', r.id, a.id, 'Удаление отзывов'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'reviews' AND a.slug = 'delete'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Cart
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Управление корзиной', 'cart.manage', r.id, a.id, 'Добавление и удаление товаров из корзины'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'cart' AND a.slug = 'manage'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Users
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Просмотр пользователей', 'users.view', r.id, a.id, 'Просмотр списка пользователей'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'users' AND a.slug = 'view'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Редактирование пользователей', 'users.edit', r.id, a.id, 'Редактирование данных пользователей'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'users' AND a.slug = 'edit'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Удаление пользователей', 'users.delete', r.id, a.id, 'Удаление пользователей'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = 'users' AND a.slug = 'delete'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- Admin (полные права)
|
||||
INSERT INTO permissions (name, slug, resource_id, action_id, description)
|
||||
SELECT 'Полные права', 'admin.all', r.id, a.id, 'Полные права администратора на все ресурсы'
|
||||
FROM resources r, actions a
|
||||
WHERE r.slug = '*' AND a.slug = '*'
|
||||
ON CONFLICT (resource_id, action_id) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
slug = EXCLUDED.slug,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- ============================================================================
|
||||
-- 4. РОЛИ (ROLES)
|
||||
-- ============================================================================
|
||||
|
||||
INSERT INTO roles (name, slug, description) VALUES
|
||||
('Администратор', 'admin', 'Администратор системы с полными правами доступа ко всем ресурсам')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO roles (name, slug, description) VALUES
|
||||
('Владелец', 'owner', 'Владелец магазина с расширенными правами управления')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO roles (name, slug, description) VALUES
|
||||
('Клиент', 'customer', 'Обычный покупатель магазина с базовыми правами')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO roles (name, slug, description) VALUES
|
||||
('Сотрудник', 'employee', 'Сотрудник магазина с правами на управление товарами и заказами')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO roles (name, slug, description) VALUES
|
||||
('Менеджер', 'manager', 'Менеджер магазина')
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- ============================================================================
|
||||
-- 5. СВЯЗЬ РОЛЕЙ И ПРАВ (ROLE_PERMISSIONS)
|
||||
-- ============================================================================
|
||||
|
||||
-- Администратор (admin) - все права
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'admin'
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Владелец (owner) - расширенные права (почти как администратор, но без управления ролями и правами)
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'owner'
|
||||
AND p.slug NOT LIKE 'roles.%'
|
||||
AND p.slug NOT LIKE 'permissions.%'
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Сотрудник (employee) - управление товарами и заказами
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'employee'
|
||||
AND p.slug IN (
|
||||
'products.view', 'products.create', 'products.edit', 'products.delete',
|
||||
'orders.view', 'orders.create', 'orders.edit',
|
||||
'categories.view', 'categories.create', 'categories.edit', 'categories.delete',
|
||||
'reviews.view', 'reviews.moderate', 'reviews.delete',
|
||||
'users.view',
|
||||
'cart.manage'
|
||||
)
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Менеджер (manager) - аналогично сотруднику
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'manager'
|
||||
AND p.slug IN (
|
||||
'products.view', 'products.create', 'products.edit', 'products.delete',
|
||||
'orders.view', 'orders.edit',
|
||||
'categories.view', 'categories.create', 'categories.edit', 'categories.delete',
|
||||
'reviews.view', 'reviews.moderate', 'reviews.delete',
|
||||
'users.view',
|
||||
'cart.manage'
|
||||
)
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Клиент (customer) - базовые права
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'customer'
|
||||
AND p.slug IN (
|
||||
'products.view',
|
||||
'orders.create',
|
||||
'orders.view_own',
|
||||
'cart.manage',
|
||||
'reviews.create',
|
||||
'categories.view'
|
||||
)
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- ============================================================================
|
||||
-- 6. СТАТУСЫ ЗАКАЗОВ (ORDER_STATUSES)
|
||||
-- ============================================================================
|
||||
|
||||
INSERT INTO order_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Ожидает обработки', 'pending', 'Заказ создан и ожидает обработки', '#FFA500', 1)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO order_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('В обработке', 'processing', 'Заказ обрабатывается', '#4169E1', 2)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO order_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Отправлен', 'shipped', 'Заказ отправлен покупателю', '#32CD32', 3)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO order_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Доставлен', 'delivered', 'Заказ доставлен покупателю', '#228B22', 4)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO order_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Отменен', 'cancelled', 'Заказ отменен', '#DC143C', 5)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO order_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Возвращен', 'refunded', 'Заказ возвращен, средства возвращены', '#8B0000', 6)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- ============================================================================
|
||||
-- 7. СПОСОБЫ ОПЛАТЫ (PAYMENT_METHODS)
|
||||
-- ============================================================================
|
||||
|
||||
INSERT INTO payment_methods (name, slug, description, sort_order) VALUES
|
||||
('Банковская карта', 'card', 'Оплата банковской картой онлайн', 1)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_methods (name, slug, description, sort_order) VALUES
|
||||
('Электронный кошелек', 'e-wallet', 'Оплата через электронный кошелек (Яндекс.Деньги, Qiwi и т.д.)', 2)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_methods (name, slug, description, sort_order) VALUES
|
||||
('Наличные при получении', 'cash_on_delivery', 'Оплата наличными при получении заказа', 3)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_methods (name, slug, description, sort_order) VALUES
|
||||
('Банковский перевод', 'bank_transfer', 'Оплата через банковский перевод', 4)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_methods (name, slug, description, sort_order) VALUES
|
||||
('Криптовалюта', 'crypto', 'Оплата криптовалютой', 5)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- ============================================================================
|
||||
-- 8. СТАТУСЫ ПЛАТЕЖЕЙ (PAYMENT_STATUSES)
|
||||
-- ============================================================================
|
||||
|
||||
INSERT INTO payment_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Ожидает оплаты', 'pending', 'Платеж ожидает оплаты', '#FFA500', 1)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Оплачен', 'paid', 'Платеж успешно оплачен', '#32CD32', 2)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Завершен', 'completed', 'Платеж завершен', '#228B22', 3)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Ошибка оплаты', 'failed', 'Ошибка при обработке платежа', '#DC143C', 4)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO payment_statuses (name, slug, description, color, sort_order) VALUES
|
||||
('Возвращен', 'refunded', 'Платеж возвращен покупателю', '#8B0000', 5)
|
||||
ON CONFLICT (slug) DO UPDATE SET
|
||||
name = EXCLUDED.name,
|
||||
description = EXCLUDED.description,
|
||||
color = EXCLUDED.color,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- ============================================================================
|
||||
-- 9. ОБНОВЛЕНИЕ ПРАВ ДЛЯ СУЩЕСТВУЮЩИХ РОЛЕЙ
|
||||
-- ============================================================================
|
||||
-- Этот раздел гарантирует, что сотрудники и менеджеры имеют все необходимые права
|
||||
-- Можно безопасно выполнять многократно благодаря ON CONFLICT
|
||||
|
||||
-- Убедиться, что сотрудники (employee) имеют право на управление корзиной
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'employee'
|
||||
AND p.slug = 'cart.manage'
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Убедиться, что менеджеры (manager) имеют право на управление корзиной
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'manager'
|
||||
AND p.slug = 'cart.manage'
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Убедиться, что сотрудники (employee) имеют право на редактирование заказов
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'employee'
|
||||
AND p.slug = 'orders.edit'
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Убедиться, что менеджеры (manager) имеют право на редактирование заказов
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug = 'manager'
|
||||
AND p.slug = 'orders.edit'
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
-- Убедиться, что все роли имеют право на создание заказов
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM roles r, permissions p
|
||||
WHERE r.slug IN ('customer', 'employee', 'manager', 'owner', 'admin')
|
||||
AND p.slug = 'orders.create'
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
@@ -0,0 +1,96 @@
|
||||
-- Триггеры для базы данных интернет-магазина
|
||||
-- PostgreSQL
|
||||
--
|
||||
-- ВАЖНО: Этот файл должен выполняться ПОСЛЕ schema.sql
|
||||
-- Сначала создайте структуру базы данных (schema.sql), затем создайте триггеры (triggers.sql)
|
||||
-- Функции должны быть созданы в schema.sql перед выполнением этого файла
|
||||
|
||||
-- Триггеры для автоматического обновления updated_at
|
||||
DROP TRIGGER IF EXISTS update_resources_updated_at ON resources;
|
||||
CREATE TRIGGER update_resources_updated_at BEFORE UPDATE ON resources
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_actions_updated_at ON actions;
|
||||
CREATE TRIGGER update_actions_updated_at BEFORE UPDATE ON actions
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_permissions_updated_at ON permissions;
|
||||
CREATE TRIGGER update_permissions_updated_at BEFORE UPDATE ON permissions
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_roles_updated_at ON roles;
|
||||
CREATE TRIGGER update_roles_updated_at BEFORE UPDATE ON roles
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_users_updated_at ON users;
|
||||
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_categories_updated_at ON categories;
|
||||
CREATE TRIGGER update_categories_updated_at BEFORE UPDATE ON categories
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_order_statuses_updated_at ON order_statuses;
|
||||
CREATE TRIGGER update_order_statuses_updated_at BEFORE UPDATE ON order_statuses
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_payment_methods_updated_at ON payment_methods;
|
||||
CREATE TRIGGER update_payment_methods_updated_at BEFORE UPDATE ON payment_methods
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_payment_statuses_updated_at ON payment_statuses;
|
||||
CREATE TRIGGER update_payment_statuses_updated_at BEFORE UPDATE ON payment_statuses
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_products_updated_at ON products;
|
||||
CREATE TRIGGER update_products_updated_at BEFORE UPDATE ON products
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_addresses_updated_at ON addresses;
|
||||
CREATE TRIGGER update_addresses_updated_at BEFORE UPDATE ON addresses
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_orders_updated_at ON orders;
|
||||
CREATE TRIGGER update_orders_updated_at BEFORE UPDATE ON orders
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_cart_items_updated_at ON cart_items;
|
||||
CREATE TRIGGER update_cart_items_updated_at BEFORE UPDATE ON cart_items
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_reviews_updated_at ON reviews;
|
||||
CREATE TRIGGER update_reviews_updated_at BEFORE UPDATE ON reviews
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_payments_updated_at ON payments;
|
||||
CREATE TRIGGER update_payments_updated_at BEFORE UPDATE ON payments
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Триггеры для обновления рейтинга товара
|
||||
DROP TRIGGER IF EXISTS update_product_rating_on_review_insert ON reviews;
|
||||
CREATE TRIGGER update_product_rating_on_review_insert
|
||||
AFTER INSERT ON reviews
|
||||
FOR EACH ROW
|
||||
WHEN (NEW.is_approved = TRUE)
|
||||
EXECUTE FUNCTION update_product_rating();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_product_rating_on_review_update ON reviews;
|
||||
CREATE TRIGGER update_product_rating_on_review_update
|
||||
AFTER UPDATE ON reviews
|
||||
FOR EACH ROW
|
||||
WHEN (NEW.is_approved != OLD.is_approved OR NEW.rating != OLD.rating)
|
||||
EXECUTE FUNCTION update_product_rating();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_product_rating_on_review_delete ON reviews;
|
||||
CREATE TRIGGER update_product_rating_on_review_delete
|
||||
AFTER DELETE ON reviews
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_product_rating();
|
||||
|
||||
-- Триггер для автоматической генерации номера заказа
|
||||
DROP TRIGGER IF EXISTS generate_order_number_trigger ON orders;
|
||||
CREATE TRIGGER generate_order_number_trigger
|
||||
BEFORE INSERT ON orders
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION generate_order_number();
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
-- Индексы для оптимизации запросов
|
||||
-- PostgreSQL
|
||||
--
|
||||
-- ВАЖНО: Этот файл должен выполняться ПОСЛЕ schema.sql
|
||||
-- Сначала создайте структуру базы данных (schema.sql), затем создайте индексы (indexes.sql)
|
||||
|
||||
-- Индексы для таблицы resources
|
||||
CREATE INDEX IF NOT EXISTS idx_resources_slug ON resources(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_resources_is_active ON resources(is_active);
|
||||
|
||||
-- Индексы для таблицы actions
|
||||
CREATE INDEX IF NOT EXISTS idx_actions_slug ON actions(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_actions_is_active ON actions(is_active);
|
||||
|
||||
-- Индексы для таблицы permissions
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_slug ON permissions(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_resource_id ON permissions(resource_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_action_id ON permissions(action_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_resource_action ON permissions(resource_id, action_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_permissions_is_active ON permissions(is_active);
|
||||
|
||||
-- Индексы для таблицы roles
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_slug ON roles(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_is_active ON roles(is_active);
|
||||
|
||||
-- Индексы для таблицы role_permissions
|
||||
CREATE INDEX IF NOT EXISTS idx_role_permissions_role_id ON role_permissions(role_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_role_permissions_permission_id ON role_permissions(permission_id);
|
||||
|
||||
-- Индексы для таблицы users
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_telegram_id ON users(telegram_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_role_id ON users(role_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_is_active ON users(is_active);
|
||||
|
||||
-- Индексы для таблицы categories
|
||||
CREATE INDEX IF NOT EXISTS idx_categories_parent_id ON categories(parent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_categories_slug ON categories(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_categories_is_active ON categories(is_active);
|
||||
|
||||
-- Индексы для таблицы products
|
||||
CREATE INDEX IF NOT EXISTS idx_products_category_id ON products(category_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_products_slug ON products(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_products_sku ON products(sku);
|
||||
CREATE INDEX IF NOT EXISTS idx_products_is_active ON products(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_products_is_featured ON products(is_featured);
|
||||
CREATE INDEX IF NOT EXISTS idx_products_price ON products(price);
|
||||
CREATE INDEX IF NOT EXISTS idx_products_discount ON products(discount_percent) WHERE discount_percent > 0;
|
||||
|
||||
-- Индексы для таблицы product_images
|
||||
CREATE INDEX IF NOT EXISTS idx_product_images_product_id ON product_images(product_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_product_images_is_primary ON product_images(is_primary);
|
||||
|
||||
-- Индексы для таблицы addresses
|
||||
CREATE INDEX IF NOT EXISTS idx_addresses_user_id ON addresses(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_addresses_is_default ON addresses(is_default);
|
||||
|
||||
-- Индексы для таблицы order_statuses
|
||||
CREATE INDEX IF NOT EXISTS idx_order_statuses_slug ON order_statuses(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_order_statuses_is_active ON order_statuses(is_active);
|
||||
|
||||
-- Индексы для таблицы payment_methods
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_methods_slug ON payment_methods(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_methods_is_active ON payment_methods(is_active);
|
||||
|
||||
-- Индексы для таблицы payment_statuses
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_statuses_slug ON payment_statuses(slug);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_statuses_is_active ON payment_statuses(is_active);
|
||||
|
||||
-- Индексы для таблицы orders
|
||||
CREATE INDEX IF NOT EXISTS idx_orders_user_id ON orders(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_orders_order_number ON orders(order_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_orders_status_id ON orders(status_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_orders_payment_method_id ON orders(payment_method_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_orders_payment_status_id ON orders(payment_status_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_orders_created_at ON orders(created_at);
|
||||
|
||||
-- Индексы для таблицы order_items
|
||||
CREATE INDEX IF NOT EXISTS idx_order_items_order_id ON order_items(order_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_order_items_product_id ON order_items(product_id);
|
||||
|
||||
-- Индексы для таблицы cart_items
|
||||
CREATE INDEX IF NOT EXISTS idx_cart_items_user_id ON cart_items(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cart_items_product_id ON cart_items(product_id);
|
||||
|
||||
-- Индексы для таблицы reviews
|
||||
CREATE INDEX IF NOT EXISTS idx_reviews_product_id ON reviews(product_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_reviews_user_id ON reviews(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_reviews_is_approved ON reviews(is_approved);
|
||||
CREATE INDEX IF NOT EXISTS idx_reviews_rating ON reviews(rating);
|
||||
|
||||
-- Индексы для таблицы payments
|
||||
CREATE INDEX IF NOT EXISTS idx_payments_order_id ON payments(order_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_payments_payment_method_id ON payments(payment_method_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_payments_status_id ON payments(status_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_payments_transaction_id ON payments(transaction_id);
|
||||
|
||||
-- Индексы для таблицы settings
|
||||
CREATE INDEX IF NOT EXISTS idx_settings_key ON settings(key);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- Инициализация настроек системы
|
||||
-- Выполнить после создания основной схемы
|
||||
|
||||
-- Настройка для включения/отключения рейтингов
|
||||
INSERT INTO settings (key, value, description, type)
|
||||
VALUES ('ratings_enabled', 'true', 'Включить/выключить функционал рейтингов и отзывов', 'boolean')
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
+757
@@ -0,0 +1,757 @@
|
||||
# Документация базы данных интернет-магазина
|
||||
|
||||
## Описание проекта
|
||||
|
||||
База данных для интернет-магазина на PostgreSQL, включающая систему управления пользователями с ролями и правами доступа, каталог товаров, систему заказов, корзину покупок, отзывы и платежи.
|
||||
|
||||
## Структура файлов
|
||||
|
||||
Проект состоит из четырех SQL-файлов, которые должны выполняться в следующем порядке:
|
||||
|
||||
1. **schema.sql** - Создание структуры базы данных (таблицы, функции)
|
||||
2. **indexes.sql** - Создание индексов для оптимизации запросов
|
||||
3. **triggers.sql** - Создание триггеров для автоматизации процессов
|
||||
4. **seed_data.sql** - Заполнение начальными данными
|
||||
|
||||
## Порядок установки
|
||||
|
||||
```sql
|
||||
-- 1. Создание структуры
|
||||
\i schema.sql
|
||||
|
||||
-- 2. Создание индексов
|
||||
\i indexes.sql
|
||||
|
||||
-- 3. Создание триггеров
|
||||
\i triggers.sql
|
||||
|
||||
-- 4. Заполнение данными
|
||||
\i seed_data.sql
|
||||
```
|
||||
|
||||
## Архитектура базы данных
|
||||
|
||||
### Система авторизации и прав доступа
|
||||
|
||||
База данных использует гибкую систему ролей и прав доступа (RBAC - Role-Based Access Control):
|
||||
|
||||
- **Ресурсы (resources)** - объекты системы (товары, заказы, категории и т.д.)
|
||||
- **Действия (actions)** - операции над ресурсами (просмотр, создание, редактирование, удаление)
|
||||
- **Права доступа (permissions)** - комбинация ресурса и действия
|
||||
- **Роли (roles)** - наборы прав доступа
|
||||
- **Пользователи (users)** - привязаны к ролям
|
||||
|
||||
### Основные модули
|
||||
|
||||
1. **Управление товарами** - категории, товары, изображения
|
||||
2. **Управление заказами** - заказы, элементы заказов, статусы
|
||||
3. **Корзина покупок** - временное хранение товаров перед оформлением заказа
|
||||
4. **Отзывы и рейтинги** - система отзывов с автоматическим расчетом рейтинга
|
||||
5. **Платежи** - управление платежами по заказам
|
||||
6. **Адреса доставки** - адреса пользователей
|
||||
|
||||
---
|
||||
|
||||
## Описание таблиц
|
||||
|
||||
### 1. Система авторизации
|
||||
|
||||
#### `resources` - Ресурсы системы
|
||||
Хранит список ресурсов (объектов), к которым можно предоставить доступ.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(100) | Название ресурса |
|
||||
| slug | VARCHAR(50) | Уникальный идентификатор (URL-friendly) |
|
||||
| description | TEXT | Описание ресурса |
|
||||
| is_active | BOOLEAN | Активен ли ресурс |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Примеры ресурсов:** products, orders, categories, reviews, cart, users
|
||||
|
||||
#### `actions` - Действия над ресурсами
|
||||
Хранит список действий, которые можно выполнять над ресурсами.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(100) | Название действия |
|
||||
| slug | VARCHAR(50) | Уникальный идентификатор |
|
||||
| description | TEXT | Описание действия |
|
||||
| is_active | BOOLEAN | Активно ли действие |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Примеры действий:** view, create, edit, delete, moderate, manage
|
||||
|
||||
#### `permissions` - Права доступа
|
||||
Комбинация ресурса и действия. Определяет конкретное право доступа.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(100) | Название права |
|
||||
| slug | VARCHAR(100) | Уникальный идентификатор (формат: resource.action) |
|
||||
| resource_id | INTEGER | Ссылка на ресурс |
|
||||
| action_id | INTEGER | Ссылка на действие |
|
||||
| description | TEXT | Описание права |
|
||||
| is_active | BOOLEAN | Активно ли право |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Ограничения:** UNIQUE(resource_id, action_id) - одна комбинация ресурса и действия
|
||||
|
||||
#### `roles` - Роли пользователей
|
||||
Роли, которые могут быть назначены пользователям.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(100) | Название роли |
|
||||
| slug | VARCHAR(50) | Уникальный идентификатор |
|
||||
| description | TEXT | Описание роли |
|
||||
| is_active | BOOLEAN | Активна ли роль |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Предустановленные роли:**
|
||||
- `admin` - Администратор (полные права)
|
||||
- `owner` - Владелец магазина
|
||||
- `employee` - Сотрудник
|
||||
- `manager` - Менеджер
|
||||
- `customer` - Клиент (покупатель)
|
||||
|
||||
#### `role_permissions` - Связь ролей и прав
|
||||
Связывает роли с правами доступа (многие-ко-многим).
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| role_id | INTEGER | Ссылка на роль |
|
||||
| permission_id | INTEGER | Ссылка на право доступа |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
|
||||
**Ограничения:** UNIQUE(role_id, permission_id)
|
||||
|
||||
#### `users` - Пользователи системы
|
||||
Пользователи системы (покупатели и администраторы).
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| email | VARCHAR(255) | Email (уникальный) |
|
||||
| password_hash | VARCHAR(255) | Хеш пароля |
|
||||
| first_name | VARCHAR(100) | Имя |
|
||||
| last_name | VARCHAR(100) | Фамилия |
|
||||
| phone | VARCHAR(20) | Телефон |
|
||||
| telegram_id | BIGINT | ID в Telegram (уникальный) |
|
||||
| role_id | INTEGER | Ссылка на роль |
|
||||
| is_active | BOOLEAN | Активен ли пользователь |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Особенности:**
|
||||
- Поддержка авторизации через email или Telegram
|
||||
- Связь с ролью через `role_id`
|
||||
|
||||
---
|
||||
|
||||
### 2. Каталог товаров
|
||||
|
||||
#### `categories` - Категории товаров
|
||||
Иерархическая структура категорий товаров.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(255) | Название категории |
|
||||
| slug | VARCHAR(255) | Уникальный идентификатор (URL-friendly) |
|
||||
| description | TEXT | Описание категории |
|
||||
| parent_id | INTEGER | Ссылка на родительскую категорию (для иерархии) |
|
||||
| image_url | VARCHAR(500) | URL изображения категории |
|
||||
| is_active | BOOLEAN | Активна ли категория |
|
||||
| sort_order | INTEGER | Порядок сортировки |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Особенности:**
|
||||
- Поддержка вложенных категорий через `parent_id`
|
||||
- Возможность сортировки через `sort_order`
|
||||
|
||||
#### `products` - Товары
|
||||
Основная информация о товарах магазина.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(255) | Название товара |
|
||||
| slug | VARCHAR(255) | Уникальный идентификатор (URL-friendly) |
|
||||
| description | TEXT | Полное описание |
|
||||
| short_description | TEXT | Краткое описание |
|
||||
| sku | VARCHAR(100) | Артикул товара (уникальный) |
|
||||
| price | DECIMAL(10, 2) | Цена продажи |
|
||||
| compare_at_price | DECIMAL(10, 2) | Старая цена (для отображения скидки) |
|
||||
| cost_price | DECIMAL(10, 2) | Себестоимость |
|
||||
| category_id | INTEGER | Ссылка на категорию |
|
||||
| stock_quantity | INTEGER | Количество на складе |
|
||||
| weight | DECIMAL(8, 2) | Вес товара |
|
||||
| dimensions | VARCHAR(100) | Размеры товара |
|
||||
| is_active | BOOLEAN | Активен ли товар |
|
||||
| is_featured | BOOLEAN | Рекомендуемый товар |
|
||||
| rating | DECIMAL(3, 2) | Средний рейтинг (0-5) |
|
||||
| review_count | INTEGER | Количество одобренных отзывов |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Ограничения:**
|
||||
- `price >= 0`
|
||||
- `compare_at_price >= 0`
|
||||
- `cost_price >= 0`
|
||||
- `stock_quantity >= 0`
|
||||
- `rating >= 0 AND rating <= 5`
|
||||
|
||||
**Особенности:**
|
||||
- Рейтинг и количество отзывов обновляются автоматически через триггеры
|
||||
|
||||
#### `product_images` - Изображения товаров
|
||||
Изображения товаров с поддержкой множественных изображений.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| product_id | INTEGER | Ссылка на товар |
|
||||
| image_url | VARCHAR(500) | URL изображения |
|
||||
| alt_text | VARCHAR(255) | Альтернативный текст для изображения |
|
||||
| is_primary | BOOLEAN | Основное изображение |
|
||||
| sort_order | INTEGER | Порядок сортировки |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
|
||||
**Особенности:**
|
||||
- Поддержка нескольких изображений на товар
|
||||
- Одно изображение может быть помечено как основное (`is_primary = TRUE`)
|
||||
|
||||
---
|
||||
|
||||
### 3. Система заказов
|
||||
|
||||
#### `order_statuses` - Статусы заказов
|
||||
Предустановленные статусы заказов.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(100) | Название статуса |
|
||||
| slug | VARCHAR(50) | Уникальный идентификатор |
|
||||
| description | TEXT | Описание статуса |
|
||||
| color | VARCHAR(20) | Цвет для отображения в интерфейсе |
|
||||
| sort_order | INTEGER | Порядок сортировки |
|
||||
| is_active | BOOLEAN | Активен ли статус |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Предустановленные статусы:**
|
||||
- `pending` - Ожидает обработки
|
||||
- `processing` - В обработке
|
||||
- `shipped` - Отправлен
|
||||
- `delivered` - Доставлен
|
||||
- `cancelled` - Отменен
|
||||
- `refunded` - Возвращен
|
||||
|
||||
#### `payment_methods` - Способы оплаты
|
||||
Справочник способов оплаты.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(100) | Название способа оплаты |
|
||||
| slug | VARCHAR(50) | Уникальный идентификатор |
|
||||
| description | TEXT | Описание способа оплаты |
|
||||
| is_active | BOOLEAN | Активен ли способ оплаты |
|
||||
| sort_order | INTEGER | Порядок сортировки |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Предустановленные способы оплаты:**
|
||||
- `card` - Банковская карта
|
||||
- `e-wallet` - Электронный кошелек
|
||||
- `cash_on_delivery` - Наличные при получении
|
||||
- `bank_transfer` - Банковский перевод
|
||||
- `crypto` - Криптовалюта
|
||||
|
||||
#### `payment_statuses` - Статусы платежей
|
||||
Справочник статусов платежей.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| name | VARCHAR(100) | Название статуса |
|
||||
| slug | VARCHAR(50) | Уникальный идентификатор |
|
||||
| description | TEXT | Описание статуса |
|
||||
| color | VARCHAR(20) | Цвет для отображения в интерфейсе |
|
||||
| sort_order | INTEGER | Порядок сортировки |
|
||||
| is_active | BOOLEAN | Активен ли статус |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Предустановленные статусы:**
|
||||
- `pending` - Ожидает оплаты
|
||||
- `paid` - Оплачен
|
||||
- `completed` - Завершен
|
||||
- `failed` - Ошибка оплаты
|
||||
- `refunded` - Возвращен
|
||||
|
||||
#### `orders` - Заказы
|
||||
Основная информация о заказах покупателей.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| user_id | INTEGER | Ссылка на пользователя |
|
||||
| order_number | VARCHAR(50) | Уникальный номер заказа |
|
||||
| status_id | INTEGER | Ссылка на статус заказа |
|
||||
| subtotal | DECIMAL(10, 2) | Сумма товаров |
|
||||
| tax_amount | DECIMAL(10, 2) | Сумма налогов |
|
||||
| shipping_cost | DECIMAL(10, 2) | Стоимость доставки |
|
||||
| discount_amount | DECIMAL(10, 2) | Сумма скидки |
|
||||
| total_amount | DECIMAL(10, 2) | Итоговая сумма |
|
||||
| shipping_address_id | INTEGER | Ссылка на адрес доставки |
|
||||
| billing_address_id | INTEGER | Ссылка на адрес для выставления счета |
|
||||
| payment_method_id | INTEGER | Ссылка на способ оплаты |
|
||||
| payment_status_id | INTEGER | Ссылка на статус платежа |
|
||||
| notes | TEXT | Примечания к заказу |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Ограничения:**
|
||||
- `subtotal >= 0`
|
||||
- `tax_amount >= 0`
|
||||
- `shipping_cost >= 0`
|
||||
- `discount_amount >= 0`
|
||||
- `total_amount >= 0`
|
||||
|
||||
**Особенности:**
|
||||
- Номер заказа генерируется автоматически через триггер в формате: `ORD-YYYYMMDD-XXXXXX`
|
||||
|
||||
#### `order_items` - Элементы заказа
|
||||
Товары, входящие в заказ.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| order_id | INTEGER | Ссылка на заказ |
|
||||
| product_id | INTEGER | Ссылка на товар |
|
||||
| product_name | VARCHAR(255) | Название товара на момент заказа |
|
||||
| product_sku | VARCHAR(100) | Артикул товара на момент заказа |
|
||||
| quantity | INTEGER | Количество |
|
||||
| price | DECIMAL(10, 2) | Цена за единицу на момент заказа |
|
||||
| subtotal | DECIMAL(10, 2) | Сумма по позиции |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
|
||||
**Ограничения:**
|
||||
- `quantity > 0`
|
||||
- `price >= 0`
|
||||
- `subtotal >= 0`
|
||||
|
||||
**Особенности:**
|
||||
- Сохраняет название, артикул и цену товара на момент заказа (на случай изменения товара в будущем)
|
||||
|
||||
---
|
||||
|
||||
### 4. Корзина покупок
|
||||
|
||||
#### `cart_items` - Корзина покупок
|
||||
Временное хранение товаров перед оформлением заказа.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| user_id | INTEGER | Ссылка на пользователя |
|
||||
| product_id | INTEGER | Ссылка на товар |
|
||||
| quantity | INTEGER | Количество |
|
||||
| created_at | TIMESTAMP | Дата добавления |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Ограничения:**
|
||||
- `quantity > 0`
|
||||
- UNIQUE(user_id, product_id) - один товар может быть в корзине только один раз
|
||||
|
||||
---
|
||||
|
||||
### 5. Отзывы и рейтинги
|
||||
|
||||
#### `reviews` - Отзывы на товары
|
||||
Отзывы покупателей на товары.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| product_id | INTEGER | Ссылка на товар |
|
||||
| user_id | INTEGER | Ссылка на пользователя |
|
||||
| rating | INTEGER | Оценка (1-5) |
|
||||
| title | VARCHAR(255) | Заголовок отзыва |
|
||||
| comment | TEXT | Текст отзыва |
|
||||
| is_approved | BOOLEAN | Одобрен ли отзыв модератором |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Ограничения:**
|
||||
- `rating >= 1 AND rating <= 5`
|
||||
- UNIQUE(product_id, user_id) - один пользователь может оставить только один отзыв на товар
|
||||
|
||||
**Особенности:**
|
||||
- Отзывы требуют модерации (`is_approved = FALSE` по умолчанию)
|
||||
- Рейтинг товара обновляется автоматически при одобрении/изменении отзывов
|
||||
|
||||
---
|
||||
|
||||
### 6. Платежи
|
||||
|
||||
#### `payments` - Платежи по заказам
|
||||
Информация о платежах по заказам.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| order_id | INTEGER | Ссылка на заказ |
|
||||
| payment_method_id | INTEGER | Ссылка на способ оплаты |
|
||||
| transaction_id | VARCHAR(255) | ID транзакции в платежной системе (уникальный) |
|
||||
| amount | DECIMAL(10, 2) | Сумма платежа |
|
||||
| status_id | INTEGER | Ссылка на статус платежа |
|
||||
| payment_date | TIMESTAMP | Дата платежа |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
**Ограничения:**
|
||||
- `amount >= 0`
|
||||
|
||||
---
|
||||
|
||||
### 7. Адреса доставки
|
||||
|
||||
#### `addresses` - Адреса пользователей
|
||||
Адреса доставки пользователей.
|
||||
|
||||
| Поле | Тип | Описание |
|
||||
|------|-----|----------|
|
||||
| id | SERIAL | Первичный ключ |
|
||||
| user_id | INTEGER | Ссылка на пользователя |
|
||||
| first_name | VARCHAR(100) | Имя получателя |
|
||||
| last_name | VARCHAR(100) | Фамилия получателя |
|
||||
| phone | VARCHAR(20) | Телефон |
|
||||
| country | VARCHAR(100) | Страна |
|
||||
| city | VARCHAR(100) | Город |
|
||||
| street | VARCHAR(255) | Улица |
|
||||
| building | VARCHAR(50) | Номер дома |
|
||||
| apartment | VARCHAR(50) | Номер квартиры |
|
||||
| postal_code | VARCHAR(20) | Почтовый индекс |
|
||||
| is_default | BOOLEAN | Адрес по умолчанию |
|
||||
| created_at | TIMESTAMP | Дата создания |
|
||||
| updated_at | TIMESTAMP | Дата обновления |
|
||||
|
||||
---
|
||||
|
||||
## Функции базы данных
|
||||
|
||||
### `update_updated_at_column()`
|
||||
Автоматически обновляет поле `updated_at` при изменении записи.
|
||||
|
||||
**Использование:** Применяется через триггеры на всех таблицах с полем `updated_at`.
|
||||
|
||||
### `update_product_rating()`
|
||||
Автоматически пересчитывает рейтинг и количество отзывов товара при изменении отзывов.
|
||||
|
||||
**Логика:**
|
||||
- Рассчитывает средний рейтинг из одобренных отзывов
|
||||
- Подсчитывает количество одобренных отзывов
|
||||
- Обновляет поля `rating` и `review_count` в таблице `products`
|
||||
|
||||
**Триггеры:**
|
||||
- Срабатывает при INSERT, UPDATE и DELETE в таблице `reviews`
|
||||
|
||||
### `generate_order_number()`
|
||||
Автоматически генерирует уникальный номер заказа.
|
||||
|
||||
**Формат:** `ORD-YYYYMMDD-XXXXXX`
|
||||
|
||||
**Пример:** `ORD-20240115-000001`
|
||||
|
||||
**Триггер:** Срабатывает перед INSERT в таблицу `orders`, если `order_number` не указан.
|
||||
|
||||
### `get_order_status_id(status_slug VARCHAR)`
|
||||
Вспомогательная функция для получения ID статуса заказа по его slug.
|
||||
|
||||
**Возвращает:** INTEGER (ID статуса) или NULL
|
||||
|
||||
### `get_payment_status_id(status_slug VARCHAR)`
|
||||
Вспомогательная функция для получения ID статуса платежа по его slug.
|
||||
|
||||
**Возвращает:** INTEGER (ID статуса) или NULL
|
||||
|
||||
### `get_payment_method_id(method_slug VARCHAR)`
|
||||
Вспомогательная функция для получения ID способа оплаты по его slug.
|
||||
|
||||
**Возвращает:** INTEGER (ID способа оплаты) или NULL
|
||||
|
||||
---
|
||||
|
||||
## Триггеры
|
||||
|
||||
### Триггеры обновления `updated_at`
|
||||
Автоматически обновляют поле `updated_at` при изменении записи в следующих таблицах:
|
||||
- `resources`
|
||||
- `actions`
|
||||
- `permissions`
|
||||
- `roles`
|
||||
- `users`
|
||||
- `categories`
|
||||
- `order_statuses`
|
||||
- `products`
|
||||
- `addresses`
|
||||
- `orders`
|
||||
- `cart_items`
|
||||
- `reviews`
|
||||
- `payments`
|
||||
|
||||
### Триггеры обновления рейтинга товара
|
||||
- **`update_product_rating_on_review_insert`** - после добавления отзыва (если он одобрен)
|
||||
- **`update_product_rating_on_review_update`** - после изменения отзыва (если изменился рейтинг или статус одобрения)
|
||||
- **`update_product_rating_on_review_delete`** - после удаления отзыва
|
||||
|
||||
### Триггер генерации номера заказа
|
||||
- **`generate_order_number_trigger`** - перед вставкой нового заказа генерирует номер, если он не указан
|
||||
|
||||
---
|
||||
|
||||
## Индексы
|
||||
|
||||
Индексы созданы для оптимизации наиболее частых запросов:
|
||||
|
||||
### Индексы по slug
|
||||
- `resources.slug`
|
||||
- `actions.slug`
|
||||
- `permissions.slug`
|
||||
- `roles.slug`
|
||||
- `categories.slug`
|
||||
- `products.slug`
|
||||
- `order_statuses.slug`
|
||||
|
||||
### Индексы по внешним ключам
|
||||
- `permissions.resource_id`, `permissions.action_id`
|
||||
- `role_permissions.role_id`, `role_permissions.permission_id`
|
||||
- `users.role_id`
|
||||
- `categories.parent_id`
|
||||
- `products.category_id`
|
||||
- `product_images.product_id`
|
||||
- `addresses.user_id`
|
||||
- `orders.user_id`, `orders.status_id`, `orders.payment_method_id`, `orders.payment_status_id`
|
||||
- `order_items.order_id`, `order_items.product_id`
|
||||
- `cart_items.user_id`, `cart_items.product_id`
|
||||
- `reviews.product_id`, `reviews.user_id`
|
||||
- `payments.order_id`, `payments.payment_method_id`, `payments.status_id`
|
||||
|
||||
### Индексы по статусам и флагам
|
||||
- `resources.is_active`
|
||||
- `actions.is_active`
|
||||
- `permissions.is_active`
|
||||
- `roles.is_active`
|
||||
- `users.is_active`
|
||||
- `categories.is_active`
|
||||
- `products.is_active`, `products.is_featured`
|
||||
- `order_statuses.is_active`
|
||||
- `payment_methods.is_active`
|
||||
- `payment_statuses.is_active`
|
||||
- `reviews.is_approved`
|
||||
|
||||
### Индексы по уникальным полям
|
||||
- `users.email`
|
||||
- `users.telegram_id`
|
||||
- `products.sku`
|
||||
- `orders.order_number`
|
||||
- `payments.transaction_id`
|
||||
|
||||
### Индексы для сортировки и фильтрации
|
||||
- `products.price`
|
||||
- `orders.created_at`
|
||||
- `orders.payment_status_id`
|
||||
- `reviews.rating`
|
||||
|
||||
---
|
||||
|
||||
## Начальные данные (seed_data.sql)
|
||||
|
||||
### Ресурсы
|
||||
- products, orders, categories, reviews, cart, users
|
||||
- payments, addresses, roles, permissions
|
||||
- * (все ресурсы для администратора)
|
||||
|
||||
### Действия
|
||||
- view, create, edit, delete
|
||||
- moderate, manage, view_own
|
||||
- * (все действия для администратора)
|
||||
|
||||
### Права доступа
|
||||
Создаются комбинации ресурсов и действий, например:
|
||||
- `products.view`, `products.create`, `products.edit`, `products.delete`
|
||||
- `orders.view`, `orders.create`, `orders.edit`, `orders.view_own`
|
||||
- `categories.view`, `categories.create`, `categories.edit`, `categories.delete`
|
||||
- `reviews.view`, `reviews.create`, `reviews.moderate`, `reviews.delete`
|
||||
- `cart.manage`
|
||||
- `users.view`, `users.edit`, `users.delete`
|
||||
- `admin.all` (полные права)
|
||||
|
||||
### Роли и их права
|
||||
|
||||
#### Администратор (admin)
|
||||
- Все права доступа (`admin.all`)
|
||||
|
||||
#### Владелец (owner)
|
||||
- Все права, кроме управления ролями и правами доступа
|
||||
|
||||
#### Сотрудник (employee)
|
||||
- Просмотр, создание, редактирование, удаление товаров
|
||||
- Просмотр и редактирование заказов
|
||||
- Полное управление категориями
|
||||
- Просмотр, модерация и удаление отзывов
|
||||
- Просмотр пользователей
|
||||
|
||||
#### Менеджер (manager)
|
||||
- Те же права, что и у сотрудника
|
||||
|
||||
#### Клиент (customer)
|
||||
- Просмотр товаров и категорий
|
||||
- Создание заказов и просмотр своих заказов
|
||||
- Управление корзиной
|
||||
- Создание отзывов
|
||||
|
||||
### Статусы заказов
|
||||
1. **pending** - Ожидает обработки (#FFA500)
|
||||
2. **processing** - В обработке (#4169E1)
|
||||
3. **shipped** - Отправлен (#32CD32)
|
||||
4. **delivered** - Доставлен (#228B22)
|
||||
5. **cancelled** - Отменен (#DC143C)
|
||||
6. **refunded** - Возвращен (#8B0000)
|
||||
|
||||
### Способы оплаты
|
||||
1. **card** - Банковская карта
|
||||
2. **e-wallet** - Электронный кошелек
|
||||
3. **cash_on_delivery** - Наличные при получении
|
||||
4. **bank_transfer** - Банковский перевод
|
||||
5. **crypto** - Криптовалюта
|
||||
|
||||
### Статусы платежей
|
||||
1. **pending** - Ожидает оплаты (#FFA500)
|
||||
2. **paid** - Оплачен (#32CD32)
|
||||
3. **completed** - Завершен (#228B22)
|
||||
4. **failed** - Ошибка оплаты (#DC143C)
|
||||
5. **refunded** - Возвращен (#8B0000)
|
||||
|
||||
---
|
||||
|
||||
## Диаграмма связей
|
||||
|
||||
```
|
||||
users ──┬──> roles ──> role_permissions ──> permissions ──┬──> resources
|
||||
│ └──> actions
|
||||
│
|
||||
├──> addresses
|
||||
├──> cart_items ──> products ──> categories
|
||||
├──> orders ──> order_statuses
|
||||
│ └──> order_items ──> products
|
||||
│ └──> payments
|
||||
└──> reviews ──> products
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### Получение всех прав пользователя
|
||||
```sql
|
||||
SELECT p.slug, p.name
|
||||
FROM users u
|
||||
JOIN roles r ON u.role_id = r.id
|
||||
JOIN role_permissions rp ON r.id = rp.role_id
|
||||
JOIN permissions p ON rp.permission_id = p.id
|
||||
WHERE u.id = 1 AND p.is_active = TRUE;
|
||||
```
|
||||
|
||||
### Получение товаров с рейтингом
|
||||
```sql
|
||||
SELECT p.*, c.name as category_name
|
||||
FROM products p
|
||||
LEFT JOIN categories c ON p.category_id = c.id
|
||||
WHERE p.is_active = TRUE
|
||||
ORDER BY p.rating DESC, p.review_count DESC;
|
||||
```
|
||||
|
||||
### Получение заказов пользователя
|
||||
```sql
|
||||
SELECT o.*,
|
||||
os.name as status_name, os.color as status_color,
|
||||
pm.name as payment_method_name,
|
||||
ps.name as payment_status_name, ps.color as payment_status_color
|
||||
FROM orders o
|
||||
JOIN order_statuses os ON o.status_id = os.id
|
||||
LEFT JOIN payment_methods pm ON o.payment_method_id = pm.id
|
||||
LEFT JOIN payment_statuses ps ON o.payment_status_id = ps.id
|
||||
WHERE o.user_id = 1
|
||||
ORDER BY o.created_at DESC;
|
||||
```
|
||||
|
||||
### Получение элементов заказа
|
||||
```sql
|
||||
SELECT oi.*, p.name as current_product_name, p.price as current_price
|
||||
FROM order_items oi
|
||||
LEFT JOIN products p ON oi.product_id = p.id
|
||||
WHERE oi.order_id = 1;
|
||||
```
|
||||
|
||||
### Получение корзины пользователя
|
||||
```sql
|
||||
SELECT ci.*, p.name, p.price, p.stock_quantity, pi.image_url
|
||||
FROM cart_items ci
|
||||
JOIN products p ON ci.product_id = p.id
|
||||
LEFT JOIN product_images pi ON p.id = pi.product_id AND pi.is_primary = TRUE
|
||||
WHERE ci.user_id = 1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Рекомендации по использованию
|
||||
|
||||
1. **Безопасность:**
|
||||
- Всегда проверяйте права доступа перед выполнением операций
|
||||
- Используйте параметризованные запросы для предотвращения SQL-инъекций
|
||||
- Храните пароли только в виде хешей
|
||||
|
||||
2. **Производительность:**
|
||||
- Используйте индексы для часто запрашиваемых полей
|
||||
- При больших объемах данных рассмотрите партиционирование таблиц `orders` и `order_items`
|
||||
- Регулярно анализируйте и оптимизируйте медленные запросы
|
||||
|
||||
3. **Целостность данных:**
|
||||
- Используйте транзакции при создании заказов (заказ + элементы заказа)
|
||||
- Проверяйте наличие товара на складе перед добавлением в корзину
|
||||
- Обновляйте количество товара на складе при создании заказа
|
||||
|
||||
4. **Масштабирование:**
|
||||
- Рассмотрите возможность добавления таблицы для истории изменений заказов
|
||||
- Для больших каталогов товаров используйте полнотекстовый поиск (PostgreSQL tsvector)
|
||||
- Кэшируйте часто запрашиваемые данные (категории, популярные товары)
|
||||
|
||||
---
|
||||
|
||||
## Версия
|
||||
|
||||
**Версия базы данных:** 1.0
|
||||
**СУБД:** PostgreSQL
|
||||
**Дата создания:** 2024
|
||||
|
||||
---
|
||||
|
||||
## Лицензия
|
||||
|
||||
Данная схема базы данных предоставляется "как есть" для использования в проектах интернет-магазинов.
|
||||
|
||||
Reference in new issue
Block a user