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,70 @@
# -*- coding: utf-8 -*-
"""
Скрипт для переключения в пространство конкретного тенанта.
Использование:
python switch_to_tenant.py grach
"""
import os
import sys
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
from django.db import connection
from tenants.models import Client
if len(sys.argv) < 2:
print("Использование: python switch_to_tenant.py <schema_name>")
print("\nДоступные тенанты:")
for client in Client.objects.all():
print(f" - {client.schema_name}: {client.name}")
sys.exit(1)
schema_name = sys.argv[1]
try:
# Находим тенанта
client = Client.objects.get(schema_name=schema_name)
print(f"Найден тенант: {client.name} ({client.schema_name})")
# Переключаемся на схему тенанта
connection.set_tenant(client)
print(f"Переключено на схему: {connection.tenant.schema_name}")
print("")
# Теперь можем работать с данными тенанта
print("=" * 60)
print("Теперь вы работаете в контексте тенанта!")
print("=" * 60)
print("")
# Примеры работы с данными тенанта
from products.models import Product
from customers.models import Customer
from orders.models import Order
products_count = Product.objects.count()
customers_count = Customer.objects.count()
orders_count = Order.objects.count()
print(f"Товары: {products_count}")
print(f"Клиенты: {customers_count}")
print(f"Заказы: {orders_count}")
print("")
# Интерактивный режим
print("Запуск интерактивной оболочки...")
print("Вы можете использовать: Product, Customer, Order и другие модели")
print("")
import code
code.interact(local=locals())
except Client.DoesNotExist:
print(f"Ошибка: Тенант с schema_name '{schema_name}' не найден")
print("\nДоступные тенанты:")
for client in Client.objects.all():
print(f" - {client.schema_name}: {client.name}")
sys.exit(1)