# FitnessCenter — эксплуатационная документация ## Назначение Одностраничный лендинг и личный кабинет фитнес‑клуба с регистрацией, входом и покупкой абонементов. Рендеринг на сервере (Django), без JSON API. ## Стек - Python 3.13, Django 5.1.4 - Bootstrap 5.3 (CDN), шрифт Manrope, кастомный тёмный UI `static/css/main.css` - БД по умолчанию: SQLite (`db.sqlite3`); совместимо с Postgres - Контейнеризация: Dockerfile (python:3.13-slim) + `docker-compose.yml` (порт 1337→8000) ## Архитектура и файлы - `gymclub/` — настройки Django, URL‑маршрутизация верхнего уровня. - `club/` — доменная логика: модели, формы, views, urls, context processor с адресами клубов. - `templates/` — серверные шаблоны: `base.html`, `home.html`, `register.html`, `login.html`, `dashboard.html`. - `static/` — стили и логотип, подключаются через `{% static %}`; собранные файлы кладутся в `staticfiles/`. - `entrypoint.sh` — миграции + `collectstatic` (ошибки игнорируются) и запуск `runserver` на 0.0.0.0:8000. - `www/` — архивная статическая версия лендинга (не используется приложением). ## Данные и бизнес‑логика - `MembershipPlan`: имя, описание, длительность в днях, цена. Начальные тарифы создаются миграцией `0002_default_plans`. - `Profile`: OneToOne к пользователю, хранит телефон. - `Subscription`: ссылка на пользователя и план, даты начала/окончания; `is_active` проверяет `end_date` ≥ сегодня. - Хелпер `Subscription.create_for_plan(user, plan)` рассчитывает дату окончания от текущей даты и создаёт запись — используйте его вместо ручного сохранения. - Проверка телефона (RegistrationForm): нормализует «8» в «+7», требует 11 цифр формата +7XXXXXXXXXX. - Парольные валидаторы стандартные, но проверка «простых паролей» отключена (CommonPasswordValidator не подключён). ## Маршруты (HTML API) Все пути объявлены в `club/urls.py`, подключены в `gymclub/urls.py`. - `GET /` — витрина с планами, адресами клубов. - `GET /register/`, `POST /register/` — регистрация пользователя, автологин, создание Profile. - `GET /login/`, `POST /login/` — аутентификация через Django AuthenticationForm. - `GET /logout/` — logout + redirect домой (view использует `logout`, форма не нужна). - `GET /dashboard/` (требует авторизации) — активный абонемент, история, покупка новых. - `POST /subscribe//` — покупка плана через `Subscription.create_for_plan`. - `admin/` — стандартная админка для планов, подписок и профилей. Все формы защищены CSRF; сообщения пользователю выводятся через Django messages. ## UI и контент - Тёмная тема с акцентным цветом `--accent` в `static/css/main.css`; поменяйте переменные в корне файла для ребрендинга. - Список клубов задаётся константой `CLUBS` в `club/context_processors.py` и доступен в шаблонах как `clubs`. - Главная страница содержит секции «Абонементы», «Тренеры», «Клубы», «О нас» и форму заявки в футере (пока без обработки). ## Переменные окружения Файл примера `.env.example`: - `DJANGO_DEBUG` (True/False) - `DJANGO_ALLOWED_HOSTS` (список через запятую, `*` по умолчанию) - `DJANGO_SECRET_KEY` (смените в проде) Дополнительно в `settings.py`: язык `ru-ru`, часовой пояс `Europe/Moscow`. ## Запуск ### В Docker ```bash cp .env.example .env docker compose build docker compose up # Откройте http://localhost:1337 ``` Контейнер монтирует текущую директорию, так что правки видны без пересборки. ### Локально (без Docker) ```bash python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt cp .env.example .env # при необходимости отредактируйте python manage.py migrate python manage.py runserver ``` ### Админка и данные - Создайте суперпользователя: `python manage.py createsuperuser`. - Начальные планы создаются миграцией; новые можно добавить через /admin/ или фикстуры. ### Переключение на Postgres (кратко) 1. Добавьте сервис в `docker-compose.yml` или поднимите внешнюю БД. 2. В `gymclub/settings.py` задайте `ENGINE = 'django.db.backends.postgresql'` и параметры `NAME/USER/PASSWORD/HOST/PORT` (лучше через переменные окружения). 3. Выполните миграции заново (`python manage.py migrate`). ## Хитрости и рекомендации - Используйте `Subscription.create_for_plan` — он правильно считает `end_date` от текущего дня. - Телефон хранится в нормализованном формате `+7XXXXXXXXXX`; это можно использовать для SMS‑интеграций. - Планы отсортированы по цене (`ordering = ['price']`), поэтому вывод на главной будет от дешёвого к дорогому. - `entrypoint.sh` не падает, если `collectstatic` без настроек S3; удобнее для локалки, но в проде задайте `STATIC_ROOT` и уберите `|| true` при необходимости. - Блок футера «Позвоните мне» пока статический — если нужна отправка заявки, повесьте action на форму и добавьте view. ## Полезные пути - Основной код: `club/views.py`, `club/forms.py`, `club/models.py` - Стили: `static/css/main.css` - Шаблоны: `templates/` - Контейнеризация: `Dockerfile`, `docker-compose.yml`, `entrypoint.sh`