Initial commit: Korea Tourism Agency website with AdminJS
- Full-stack Node.js/Express application with PostgreSQL - Modern ES modules architecture - AdminJS admin panel with Sequelize ORM - Tourism routes, guides, articles, bookings management - Responsive Bootstrap 5 frontend - Docker containerization with docker-compose - Complete database schema with migrations - Authentication system for admin panel - Dynamic placeholder images for tour categories
This commit is contained in:
155
database/schema.sql
Normal file
155
database/schema.sql
Normal file
@@ -0,0 +1,155 @@
|
||||
-- Korea Tourism Agency Database Schema
|
||||
-- Создание основных таблиц для туристического агентства
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Таблица администраторов
|
||||
CREATE TABLE IF NOT EXISTS admins (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(50) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(100) UNIQUE NOT NULL,
|
||||
role VARCHAR(20) DEFAULT 'admin',
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица гидов
|
||||
CREATE TABLE IF NOT EXISTS guides (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(100) UNIQUE,
|
||||
phone VARCHAR(20),
|
||||
bio TEXT,
|
||||
specialization VARCHAR(20) NOT NULL CHECK (specialization IN ('city', 'mountain', 'fishing')),
|
||||
languages TEXT[], -- Массив языков
|
||||
experience INTEGER DEFAULT 0, -- Опыт в годах
|
||||
image_url VARCHAR(255),
|
||||
hourly_rate DECIMAL(8,2),
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица маршрутов/туров
|
||||
CREATE TABLE IF NOT EXISTS routes (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title VARCHAR(200) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
content TEXT, -- Полное описание
|
||||
type VARCHAR(20) NOT NULL CHECK (type IN ('city', 'mountain', 'fishing')),
|
||||
price DECIMAL(10,2) NOT NULL,
|
||||
duration INTEGER NOT NULL, -- Длительность в часах
|
||||
difficulty_level VARCHAR(10) DEFAULT 'easy' CHECK (difficulty_level IN ('easy', 'moderate', 'hard')),
|
||||
max_group_size INTEGER DEFAULT 10,
|
||||
included_services TEXT[],
|
||||
meeting_point TEXT,
|
||||
image_url VARCHAR(255),
|
||||
guide_id INTEGER REFERENCES guides(id),
|
||||
is_featured BOOLEAN DEFAULT false,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица статей
|
||||
CREATE TABLE IF NOT EXISTS articles (
|
||||
id SERIAL PRIMARY KEY,
|
||||
title VARCHAR(200) NOT NULL,
|
||||
excerpt TEXT,
|
||||
content TEXT NOT NULL,
|
||||
category VARCHAR(50) NOT NULL CHECK (category IN ('travel-tips', 'culture', 'food', 'nature', 'history')),
|
||||
image_url VARCHAR(255),
|
||||
author_id INTEGER REFERENCES admins(id),
|
||||
views INTEGER DEFAULT 0,
|
||||
is_published BOOLEAN DEFAULT false,
|
||||
meta_description TEXT,
|
||||
meta_keywords TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица бронирований
|
||||
CREATE TABLE IF NOT EXISTS bookings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
route_id INTEGER REFERENCES routes(id) NOT NULL,
|
||||
guide_id INTEGER REFERENCES guides(id),
|
||||
customer_name VARCHAR(100) NOT NULL,
|
||||
customer_email VARCHAR(100) NOT NULL,
|
||||
customer_phone VARCHAR(20),
|
||||
preferred_date DATE,
|
||||
group_size INTEGER DEFAULT 1,
|
||||
total_price DECIMAL(10,2),
|
||||
special_requirements TEXT,
|
||||
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'confirmed', 'cancelled', 'completed')),
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица отзывов
|
||||
CREATE TABLE IF NOT EXISTS reviews (
|
||||
id SERIAL PRIMARY KEY,
|
||||
route_id INTEGER REFERENCES routes(id),
|
||||
guide_id INTEGER REFERENCES guides(id),
|
||||
booking_id INTEGER REFERENCES bookings(id),
|
||||
customer_name VARCHAR(100) NOT NULL,
|
||||
customer_email VARCHAR(100),
|
||||
rating INTEGER CHECK (rating >= 1 AND rating <= 5) NOT NULL,
|
||||
comment TEXT,
|
||||
is_approved BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица сообщений с формы контактов
|
||||
CREATE TABLE IF NOT EXISTS contact_messages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(100) NOT NULL,
|
||||
phone VARCHAR(20),
|
||||
subject VARCHAR(200),
|
||||
message TEXT NOT NULL,
|
||||
status VARCHAR(20) DEFAULT 'unread' CHECK (status IN ('unread', 'read', 'replied')),
|
||||
admin_notes TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Таблица настроек сайта
|
||||
CREATE TABLE IF NOT EXISTS site_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
setting_key VARCHAR(100) UNIQUE NOT NULL,
|
||||
setting_value TEXT,
|
||||
setting_type VARCHAR(20) DEFAULT 'text' CHECK (setting_type IN ('text', 'number', 'boolean', 'json')),
|
||||
description TEXT,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Создание индексов для производительности
|
||||
CREATE INDEX IF NOT EXISTS idx_routes_type ON routes(type);
|
||||
CREATE INDEX IF NOT EXISTS idx_routes_active ON routes(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_routes_featured ON routes(is_featured);
|
||||
CREATE INDEX IF NOT EXISTS idx_guides_specialization ON guides(specialization);
|
||||
CREATE INDEX IF NOT EXISTS idx_guides_active ON guides(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_articles_category ON articles(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_articles_published ON articles(is_published);
|
||||
CREATE INDEX IF NOT EXISTS idx_bookings_status ON bookings(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_bookings_date ON bookings(preferred_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_reviews_rating ON reviews(rating);
|
||||
|
||||
-- Создание триггеров для автоматического обновления 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 TRIGGER update_admins_updated_at BEFORE UPDATE ON admins FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER update_guides_updated_at BEFORE UPDATE ON guides FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER update_routes_updated_at BEFORE UPDATE ON routes FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER update_articles_updated_at BEFORE UPDATE ON articles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER update_bookings_updated_at BEFORE UPDATE ON bookings FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
CREATE TRIGGER update_site_settings_updated_at BEFORE UPDATE ON site_settings FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
Reference in New Issue
Block a user