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:
324
myproject/TENANT_REGISTRATION_GUIDE.md
Normal file
324
myproject/TENANT_REGISTRATION_GUIDE.md
Normal file
@@ -0,0 +1,324 @@
|
||||
# Руководство по системе регистрации тенантов
|
||||
|
||||
## Что реализовано
|
||||
|
||||
Создана полноценная система регистрации новых магазинов (тенантов) с ручной модерацией администратором.
|
||||
|
||||
### 1. Модели данных ([tenants/models.py](myproject/tenants/models.py))
|
||||
|
||||
#### Client (обновлена)
|
||||
- Добавлен `db_index` для поля `name` (ускорение поиска)
|
||||
- Изменено поле `phone` на `PhoneNumberField` (поддержка РБ/РФ форматов)
|
||||
- Обновлен `help_text` для `owner_email` (один email может быть у нескольких магазинов для супер-админа)
|
||||
|
||||
#### TenantRegistration (новая)
|
||||
Модель заявки на регистрацию:
|
||||
- `shop_name` - название магазина
|
||||
- `schema_name` - желаемый поддомен (с валидацией regex)
|
||||
- `owner_email`, `owner_name`, `phone` - контактные данные
|
||||
- `status` - статус заявки: pending/approved/rejected
|
||||
- `processed_at`, `processed_by` - данные обработки
|
||||
- `tenant` - ссылка на созданный тенант после активации
|
||||
|
||||
#### Subscription (новая)
|
||||
Модель подписки:
|
||||
- `plan` - тип плана (триал 90 дней, месяц, квартал, год)
|
||||
- `started_at`, `expires_at` - период действия
|
||||
- `is_active`, `auto_renew` - статус и автопродление
|
||||
- Методы: `is_expired()`, `days_left()`, `create_trial(client)`
|
||||
|
||||
#### RESERVED_SCHEMA_NAMES
|
||||
Список зарезервированных поддоменов (admin, api, www, и т.д.)
|
||||
|
||||
---
|
||||
|
||||
### 2. Админ-панель ([tenants/admin.py](myproject/tenants/admin.py))
|
||||
|
||||
#### ClientAdmin (обновлена)
|
||||
- Добавлена колонка `subscription_status` с цветовой индикацией
|
||||
- Разрешено редактирование `schema_name` при создании нового тенанта
|
||||
- Запрещено удаление тенантов через админку (для безопасности)
|
||||
|
||||
#### TenantRegistrationAdmin (новая)
|
||||
Функции:
|
||||
- Список заявок с фильтрами по статусу и дате
|
||||
- Кнопки "Активировать" / "Отклонить" для каждой заявки
|
||||
- Массовые действия для обработки нескольких заявок
|
||||
- При активации:
|
||||
- Создается тенант (Client)
|
||||
- Создается домен (например: myshop.localhost)
|
||||
- Создается триальная подписка на 90 дней
|
||||
- Заявка помечается как "Одобрено"
|
||||
|
||||
#### SubscriptionAdmin (новая)
|
||||
- Просмотр и управление подписками
|
||||
- Цветовая индикация истекающих подписок (красный < 0 дней, оранжевый < 7 дней)
|
||||
|
||||
---
|
||||
|
||||
### 3. Публичная форма регистрации
|
||||
|
||||
#### [tenants/forms.py](myproject/tenants/forms.py) - TenantRegistrationForm
|
||||
Валидация:
|
||||
- `schema_name`: приведение к lowercase, проверка длины (3-63 символа), проверка на зарезервированные имена, проверка уникальности
|
||||
- `owner_email`: проверка на дубликаты pending заявок
|
||||
|
||||
#### [tenants/views.py](myproject/tenants/views.py)
|
||||
- `TenantRegistrationView` - форма регистрации
|
||||
- `RegistrationSuccessView` - страница благодарности
|
||||
|
||||
#### HTML шаблоны
|
||||
- [base.html](myproject/tenants/templates/tenants/base.html) - базовый шаблон с Bootstrap 5
|
||||
- [registration_form.html](myproject/tenants/templates/tenants/registration_form.html) - красивая форма с валидацией
|
||||
- [registration_success.html](myproject/tenants/templates/tenants/registration_success.html) - страница с инструкциями
|
||||
|
||||
---
|
||||
|
||||
## Как использовать
|
||||
|
||||
### Для пользователей (владельцев будущих магазинов)
|
||||
|
||||
1. Откройте публичную форму регистрации:
|
||||
```
|
||||
http://localhost:8000/register/
|
||||
```
|
||||
|
||||
2. Заполните форму:
|
||||
- Название магазина
|
||||
- Желаемый поддомен (только латиница, цифры, дефис)
|
||||
- Ваше имя
|
||||
- Email
|
||||
- Телефон
|
||||
|
||||
3. После отправки увидите страницу благодарности
|
||||
|
||||
4. Ожидайте активации администратором (в течение 24 часов)
|
||||
|
||||
---
|
||||
|
||||
### Для администратора
|
||||
|
||||
1. Войдите в админ-панель:
|
||||
```
|
||||
http://localhost:8000/admin/
|
||||
```
|
||||
|
||||
2. Перейдите в раздел "Заявки на регистрацию"
|
||||
|
||||
3. Увидите список заявок со статусом "Ожидает проверки"
|
||||
|
||||
4. Для активации заявки:
|
||||
- Кликните на кнопку "Активировать" справа от заявки
|
||||
- ИЛИ выберите несколько заявок и используйте массовое действие
|
||||
|
||||
5. Что происходит при активации:
|
||||
- Создается новый тенант (Client) с указанным schema_name
|
||||
- Создается домен `{schema_name}.localhost`
|
||||
- Создается триальная подписка на 90 дней
|
||||
- Заявка помечается как "Одобрено"
|
||||
- В поле "Созданный тенант" появляется ссылка на тенант
|
||||
|
||||
6. Для отклонения:
|
||||
- Кликните "Отклонить"
|
||||
- Заявка помечается как "Отклонено"
|
||||
|
||||
---
|
||||
|
||||
## Доступ к магазинам
|
||||
|
||||
После активации магазин доступен по адресу:
|
||||
```
|
||||
http://{schema_name}.localhost:8000/
|
||||
```
|
||||
|
||||
Например, для магазина с `schema_name=myshop`:
|
||||
```
|
||||
http://myshop.localhost:8000/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Управление подписками
|
||||
|
||||
### Просмотр подписок
|
||||
|
||||
1. Админ-панель → "Подписки"
|
||||
2. Видны все подписки с информацией:
|
||||
- Тип плана
|
||||
- Дата начала/окончания
|
||||
- Осталось дней
|
||||
- Истекла или нет
|
||||
|
||||
### Продление подписки
|
||||
|
||||
1. Откройте подписку тенанта
|
||||
2. Измените:
|
||||
- `expires_at` - новую дату окончания
|
||||
- `plan` - новый тип плана (если меняется)
|
||||
3. Сохраните
|
||||
|
||||
### Типы планов
|
||||
|
||||
- **Триальный (90 дней)** - автоматически при создании
|
||||
- **Месячный** - 30 дней
|
||||
- **Квартальный** - 90 дней
|
||||
- **Годовой** - 365 дней
|
||||
|
||||
---
|
||||
|
||||
## Технические детали
|
||||
|
||||
### Валидация schema_name
|
||||
|
||||
Regex: `^[a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?$`
|
||||
|
||||
Правила:
|
||||
- Только латинские буквы в нижнем регистре
|
||||
- Цифры и дефис разрешены
|
||||
- Длина 3-63 символа
|
||||
- Не может начинаться или заканчиваться дефисом
|
||||
- Не совпадает с зарезервированными именами
|
||||
|
||||
### Зарезервированные имена
|
||||
|
||||
```python
|
||||
RESERVED_SCHEMA_NAMES = [
|
||||
'public', 'admin', 'api', 'www', 'mail', 'ftp', 'smtp',
|
||||
'static', 'media', 'assets', 'cdn', 'app', 'web',
|
||||
'billing', 'register', 'login', 'logout', 'dashboard',
|
||||
'test', 'dev', 'staging', 'production', 'demo'
|
||||
]
|
||||
```
|
||||
|
||||
### Email для супер-админа
|
||||
|
||||
Один email может использоваться для нескольких магазинов (полезно для вас как супер-админа для входа в разные тенанты).
|
||||
|
||||
Для обычных пользователей форма проверяет наличие pending заявок с таким же email.
|
||||
|
||||
---
|
||||
|
||||
## Что дальше (рекомендации)
|
||||
|
||||
### 1. Email-уведомления
|
||||
|
||||
Добавить отправку писем:
|
||||
- Пользователю при активации заявки
|
||||
- Пользователю при истечении подписки (за 7 дней, за 1 день)
|
||||
- Админу при новой заявке
|
||||
|
||||
### 2. Биллинг
|
||||
|
||||
Создать страницу `/billing/` где владелец магазина может:
|
||||
- Посмотреть текущую подписку
|
||||
- Продлить подписку
|
||||
- Оплатить через платежную систему
|
||||
|
||||
### 3. Middleware для is_active
|
||||
|
||||
Если нужна жесткая блокировка доступа к деактивированным магазинам, создать middleware:
|
||||
```python
|
||||
# tenants/middleware.py
|
||||
class TenantStatusMiddleware:
|
||||
def __call__(self, request):
|
||||
if hasattr(request, 'tenant'):
|
||||
if not request.tenant.is_active:
|
||||
# Показать страницу "Магазин заблокирован"
|
||||
pass
|
||||
|
||||
sub = request.tenant.subscription
|
||||
if sub.is_expired():
|
||||
# Редирект на /billing/renew/
|
||||
pass
|
||||
|
||||
return self.get_response(request)
|
||||
```
|
||||
|
||||
### 4. Автоматическая очистка
|
||||
|
||||
Создать команду для удаления старых отклоненных заявок:
|
||||
```bash
|
||||
python manage.py cleanup_old_registrations --days=30
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Структура файлов
|
||||
|
||||
```
|
||||
myproject/tenants/
|
||||
├── models.py # Модели Client, TenantRegistration, Subscription
|
||||
├── admin.py # Админ-панель с функционалом активации
|
||||
├── forms.py # Форма регистрации с валидацией
|
||||
├── views.py # Views для публичной регистрации
|
||||
├── urls.py # Роуты /register/ и /register/success/
|
||||
└── templates/tenants/
|
||||
├── base.html # Базовый шаблон
|
||||
├── registration_form.html # Форма регистрации
|
||||
└── registration_success.html # Страница благодарности
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Тестирование
|
||||
|
||||
### 1. Регистрация магазина
|
||||
|
||||
```bash
|
||||
# Запустите сервер
|
||||
python manage.py runserver
|
||||
|
||||
# Откройте браузер
|
||||
http://localhost:8000/register/
|
||||
|
||||
# Заполните форму:
|
||||
Название: Тестовый магазин
|
||||
Поддомен: testshop
|
||||
Имя: Иван Иванов
|
||||
Email: test@example.com
|
||||
Телефон: +375291234567
|
||||
|
||||
# Отправьте заявку
|
||||
```
|
||||
|
||||
### 2. Активация через админку
|
||||
|
||||
```bash
|
||||
# Войдите в админку
|
||||
http://localhost:8000/admin/
|
||||
|
||||
# Логин/пароль супер-админа
|
||||
# Перейдите в "Заявки на регистрацию"
|
||||
# Нажмите "Активировать" напротив заявки
|
||||
```
|
||||
|
||||
### 3. Проверка созданного магазина
|
||||
|
||||
```bash
|
||||
# Откройте браузер
|
||||
http://testshop.localhost:8000/
|
||||
|
||||
# Должна открыться страница магазина
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Поддержка
|
||||
|
||||
При возникновении проблем проверьте:
|
||||
|
||||
1. Миграции применены: `python manage.py migrate_schemas --shared`
|
||||
2. В `settings.py` приложение `tenants` в `SHARED_APPS`
|
||||
3. В `urls_public.py` подключены роуты tenants
|
||||
4. Виртуальное окружение активировано
|
||||
5. `phonenumber_field` установлен
|
||||
|
||||
---
|
||||
|
||||
**Система готова к использованию!**
|
||||
|
||||
Теперь вы можете:
|
||||
- Принимать заявки на регистрацию
|
||||
- Модерировать их через админку
|
||||
- Управлять подписками
|
||||
- Контролировать доступ к магазинам
|
||||
Reference in New Issue
Block a user