# Руководство по системе регистрации тенантов ## Что реализовано Создана полноценная система регистрации новых магазинов (тенантов) с ручной модерацией администратором. ### 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` установлен --- **Система готова к использованию!** Теперь вы можете: - Принимать заявки на регистрацию - Модерировать их через админку - Управлять подписками - Контролировать доступ к магазинам