feat: Добавить систему мультитенантности с регистрацией магазинов

Реализована полноценная система мультитенантности на базе django-tenants.
Каждый магазин получает изолированную схему БД и поддомен.

Основные компоненты:

Django-tenants интеграция:
- Модели Client (тенант) и Domain в приложении tenants/
- Разделение на SHARED_APPS и TENANT_APPS
- Public schema для общей админки
- Tenant schemas для изолированных данных магазинов

Система регистрации магазинов:
- Публичная форма регистрации на /register/
- Модель TenantRegistration для заявок со статусами (pending/approved/rejected)
- Валидация schema_name (латиница, 3-63 символа, уникальность)
- Проверка на зарезервированные имена (admin, api, www и т.д.)
- Админ-панель для модерации заявок с кнопками активации/отклонения

Система подписок:
- Модель Subscription с планами (триал 90 дней, месяц, квартал, год)
- Автоматическое создание триальной подписки при активации
- Методы is_expired() и days_left() для проверки статуса
- Цветовая индикация в админке (зеленый/оранжевый/красный)

Приложения:
- tenants/ - управление тенантами, регистрация, подписки
- shops/ - точки магазинов/самовывоза (tenant app)
- Обновлены миграции для всех приложений

Утилиты:
- switch_to_tenant.py - переключение между схемами тенантов
- Обновлены image_processor и image_service

Конфигурация:
- urls_public.py - роуты для public schema (админка + регистрация)
- urls.py - роуты для tenant schemas (магазины)
- requirements.txt - добавлены django-tenants, django-environ, phonenumber-field

Документация:
- DJANGO_TENANTS_SETUP.md - настройка мультитенантности
- TENANT_REGISTRATION_GUIDE.md - руководство по регистрации
- QUICK_START.md - быстрый старт
- START_HERE.md - общая документация

Использование:
1. Пользователь: http://localhost:8000/register/ → заполняет форму
2. Админ: http://localhost:8000/admin/ → активирует заявку
3. Результат: http://{schema_name}.localhost:8000/ - готовый магазин

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-27 19:13:10 +03:00
parent 4b44624f86
commit 097d4ea304
43 changed files with 3186 additions and 553 deletions

View File

@@ -0,0 +1,302 @@
# Настройка Django Tenants для multi-tenancy
Этот проект настроен как SaaS-платформа с поддержкой multi-tenancy через django-tenants.
Каждый владелец магазина получает свой поддомен и изолированную схему БД в PostgreSQL.
## Шаг 1: Установка PostgreSQL
### Вариант A: Установка локально (Windows)
1. Скачайте PostgreSQL с https://www.postgresql.org/download/windows/
2. Установите PostgreSQL (запомните пароль для пользователя `postgres`)
3. Откройте pgAdmin или psql и создайте базу данных:
```sql
CREATE DATABASE inventory_db;
```
### Вариант B: Использование Docker (рекомендуется)
```bash
docker run --name inventory-postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=inventory_db \
-p 5432:5432 \
-d postgres:15
```
## Шаг 2: Установка зависимостей
```bash
pip install -r requirements.txt
```
Это установит:
- `django-tenants==3.7.0`
- `psycopg2-binary==2.9.10`
- и другие зависимости
## Шаг 3: Настройка подключения к БД
Откройте `myproject/settings.py` и при необходимости измените параметры подключения:
```python
DATABASES = {
'default': {
'ENGINE': 'django_tenants.postgresql_backend',
'NAME': 'inventory_db',
'USER': 'postgres',
'PASSWORD': 'postgres', # ВАШ ПАРОЛЬ
'HOST': 'localhost',
'PORT': '5432',
}
}
```
## Шаг 4: Создание миграций
```bash
# Создать миграции для всех приложений
python manage.py makemigrations
# Применить миграции для public схемы
python manage.py migrate_schemas --shared
```
## Шаг 5: Создание публичного тенанта
Django-tenants требует создания public тенанта для работы главного домена (inventory.by):
```bash
python manage.py shell
```
```python
from tenants.models import Client, Domain
# Создать public тенанта
public_tenant = Client.objects.create(
schema_name='public',
name='Главный домен',
owner_email='admin@inventory.by',
owner_name='Администратор'
)
# Создать домен для public
public_domain = Domain.objects.create(
domain='localhost', # Для локальной разработки
tenant=public_tenant,
is_primary=True
)
print(f'Public тенант создан: {public_tenant}')
print(f'Public домен создан: {public_domain}')
exit()
```
## Шаг 6: Создание суперпользователя
```bash
# Создать суперпользователя в public схеме
python manage.py createsuperuser --schema=public
```
Введите:
- Email: ваш email
- Name: ваше имя
- Password: ваш пароль
## Шаг 7: Создание тестового магазина (тенанта)
```bash
python manage.py create_tenant
```
Введите данные:
- Название магазина: Тестовый Магазин
- Схема БД: shop1
- Домен: shop1.localhost (или оставьте по умолчанию)
- Имя владельца: Иван Иванов
- Email: shop1@example.com
- Телефон: (опционально)
Команда автоматически:
1. Создаст тенанта в таблице `Client`
2. Создаст домен в таблице `Domain`
3. Создаст схему БД `shop1` в PostgreSQL
4. Применит все миграции к схеме `shop1`
## Шаг 8: Настройка hosts файла
Для локального тестирования добавьте в файл hosts:
**Windows**: `C:\Windows\System32\drivers\etc\hosts`
**Linux/Mac**: `/etc/hosts`
```
127.0.0.1 localhost
127.0.0.1 shop1.localhost
127.0.0.1 shop2.localhost
```
## Шаг 9: Запуск сервера
```bash
python manage.py runserver 0.0.0.0:8000
```
## Шаг 10: Тестирование
### Доступ к админке супер-администратора (Public схема):
- URL: http://localhost:8000/admin/
- Логин: email и пароль суперпользователя
- Здесь вы можете управлять тенантами (магазинами)
### Доступ к админке магазина (Tenant схема):
- URL: http://shop1.localhost:8000/admin/
- Создайте суперпользователя для магазина:
```bash
python manage.py tenant_command createsuperuser --schema=shop1
```
- Здесь владелец магазина управляет своими товарами, заказами, клиентами
---
## Архитектура проекта
### Public Schema (схема `public`):
Доступна по адресу: `localhost` или `inventory.by`
**Модели:**
- `Client` - информация о тенантах (магазинах)
- `Domain` - домены тенантов
**Кто имеет доступ:**
- Супер-администратор (вы)
**Для чего:**
- Управление тенантами
- Просмотр статистики
- Биллинг (в будущем)
### Tenant Schema (схемы `shop1`, `shop2`, и т.д.):
Доступна по поддоменам: `shop1.localhost`, `shop2.localhost`
**Модели:**
- `Customer` - клиенты магазина
- `Address` - адреса клиентов
- `Shop` - точки магазина
- `Product`, `ProductKit`, `Category` - товары
- `Order`, `OrderItem` - заказы
- `Inventory` - складской учет
- `CustomUser` - сотрудники (для будущего)
**Кто имеет доступ:**
- Владелец магазина
- Сотрудники магазина (в будущем)
**Для чего:**
- Управление товарами
- Обработка заказов
- Работа с клиентами
- Складской учет
---
## Полезные команды
### Создать тенанта:
```bash
python manage.py create_tenant
```
### Применить миграции ко всем тенантам:
```bash
python manage.py migrate_schemas
```
### Применить миграции только к public:
```bash
python manage.py migrate_schemas --shared
```
### Применить миграции к конкретному тенанту:
```bash
python manage.py migrate_schemas --schema=shop1
```
### Выполнить команду для конкретного тенанта:
```bash
python manage.py tenant_command <command> --schema=shop1
```
Например:
```bash
python manage.py tenant_command createsuperuser --schema=shop1
python manage.py tenant_command loaddata data.json --schema=shop1
```
### Список всех тенантов:
```bash
python manage.py shell
```
```python
from tenants.models import Client
for tenant in Client.objects.all():
print(f'{tenant.name}: {tenant.schema_name}')
```
---
## Устранение проблем
### Ошибка: "No tenant found for hostname"
- Проверьте, что домен добавлен в hosts файл
- Проверьте, что домен существует в таблице `Domain`
- Проверьте, что вы обращаетесь к правильному поддомену
### Ошибка: "relation does not exist"
- Запустите миграции: `python manage.py migrate_schemas`
- Проверьте, что схема создана в PostgreSQL
### Ошибка подключения к PostgreSQL:
- Проверьте, что PostgreSQL запущен
- Проверьте параметры подключения в `settings.py`
- Проверьте, что база данных `inventory_db` существует
---
## Продакшн
Для продакшна (на сервере):
1. Измените `settings.py`:
```python
DEBUG = False
ALLOWED_HOSTS = ['.inventory.by']
```
2. Настройте DNS для поддоменов (wildcard):
```
*.inventory.by → ваш сервер
```
3. Используйте реальные домены вместо localhost
4. Настройте PostgreSQL с безопасным паролем
5. Используйте environment variables для секретов
---
## Следующие шаги
После успешной настройки:
1. ✅ Создайте несколько тестовых магазинов
2. ✅ Добавьте товары в каждый магазин
3. ✅ Создайте тестовые заказы
4. ✅ Проверьте изоляцию данных между магазинами
5. 🔜 Разработайте веб-интерфейс для владельцев магазинов
6. 🔜 Добавьте регистрацию новых магазинов через веб-форму
7. 🔜 Реализуйте биллинг и тарифные планы