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

297
myproject/START_HERE.md Normal file
View File

@@ -0,0 +1,297 @@
# 🚀 Чистый старт проекта с Django Tenants
Все миграции удалены. База данных пуста. Готов к чистому старту!
## ✅ Что уже сделано:
1. ✅ PostgreSQL установлен и запущен в Docker
2.Все старые миграции удалены
3. ✅ SQLite база удалена
4. ✅ Проект настроен для django-tenants
---
## 📋 Пошаговая инструкция:
### Шаг 1: Установить зависимости
```bash
pip install -r requirements.txt
```
Это установит:
- django-tenants
- psycopg2-binary
- и все остальные зависимости
---
### Шаг 2: Создать миграции для всех приложений
```bash
python manage.py makemigrations
```
Django создаст миграции для:
- **tenants** (public схема - Client и Domain)
- **accounts, customers, shops, products, orders, inventory** (tenant схемы)
---
### Шаг 3: Применить миграции к public схеме
```bash
python manage.py migrate_schemas --shared
```
Это создаст:
- Схему `public` в PostgreSQL
- Таблицы для управления тенантами (Client, Domain)
- Таблицы Django (auth, contenttypes, sessions, admin)
---
### Шаг 4: Создать public тенанта
Public тенант нужен для главного домена (localhost в разработке).
```bash
python manage.py shell
```
В 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()
```
---
### Шаг 5: Создать суперпользователя (ваш аккаунт)
```bash
python manage.py createsuperuser --schema=public
```
Введите:
- **Email**: ваш email
- **Name**: ваше имя
- **Password**: ваш пароль
Этот суперпользователь будет иметь доступ к админке на `localhost:8000/admin/` для управления тенантами.
---
### Шаг 6: Создать первый магазин (тенант)
```bash
python manage.py create_tenant
```
Пример данных:
- **Название магазина**: Цветочный рай
- **Схема БД**: shop1
- **Домен**: shop1.localhost (или оставьте по умолчанию)
- **Имя владельца**: Иван Иванов
- **Email**: ivan@example.com
- **Телефон**: (можете оставить пустым)
Команда автоматически:
1. Создаст тенанта в таблице `Client`
2. Создаст домен в таблице `Domain`
3. Создаст схему `shop1` в PostgreSQL
4. Применит все миграции к схеме `shop1`
5. Создаст все таблицы (customers, orders, products, etc.) в схеме `shop1`
---
### Шаг 7: Настроить hosts файл
Откройте файл hosts с правами администратора:
**Windows**: `C:\Windows\System32\drivers\etc\hosts`
Добавьте строки:
```
127.0.0.1 localhost
127.0.0.1 shop1.localhost
127.0.0.1 shop2.localhost
```
Сохраните файл.
---
### Шаг 8: Запустить сервер
```bash
python manage.py runserver 0.0.0.0:8000
```
---
### Шаг 9: Проверить работу
#### 1. Админка супер-администратора (Public схема):
URL: **http://localhost:8000/admin/**
Логин: email и пароль суперпользователя (из Шага 5)
Здесь вы увидите:
- Управление тенантами (магазинами)
- Управление доменами
- Стандартные разделы Django
#### 2. Админка магазина (Tenant схема):
URL: **http://shop1.localhost:8000/admin/**
Сначала нужно создать пользователя для магазина:
```bash
python manage.py tenant_command createsuperuser --schema=shop1
```
Затем зайдите в админку магазина и увидите:
- Клиенты (Customers)
- Адреса (Addresses)
- Магазины/точки (Shops)
- Товары (Products, Categories, Kits)
- Заказы (Orders, OrderItems)
- Складской учет (Inventory)
---
## 🎯 Проверка изоляции данных
Создайте второй магазин:
```bash
python manage.py create_tenant
```
Данные (название: "Второй магазин", схема: "shop2", домен: "shop2.localhost")
Затем:
1. Добавьте товары в shop1
2. Добавьте товары в shop2
3. Убедитесь, что товары из shop1 НЕ видны в shop2 и наоборот
**Это и есть полная изоляация данных!**
---
## 🛠 Полезные команды
### Посмотреть список всех тенантов:
```bash
python manage.py shell
```
```python
from tenants.models import Client
for tenant in Client.objects.all():
print(f'{tenant.name}: {tenant.schema_name} - {tenant.get_primary_domain()}')
```
### Применить миграции ко всем тенантам:
```bash
python manage.py migrate_schemas
```
### Применить миграции к конкретному тенанту:
```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 shell --schema=shop1
python manage.py tenant_command dumpdata --schema=shop1 > shop1_data.json
```
---
## 📊 Структура базы данных
После выполнения всех шагов в PostgreSQL будет:
### Схема `public`:
- Таблицы тенантов: `tenants_client`, `tenants_domain`
- Таблицы Django: `auth_user`, `auth_group`, `django_session`, etc.
### Схема `shop1`:
- `customers_customer`, `customers_address`
- `shops_shop`
- `products_product`, `products_category`, `products_productkit`
- `orders_order`, `orders_orderitem`
- `inventory_*`
- И все остальные таблицы приложений
### Схема `shop2`:
- Те же таблицы что и в `shop1`, но с ДРУГИМИ данными!
---
## ❗ Возможные проблемы
### Ошибка: "connection to server at localhost (127.0.0.1), port 5432 failed"
PostgreSQL не запущен. Запустите:
```bash
docker start inventory-postgres
```
### Ошибка: "database 'inventory_db' does not exist"
Создайте базу:
```bash
docker exec -it inventory-postgres psql -U postgres -c "CREATE DATABASE inventory_db;"
```
### Ошибка: "No tenant found for hostname 'shop1.localhost'"
- Проверьте hosts файл
- Проверьте, что домен создан: `Domain.objects.filter(domain='shop1.localhost').exists()`
### Ошибка: "relation does not exist"
Миграции не применены. Запустите:
```bash
python manage.py migrate_schemas
```
---
## 🎉 Готово!
После выполнения всех шагов у вас будет работающая SaaS-платформа с полной изоляцией данных между магазинами!
**Подробная документация**: [DJANGO_TENANTS_SETUP.md](DJANGO_TENANTS_SETUP.md)