Compare commits

...

34 Commits
main ... pages

Author SHA1 Message Date
0b97d00c54 Мотивационный отчёт для Кайрат Гали 2026-06-02 06:55:44 +00:00
7ac87e7497 v27 — мотивационный отчёт с рекомендациями для каждого спортсмена 2026-06-02 06:13:51 +00:00
14ae4f0ce7 v26 — спортивный дизайн Nike-style: оранжевый акцент, тёмная тема 2026-06-02 05:44:28 +00:00
4d8eb7cd66 v25 — светлый дизайн, переработанный CSS 2026-06-02 05:26:04 +00:00
d96b06e580 Пошаговая инструкция для разработчиков 2026-06-01 13:36:25 +00:00
9ff5334fd4 ТЗ — HTML-версия с разделом 3.12 Аналитика 2026-06-01 13:02:56 +00:00
c761d35983 ТЗ — docx пересобран с разделом Аналитика 3.12 2026-06-01 12:57:55 +00:00
f6c0f7c33b ТЗ дополнен разделом Аналитика и дашборды 2026-06-01 12:52:42 +00:00
03812c4f6e ТЗ Галикон в формате Word (.docx) 2026-06-01 12:19:46 +00:00
53bb80dc5e Техническое задание Галикон для разработчиков 2026-06-01 12:18:33 +00:00
a489a4ab58 v24 — подсказка на шаге 1 регистрации 2026-06-01 12:17:03 +00:00
f6525cb094 v23 — явные подсказки на каждом шаге регистрации вместо ИИ-чата 2026-06-01 12:12:32 +00:00
155c193aae v22 — ИИ-помощник встроен напрямую, без обходных путей 2026-06-01 12:10:37 +00:00
b9850923c0 v21 — ИИ-помощник возвращён в регистрацию и приложение 2026-06-01 12:08:27 +00:00
921e0c7774 v20 — исправлены все ошибки: шаги регистрации, телефон, чат, renderPage 2026-06-01 12:03:50 +00:00
fe2212cd66 v19 — телефон и email обязательны при регистрации 2026-06-01 12:02:52 +00:00
56e2cb1cda v18 — безопасность (SHA-256, CSP, XSS-защита, сессии, админ-панель) 2026-06-01 11:41:08 +00:00
b120586a01 feat: role selection, badges, calendar, coach/parent dashboard, champion comparison, video analysis, PDF report 2026-06-01 11:34:30 +00:00
b67252633a v16 — игры дают звёзды в рейтинг (викторина, крестики-нолики, реакция, угадай число) 2026-06-01 11:17:23 +00:00
6e31752125 v15 — игры в чате: крестики-нолики, угадай число, реакция, спорт-викторина 2026-06-01 11:16:43 +00:00
0b1b216715 v14 — полная переработка: регистрация по шагам, профиль, чаты, инструменты 2026-06-01 11:15:33 +00:00
925419643e v13 — телефон и email при регистрации 2026-06-01 11:09:26 +00:00
ca046a17aa v12 — ИИ-помощник внутри приложения для спортсмена и родителя 2026-06-01 10:54:43 +00:00
ec7595e38f v11 — ИИ-помощник при регистрации 2026-06-01 10:53:34 +00:00
c416563692 v10 — исправлен авторасчёт возраста 2026-06-01 10:52:29 +00:00
6e68eed378 v9 — логин и пароль при регистрации и входе 2026-06-01 10:43:02 +00:00
d814f28513 v8 — выбор города с подсказками по стране 2026-06-01 10:39:48 +00:00
5c3cdb3a10 v7 — выбор страны и города при регистрации 2026-06-01 10:39:10 +00:00
39cd446b1a v6 — возраст считается автоматически по дате рождения 2026-06-01 10:36:57 +00:00
4aee60f329 v5 — список всех олимпийских видов спорта при регистрации 2026-06-01 10:35:56 +00:00
7e823e34dd v4 — дата рождения при регистрации 2026-06-01 10:33:51 +00:00
d37012215b v3 — PWA установка на телефон + рейтинг тренеров и спортсменов 2026-06-01 10:29:24 +00:00
4cec2866c5 v2 — профили спортсменов (регистрация, переключение, свои данные) 2026-06-01 10:27:25 +00:00
3e15555a28 v1 — Галикон: приложение пловца (дневник, здоровье, нормативы, видео, фото, оценки, уроки) 2026-06-01 10:21:48 +00:00
10 changed files with 3117 additions and 0 deletions

173
AGENTS.md Normal file
View File

@ -0,0 +1,173 @@
<!-- vibe42-agents-version: v3-guided-2026-06-01 -->
# Vibe42 — учебная песочница для лендингов
Workspace юзера `Gibrat_Auganov`. Это **учебная среда**, где обычные люди (не разработчики) пробуют сделать свой первый сайт.
---
## 🎯 ТВОЯ РОЛЬ
Ты — **гид и помощник**, а не слепой исполнитель. Цель сессии — чтобы юзер вышел с:
1. **рабочим лендингом**, опубликованным по адресу `https://pages.git.vibe42.kz/Gibrat_Auganov/<repo>/`,
2. ощущением «это было легко» — без серверов, БД, токенов, конфигов.
Юзер не разработчик. Ему важен **результат, который видно в браузере**, а не код.
---
## 🗺 СЦЕНАРИЙ ПЕРВОГО ЗАХОДА (юзер только зашёл, ещё ничего нет)
1. Поздоровайся коротко: «Привет! Тут за 10 минут собираем лендинг и публикуем его в интернете. О чём хочешь сделать?»
2. Если он не знает — предложи **4 конкретных идеи** (выбирай близкие к нему, не абстрактные):
- Промо хобби (фотография / музыка / спорт)
- Резюме / personal page с контактами
- Афиша мероприятия (концерт, день рождения, мастер-класс)
- Меню заведения / прайс услуг
- Лендинг продукта или будущего проекта (waitlist)
3. Уточни **2 короткие детали**: стиль (тёмный/светлый/яркий) и главную цель (рассказать / собрать заявку / показать работы).
4. Сразу делай `./new-project <name>` и собирай страницу. Не спрашивай разрешения на каждый шаг.
---
## 💬 ЕСЛИ ЮЗЕР ОТВЕЧАЕТ РАСПЛЫВЧАТО
Юзер говорит «сделай что-нибудь» / «ну хз» / «сюрприз» → **не делай ничего абстрактного**.
Скажи: «Давай определимся, я задам 3 коротких вопроса:
1. Это для тебя лично, для проекта/бизнеса, или для события?
2. Главная цель — рассказать о чём-то / собрать заявку / показать портфолио?
3. Любимое настроение — строгое тёмное, лёгкое светлое, яркое цветное?»
После ответов **сразу** предложи 2 конкретных варианта названия+структуры. Дай выбрать и иди делать.
---
## 🚫 ЕСЛИ ЮЗЕР ХОЧЕТ СЛОЖНОЕ — ПЕРЕФОРМУЛИРУЙ В ЛЕНДИНГ
| Запрос | Что делаем вместо |
|--------|-------------------|
| «магазин с корзиной» | лендинг с товарами + кнопка «купить» = ссылка на WhatsApp / Telegram |
| «соцсеть» | лендинг будущего проекта + waitlist-форма (Formspree / Getform) |
| «блог с админкой» | personal-page + ссылки на статьи в Telegram/Medium |
| «приложение для записи» | лендинг услуги + ссылка на Calendly / WhatsApp |
| «сайт с входом юзеров» | публичный лендинг без логина (нам логин не нужен) |
| «бот в Telegram» | лендинг с описанием бота + кнопка `t.me/...` |
**Не говори «это невозможно».** Скажи: «У нас песочница только для статических сайтов. Давай сделаем лендинг, который покажет твою идею — а кнопки/формы свяжем с готовыми сервисами (WhatsApp, Telegram, Formspree)». Юзер счастлив, результат за 15 минут.
---
## 📐 ШАБЛОНЫ СТРАНИЦ (выбирай под идею юзера)
### A — Промо продукта/услуги
**Секции:** Hero (заголовок + подзаголовок + CTA-кнопка) → 3-4 преимущества (иконка emoji + текст) → социальное доказательство (отзыв или цифра) → CTA (кнопка/телефон/мессенджер).
### B — Personal / резюме
**Секции:** Hero (фото-аватарка + имя + одна фраза «кто я») → О себе (1-2 абзаца) → 3-5 карточек проектов/опыта → Контакты (email, telegram, github как ссылки-кнопки).
### C — Афиша мероприятия
**Секции:** Hero (название + дата + место крупно) → Программа (список с временем) → Локация (картинка-placeholder + адрес) → Регистрация (форма Formspree или контакт).
### D — Меню / прайс
**Секции:** Hero (название + слоган) → Меню/прайс (категории с ценами) → Контакты (телефон, адрес, часы работы, карта-картинка).
### E — Waitlist для будущего проекта
**Секции:** Hero (название проекта + одна фраза + email-форма) → 3 фичи «что будет» → FAQ (3 пункта) → CTA (та же email-форма).
Все шаблоны — **одна страница, прокрутка вниз**. Никаких роутов, ничего динамического.
---
## ⚡ РИТУАЛ ПОСЛЕ ПЕРВОГО ЗАПУСКА
Как только готов первый рабочий вариант (даже грубый):
1. **Сразу запушь:**
```bash
git add -A
git commit -m "v1"
git push origin HEAD:pages
```
2. **ОБЯЗАТЕЛЬНО** дай юзеру ссылку **жирно**:
> 🎉 Готово! Твой лендинг здесь: **https://pages.git.vibe42.kz/Gibrat_Auganov/<repo>/**
3. Скажи: «Открой в новой вкладке, посмотри. Что хочешь поменять?»
4. Дальше короткие итерации: правка → push → новый URL-показ. Каждые 2-3 правки — push.
---
## ⚠️ ЖЕЛЕЗНЫЕ ПРАВИЛА (НЕ нарушать никогда)
1. **Только статика — HTML + CSS + JS в браузере.**
2. **Никакого бэкенда.** Никаких Node/Express/FastAPI/Django/PHP/Go-серверов. Никаких БД. Никакого Redis.
3. **Никакой аутентификации / OAuth / JWT.**
4. **Никакого Docker, nginx, sudo, системных настроек.**
5. **Никаких тяжёлых сборщиков** (`npm install` дерево на 500МБ). Tailwind — только через CDN.
6. **НИКОГДА `git init` в workspace root (`/workspaces/Gibrat_Auganov`)** — это папка-контейнер юзера, не репозиторий.
---
## ✅ ВСЕГДА работай через `./new-project`
Если юзер сказал «сделай сайт NAME» / «создай проект NAME»:
```bash
cd /workspaces/Gibrat_Auganov
./new-project NAME # создаёт repo в Gitea + клонит локально в ./NAME/
cd NAME
# теперь создавай index.html / style.css / script.js внутри ./NAME
```
`./new-project` сам создаёт repo, клонит, и копирует туда `AGENTS.md` + `design.md`.
---
## 🌐 Git и публикация
**НЕТ GitHub.** Self-hosted git: **https://git.vibe42.kz**
- Профиль юзера: https://git.vibe42.kz/Gibrat_Auganov
- Pages (живые лендинги): https://pages.git.vibe42.kz/Gibrat_Auganov/<repo>/
- Креды уже в `/workspaces/Gibrat_Auganov/.git-credentials` — git push/clone работают без пароля
- **НЕ спрашивай юзера про GitHub URL / токен** — их не нужно
### Опубликовать лендинг
```bash
git add -A
git commit -m "site"
git push origin HEAD:pages
```
Ветка **`pages`** (Caddy её обслуживает; `gh-pages` тоже работает как fallback). Push → лендинг доступен мгновенно.
---
## 🔧 Когда что-то идёт не так
- **Pages 404** → запушь ветку `pages` снова: `git push origin HEAD:pages -f`
- **Не дёргай Gitea API типа `/repos/.../pages`, `/settings/pages`, `/deploy_keys`** — их нет
- **Не пытайся «настроить Pages через UI Gitea»** — Pages у нас работают только через push в ветку `pages`
- Запуталось — сделай новый чистый проект через `./new-project NAME-v2`, перенеси туда работающий index.html
---
## ❌ Чего НЕ делать НИКОГДА
- ❌ `git init` в workspace root
- ❌ `npm install` с прод-зависимостями (express/mongoose/pg/prisma/next/nuxt)
- ❌ Создавать `server.js` / `app.py` / `main.go` как backend
- ❌ Использовать `gh` CLI или GitHub API
- ❌ Вызывать Gitea Pages-API (его нет)
- ❌ Долгое отлаживание Pages — почти всегда решение «push HEAD:pages»
- ❌ Просить юзера ввести токен/URL/пароль — всё уже настроено
- ❌ Задавать юзеру 10 вопросов подряд (максимум 2-3 за раз)
- ❌ Показывать юзеру голый код больше 1 раза — ему важен результат, а не как написано
- ❌ Предлагать «давай сначала дизайн в Figma» — мы делаем сразу в HTML
- ❌ Говорить «это сложно» — переформулируй в простое
- ❌ Зависать в обсуждениях — сделай первый вариант грубо, потом итерируй
---
## 🎨 design.md
Рядом лежит `design.md` с готовой палитрой, типографикой и стартер-шаблоном `index.html`. **Начинай с него.** Не выдумывай новые цвета — модифицируй существующие.

336
DEV_GUIDE.md Normal file
View File

@ -0,0 +1,336 @@
# Пошаговая инструкция по разработке Галикона
## Этап 0. Подготовка окружения (1 день)
1. Установи Node.js 20 LTS
2. Установи PostgreSQL 16
3. Установи Redis 7
4. Создай проект:
- Фронтенд: `npx create-react-app galikon-frontend --template typescript`
- Бэкенд: `mkdir galikon-backend && cd galikon-backend && npm init -y && npm i express cors bcrypt jsonwebtoken pg redis socket.io multer`
5. Настрой ESLint + Prettier
6. Создай репозиторий на GitHub/GitLab, запушь
---
## Этап 1. Авторизация и пользователи (неделя 1-2)
### Шаг 1.1 — База данных
Создай миграцию users:
```sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
login VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(200) NOT NULL,
sport VARCHAR(100),
role VARCHAR(20) DEFAULT 'athlete',
birth_date DATE,
age INTEGER,
country VARCHAR(100),
city VARCHAR(100),
club VARCHAR(200),
coach VARCHAR(200),
rank VARCHAR(100),
goal TEXT,
phone VARCHAR(30),
email VARCHAR(200),
avatar_url TEXT,
photo_url TEXT,
child_name VARCHAR(200),
stars INTEGER DEFAULT 0,
quiz_score INTEGER DEFAULT 0,
games_won INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
```
### Шаг 1.2 — Регистрация (POST /api/auth/register)
- Прими JSON: login, password, name, sport, role, birth_date, country, city, club, coach, rank, goal, phone, email
- Проверь: login уникален, phone в формате +7..., email содержит @
- Захешируй пароль bcrypt (12 раундов)
- Вычисли возраст из birth_date
- Сохрани в базу
- Верни объект пользователя + accessToken + refreshToken
### Шаг 1.3 — Вход (POST /api/auth/login)
- Прими login + password
- Найди пользователя по логину
- Сравни пароль через bcrypt.compare()
- Сгенерируй JWT accessToken (15 мин) и refreshToken (30 дней)
- Реализуй rate limiting: 5 попыток → блок 1 мин (храни в Redis)
### Шаг 1.4 — Middleware авторизации
- Проверяй заголовок Authorization: Bearer <token>
- Декодируй JWT, доставай userId
- Клади пользователя в req.user
- Если токен просрочен → 401
### Шаг 1.5 — Обновление токена (POST /api/auth/refresh)
- Прими refreshToken
- Проверь в Redis (не отозван ли)
- Сгенерируй новую пару токенов
### Шаг 1.6 — Экран регистрации (фронтенд)
- 8 компонентов-шагов (Step1Name, Step2Login, Step3Sport, Step4Role, Step5Birth, Step6Location, Step7Club, Step8Contacts)
- Компонент StepIndicator (точки 1-8)
- Валидация на каждом шаге
- На шаге 2: индикатор силы пароля (слабый/средний/сильный)
- На шаге 4: выбор роли кнопками, поле «Имя ребёнка» для родителя
- На шаге 5: календарь даты + авто-возраст + аватарки эмодзи + загрузка фото
- На шаге 6: выбрать страну → загрузить города (API /api/locations/cities?country=...)
- На шаге 8: телефон + email с валидацией
---
## Этап 2. Профиль и дневник (неделя 3-4)
### Шаг 2.1 — Таблицы БД
```sql
CREATE TABLE achievements (
id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id),
title VARCHAR(300), date DATE, description TEXT
);
CREATE TABLE diary_entries (
id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id),
date DATE NOT NULL, type VARCHAR(50), km DECIMAL(5,1),
best_time VARCHAR(20), feel INTEGER CHECK(feel BETWEEN 1 AND 5),
note TEXT, created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE events (
id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id),
title VARCHAR(300), date DATE NOT NULL, location VARCHAR(300)
);
```
### Шаг 2.2 — API профиля
- GET /api/profile — вернуть текущего пользователя
- PUT /api/profile — обновить поля (name, sport, club, coach, goal, phone, email)
- POST /api/achievements — добавить достижение
- GET /api/achievements — список достижений
### Шаг 2.3 — API дневника
- GET /api/diary?limit=20&offset=0 — список записей
- POST /api/diary — новая запись (валидация: date обязательно)
- DELETE /api/diary/:id — удалить запись
- GET /api/diary/stats — агрегация: всего записей, суммарный км, среднее feel
### Шаг 2.4 — API календаря
- GET /api/events — все события
- POST /api/events — новое событие (title + date обязательно)
- DELETE /api/events/:id — удалить
### Шаг 2.5 — Система значков (геймификация)
- Бэкенд: эндпоинт GET /api/badges — вычисляет значки на основе данных пользователя
- Логика: 1+ запись в дневнике = 🏊, 10+ = 📖, 30+ = 🔥, есть достижения = 🏆 и т.д.
- Фронтенд: компонент BadgeGrid — сетка значков (полученные — цветные, нет — серые)
### Шаг 2.6 — Компоненты фронтенда
- ProfilePage: аватар, ФИО, спорт, клуб, тренер, значки, достижения
- DiaryPage: форма записи + список (с бесконечным скроллом)
- CalendarPage: форма добавления + предстоящие/прошедшие события
- Кнопка «PDF-отчёт» → GET /api/report/pdf (генерирует PDF на сервере через puppeteer)
---
## Этап 3. Чаты и WebSocket (неделя 5-6)
### Шаг 3.1 — Таблицы БД
```sql
CREATE TABLE chats (id SERIAL PRIMARY KEY, type VARCHAR(20), name VARCHAR(200));
CREATE TABLE chat_members (chat_id INTEGER REFERENCES chats(id), user_id INTEGER REFERENCES users(id));
CREATE TABLE messages (
id SERIAL PRIMARY KEY, chat_id INTEGER REFERENCES chats(id),
from_user_id INTEGER REFERENCES users(id), text TEXT NOT NULL,
read BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT NOW()
);
```
### Шаг 3.2 — WebSocket сервер
- Установи socket.io на сервер
- При подключении: аутентифицируй через JWT (передавай в handshake)
- Присоединяй пользователя к его комнатам (socket.join(`user:${userId}`))
- События:
- `chat:message` — отправить сообщение в чат
- `chat:read` — отметить прочитанным
- `chat:typing` — печатает...
### Шаг 3.3 — REST API чатов
- GET /api/chats — список чатов пользователя
- POST /api/chats — создать чат (прямой или групповой)
- GET /api/chats/:id/messages?limit=50 — сообщения чата
- POST /api/chats/:id/messages — отправить (дублирует WebSocket для надёжности)
### Шаг 3.4 — Фронтенд чата
- ChatList: список чатов с фильтром по роли (Все/Спортсмены/Тренеры/Родители)
- ChatView: сообщения + поле ввода + автоскролл вниз
- Счётчик непрочитанных (useEffect + WebSocket)
### Шаг 3.5 — Игры в чате
- TicTacToe: компонент с сеткой 3×3, ходы через WebSocket
- GuessNumber: компонент с полем ввода, попытки, подсказки «больше/меньше»
- Reaction: компонент с кругом, меняющим цвет (красный→зелёный), замер времени
- SportQuiz: 8 вопросов, варианты ответов, подсчёт очков
- При победе → POST /api/games/win — начислить звёзды
---
## Этап 4. Рейтинг и голосование (неделя 7)
### Шаг 4.1 — Таблица голосов
```sql
CREATE TABLE votes (
voter_id INTEGER REFERENCES users(id),
target_id INTEGER REFERENCES users(id),
created_at TIMESTAMP DEFAULT NOW(),
PRIMARY KEY(voter_id, target_id)
);
```
### Шаг 4.2 — API рейтинга
- POST /api/vote/:userId — проголосовать (один голос на пользователя)
- GET /api/ranking?limit=10 — топ спортсменов по звёздам
- Звёзды = голоса + бонусы за игры (автоматически)
### Шаг 4.3 — Фронтенд
- Компонент RankingList: топ-10, золото/серебро/бронза
- Кнопка «Проголосовать» у каждого пользователя
---
## Этап 5. Кабинет тренера и родителя (неделя 8)
### Шаг 5.1 — Кабинет тренера
- API: GET /api/coach/students — найти всех пользователей, где поле coach совпадает с именем тренера
- Для каждого ученика: аватар, ФИО, спорт, разряд, цель, суммарный км, последние 5 тренировок
- Фронтенд: компонент StudentsPage с карточками учеников
### Шаг 5.2 — Кабинет родителя
- API: POST /api/parent/link — привязать ребёнка по логину (проверка: ребёнок существует, роль athlete)
- API: GET /api/parent/child — получить профиль и статистику ребёнка
- Фронтенд: ChildPage — форма привязки + профиль ребёнка + кнопка «Отвязать»
---
## Этап 6. Инструменты (неделя 9)
### Шаг 6.1 — Нормативы
- Статический JSON с таблицей разрядов
- Компонент NormsTable — отображение таблицы
### Шаг 6.2 — Сравнение с чемпионами
- Статические данные Дрессела (14-18 лет)
- Компонент ChampionCompare: ввод времени + возраста → сравнение
### Шаг 6.3 — Анализ видео
- Компонент VideoAnalyzer: загрузка видео + плеер + кнопки покадровой перемотки
- Используй HTML5 video API: video.currentTime += 0.033
### Шаг 6.4 — Витамины и здоровье
- Таблицы: vitamin_log (user_id, date, vitamin_type, taken), sleep_log (user_id, date, hours, pulse), test_results (user_id, test_type, value, date)
- API: GET/POST для каждого лога
- Чек-лист витаминов на сегодня
- Лог сна и пульса с графиком за 7 дней
### Шаг 6.5 — Видеоуроки
- Статический список поисковых запросов YouTube (12 тем)
---
## Этап 7. Аналитика и дашборды (неделя 10)
### Шаг 7.1 — Бэкенд для аналитики
- GET /api/analytics/progress — вернуть массив {date, time} для графика прогресса
- GET /api/analytics/heatmap — годовая тепловая карта [{date, km}]
- GET /api/analytics/kpi — ключевые показатели
- GET /api/analytics/compare — сравнение со средним по возрасту
- GET /api/analytics/export/csv — CSV-файл всех тренировок
- GET /api/analytics/export/dashboard — PDF-отчёт
### Шаг 7.2 — Фронтенд дашборда
- Установи Chart.js: `npm i chart.js react-chartjs-2`
- Компонент ProgressChart: линейный график время/дата + линия цели
- Компонент RadarChart: радарная диаграмма навыков
- Компонент HeatmapCalendar: календарь активности (как на GitHub)
- Компонент KPICards: счётчики (тренировки, км, время, сон)
- Компонент TrainingPie: круговая диаграмма типов тренировок
### Шаг 7.3 — Дашборд тренера
- Компонент CoachDashboard: таблица учеников + групповой график
- Цветовое кодирование строк (зелёный — лидер, красный — отстающий)
- Алерты при отсутствии тренировок 3+ дня
### Шаг 7.4 — Дашборд родителя
- Компонент ParentDashboard: упрощённый график ребёнка + счётчики
---
## Этап 8. Админ-панель (неделя 10)
### Шаг 8.1
- Middleware adminAuth — проверка роли admin
- GET /api/admin/users — список всех пользователей
- DELETE /api/admin/users/:id — удалить
- POST /api/admin/users/:id/reset-password — сброс пароля
### Шаг 8.2
- Компонент AdminPanel: таблица пользователей с кнопками удалить/сбросить
---
## Этап 9. PWA (неделя 11)
### Шаг 9.1
- Создай manifest.json в public/
- Иконки: 192×192 и 512×512 PNG
- Service worker (workbox-webpack-plugin)
- Офлайн-режим: кэширование статики
- Настрой `"display": "standalone"`
### Шаг 9.2
- Мета-теги для iOS (apple-mobile-web-app-capable и т.д.)
- Splash screen для iOS
---
## Этап 10. Тестирование и деплой (неделя 11-12)
### Шаг 10.1 — Тесты
- Unit-тесты: Jest для компонентов и API-хендлеров
- E2E: Playwright для критических сценариев (регистрация, вход, дневник, чат)
### Шаг 10.2 — Деплой
- Собрать фронтенд: `npm run build`
- Настроить Docker:
- Dockerfile для бэкенда (Node.js)
- Dockerfile для фронтенда (Nginx)
- docker-compose.yml (frontend + backend + PostgreSQL + Redis)
- Развернуть на VPS (Hetzner, DigitalOcean) или AWS
### Шаг 10.3 — Мониторинг
- Логирование: Winston + Sentry
- Мониторинг ошибок: Sentry
- Uptime: UptimeRobot
---
## Итоговый чек-лист
- [ ] Регистрация (8 шагов) с валидацией
- [ ] Вход с JWT + refresh токеном
- [ ] Профиль: значки, достижения, PDF-отчёт
- [ ] Дневник тренировок с историей
- [ ] Календарь соревнований
- [ ] Чаты (WebSocket) + 4 игры
- [ ] Рейтинг с голосованием
- [ ] Кабинет тренера (ученики и их прогресс)
- [ ] Кабинет родителя (привязка ребёнка)
- [ ] Нормативы, сравнение с чемпионами, анализ видео
- [ ] Витамины, сон, анализы
- [ ] Видеоуроки (12 тем)
- [ ] Дашборд: графики, тепловая карта, KPI
- [ ] Админ-панель
- [ ] PWA (установка на телефон)
- [ ] Тесты + деплой

BIN
TZ_GALIKON.docx Normal file

Binary file not shown.

426
TZ_GALIKON.html Normal file
View File

@ -0,0 +1,426 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>ТЗ Галикон</title>
<style>
body{font:14px/1.7 -apple-system,Arial,sans-serif;max-width:900px;margin:40px auto;padding:20px;color:#222}
h1{font-size:26px;border-bottom:3px solid #00E5FF;padding-bottom:8px}
h2{font-size:20px;margin-top:28px;color:#0F1218;border-bottom:1px solid #ddd;padding-bottom:4px}
h3{font-size:16px;margin-top:20px;color:#333}
table{width:100%;border-collapse:collapse;margin:12px 0;font-size:13px}
td,th{padding:6px 10px;border:1px solid #ccc;text-align:left}
th{background:#f0f0f0;font-weight:700}
code{background:#f4f4f4;padding:2px 6px;border-radius:4px;font-size:13px}
pre{background:#f8f8f8;padding:12px;border-radius:8px;font-size:12px;overflow-x:auto}
ul{margin:8px 0;padding-left:20px}
li{margin:4px 0}
strong{color:#0F1218}
@media print{body{margin:0;padding:10px}}
</style>
</head>
<body>
<h1>Техническое задание: Галикон</h1>
<br>
<h2>1. Общее описание</h2>
<br>
<p>**Название:** Галикон — мобильное веб-приложение для спортсменов, тренеров и родителей.</p>
<br>
<p>**Цель:** Единая платформа для юных спортсменов (дети от 10 лет): дневник тренировок, контроль здоровья, рейтинги, чаты, игры, нормативы, сравнение с чемпионами. Аналогов в мире нет.</p>
<br>
<p><strong>Пользователи:</strong></p>
<p>- Спортсмен (основной пользователь)</p>
<p>- Тренер (видит своих учеников)</p>
<p>- Родитель (видит профиль ребёнка)</p>
<p>- Администратор (управление пользователями)</p>
<br>
<br>
<h2>2. Технический стек</h2>
<br>
<table>
<tr><th>Слой</th><th>Технология</th></tr>
</table>
<table>
<br>
<br>
<h2>3. Функциональные требования</h2>
<br>
<h3>3.1. Регистрация и вход</h3>
<br>
<p><strong>Регистрация — 8 шагов:</strong></p>
<li>ФИО (string, обязательно)</li>
<li>Логин (латиница, уникальный) + пароль (хеширование bcrypt, минимум 6 символов)</li>
<li>Вид спорта (select из 39 олимпийских видов)</li>
<li>Роль: спортсмен / тренер / родитель (если родитель — поле «Имя ребёнка»)</li>
<li>Дата рождения → возраст вычисляется автоматически. Аватарка (эмодзи на выбор) или загрузка фото (JPEG/PNG, макс 5 МБ)</li>
<li>Страна (select) → город (datalist с подсказками по стране)</li>
<li>Клуб, тренер (ФИО), разряд/звание, цель (произвольный текст)</li>
<li>Телефон (обязательно, валидация формата) + Email (обязательно)</li>
<br>
<p><strong>Вход:</strong></p>
<p>- Логин + пароль</p>
<p>- JWT access token (15 мин) + refresh token (30 дней)</p>
<p>- Rate limiting: 5 попыток → блокировка на 1 минуту</p>
<p>- Автовыход через 30 минут бездействия</p>
<br>
<p><strong>Безопасность:</strong></p>
<p>- Пароли: bcrypt с солью</p>
<p>- CSP-заголовки</p>
<p>- Санитизация всех пользовательских вводов (XSS-защита)</p>
<p>- HTTPS обязательно</p>
<p>- CORS только для доверенных доменов</p>
<br>
<br>
<h3>3.2. Профиль спортсмена</h3>
<br>
<p><strong>Отображение:</strong></p>
<p>- Аватар, ФИО, вид спорта, роль</p>
<p>- Дата рождения, возраст, страна, город</p>
<p>- Клуб, тренер, разряд, цель</p>
<p>- Телефон, email</p>
<br>
<p><strong>Значки (геймификация):</strong></p>
<p>Автоматический подсчёт по данным пользователя:</p>
<p>- 🏊 Первая тренировка (1+ запись в дневнике)</p>
<p>- 📖 10 тренировок</p>
<p>- 🔥 30 тренировок</p>
<p>- 🏆 Рекордсмен (есть достижения)</p>
<p>- 🎯 Снайпер (победа в игре «Угадай число»)</p>
<p>- ⚡ Молния (реакция < 300 мс)</p>
<p>- 🧠 Знаток (викторина 5+/8)</p>
<p>- 💪 100 км (суммарный километраж > 100)</p>
<br>
<p><strong>Достижения:</strong></p>
<p>Пользователь добавляет: название, дата, описание. Отображаются списком.</p>
<br>
<p><strong>Отчёт для тренера (PDF):</strong></p>
<p>- Генерация PDF на сервере (Puppeteer / wkhtmltopdf)</p>
<p>- Содержит: ФИО, спорт, клуб, тренер, разряд, цель, значки, достижения, последние 10 записей дневника</p>
<br>
<br>
<h3>3.3. Дневник тренировок</h3>
<br>
<p><strong>Поля записи:</strong></p>
<p>- Дата (date, обязательно)</p>
<p>- Тип тренировки (select: Скорость / Техника / Выносливость / ОФП / Соревнование)</p>
<p>- Километраж (число, км)</p>
<p>- Лучшее время (строка)</p>
<p>- Самочувствие (1-5)</p>
<p>- Заметка (текст)</p>
<br>
<p><strong>История:</strong></p>
<p>- Список записей, сортировка по дате (новые сверху)</p>
<p>- Удаление записи</p>
<br>
<p><strong>Агрегация (для тренера):</strong></p>
<p>- Всего тренировок</p>
<p>- Суммарный километраж</p>
<p>- Среднее самочувствие</p>
<p>- График прогресса по времени (библиотека Chart.js)</p>
<br>
<br>
<h3>3.4. Календарь соревнований</h3>
<br>
<p><strong>Добавление события:</strong></p>
<p>- Название (string)</p>
<p>- Дата (date)</p>
<p>- Место (string)</p>
<br>
<p><strong>Отображение:</strong></p>
<p>- Предстоящие (сортировка по дате)</p>
<p>- Прошедшие (сортировка по дате, обратная)</p>
<br>
<p><strong>Дополнительно (желательно):</strong></p>
<p>- Push-уведомление за день до события</p>
<p>- Цветовое кодирование по типу (соревнование / сборы / тренировка)</p>
<br>
<br>
<h3>3.5. Чаты</h3>
<br>
<p><strong>Архитектура:</strong></p>
<p>- WebSocket-соединение (Socket.io)</p>
<p>- Комнаты: личные (1-на-1), групповые</p>
<p>- Сообщения хранятся в PostgreSQL</p>
<p>- Индикатор «прочитано/не прочитано»</p>
<br>
<p><strong>Функции:</strong></p>
<p>- Список чатов с другими пользователями</p>
<p>- Фильтр по роли: Все / Спортсмены / Тренеры / Родители</p>
<p>- Отправка текстовых сообщений</p>
<p>- Счётчик непрочитанных</p>
<p>- Групповые чаты (создание, добавление участников)</p>
<br>
<p><strong>Встроенные игры (в чате):</strong></p>
<li>**Крестики-нолики** — пошаговая игра, синхронизация через WebSocket</li>
<li>**Угадай число (1-100)** — 7 попыток, победа < 5 попыток = +2 звезды</li>
<li>**Реакция** — измерение времени реакции, рекорд < 300 мс = +1 звезда</li>
<li>**Спорт-викторина** — 8 вопросов, результат 5+/8 = +1-5 звёзд</li>
<br>
<br>
<h3>3.6. Рейтинговая система</h3>
<br>
<p><strong>Звёзды начисляются за:</strong></p>
<p>- Победы в играх</p>
<p>- Высокие результаты викторины</p>
<p>- Голоса других пользователей</p>
<br>
<p><strong>Рейтинг:</strong></p>
<p>- Топ-5 спортсменов по звёздам</p>
<p>- Отображение: место, ФИО, звёзды, результаты викторины, победы в играх</p>
<p>- Топ-3 выделены золотом/серебром/бронзой</p>
<br>
<br>
<h3>3.7. Инструменты</h3>
<br>
<p><strong>Нормативы:</strong></p>
<p>- Статическая таблица разрядов по плаванию (50 м бассейн): МСМК → 2 юношеский</p>
<p>- Дистанции: 50 м, 100 м, 400 м вольный стиль</p>
<br>
<p><strong>Сравнение с чемпионами:</strong></p>
<p>- Данные Калеба Дрессела по возрастам (14-18 лет)</p>
<p>- Пользователь вводит своё время и возраст → сравнение</p>
<p>- Показывает: текущий результат → КМС → результат Дрессела в этом возрасте</p>
<br>
<p><strong>Анализ видео:</strong></p>
<p>- Загрузка видео (MP4, макс 200 МБ)</p>
<p>- Плеер с покадровой перемоткой (шаг 0.033 сек, 0.1 сек, 1 сек)</p>
<p>- Счётчик текущего кадра</p>
<p>- Play/Pause</p>
<br>
<p><strong>Витамины:</strong></p>
<p>- Чек-лист на сегодня: D3, Омега-3, Магний, Цинк, BCAA</p>
<p>- Сохранение истории по дням</p>
<br>
<p><strong>Сон и пульс:</strong></p>
<p>- Запись часов сна и утреннего пульса</p>
<p>- Средние значения за 7 дней</p>
<br>
<p><strong>Анализы:</strong></p>
<p>- Гемоглобин, Ферритин, Витамин D, Витамин B12</p>
<p>- История значений с датами</p>
<br>
<p><strong>Видеоуроки:</strong></p>
<p>- Список поисковых запросов для YouTube (12 тем по технике плавания)</p>
<br>
<br>
<h3>3.8. Кабинет тренера</h3>
<br>
<p><strong>Поиск учеников:</strong></p>
<p>- Автоматически: все пользователи, у которых поле «Тренер» совпадает с ФИО тренера</p>
<br>
<p><strong>Отображение по каждому ученику:</strong></p>
<p>- Аватар, ФИО, вид спорта, разряд, цель</p>
<p>- Суммарный километраж</p>
<p>- Последние 5 тренировок (дата, тип, км, время)</p>
<br>
<br>
<h3>3.9. Кабинет родителя</h3>
<br>
<p><strong>Привязка ребёнка:</strong></p>
<p>- Родитель вводит логин ребёнка → привязка (сохраняется в профиле родителя)</p>
<br>
<p><strong>Отображение:</strong></p>
<p>- Профиль ребёнка (как у спортсмена)</p>
<p>- Статистика: всего тренировок, км, среднее самочувствие</p>
<p>- Значки ребёнка</p>
<p>- Дневник тренировок (последние 15 записей)</p>
<p>- Цель и тренер ребёнка</p>
<p>- Кнопка «Отвязать»</p>
<br>
<br>
<h3>3.10. Админ-панель</h3>
<br>
<p><strong>Доступ:</strong></p>
<p>- Отдельный мастер-пароль администратора</p>
<br>
<p><strong>Функции:</strong></p>
<p>- Просмотр всех пользователей (ФИО, роль, логин, спорт, клуб, звёзды)</p>
<p>- Удаление пользователя</p>
<p>- Сброс пароля пользователя</p>
<br>
<br>
<h3>3.11. PWA (Progressive Web App)</h3>
<br>
<p><strong>Требования:</strong></p>
<p>- manifest.json с иконками (192x192, 512x512)</p>
<p>- Service Worker для офлайн-доступа</p>
<p>- Установка на домашний экран (iOS/Android)</p>
<p>- Режим standalone (без адресной строки браузера)</p>
<p>- Splash screen на iOS</p>
<br>
<br>
<h2>4. Нефункциональные требования</h2>
<br>
<tr><th>Фронтенд</th><th>React / Vue 3 + TypeScript, PWA</th></tr>
<tr><td>Бэкенд</td><td>Node.js (Express/Fastify) или Go</td></tr>
<tr><td>База данных</td><td>PostgreSQL</td></tr>
<tr><td>Кэш</td><td>Redis</td></tr>
<tr><td>Файлы</td><td>S3-совместимое хранилище (MinIO)</td></tr>
<tr><td>Чат</td><td>WebSocket (Socket.io)</td></tr>
<tr><td>Push-уведомления</td><td>Firebase Cloud Messaging / Web Push API</td></tr>
<tr><td>Авторизация</td><td>JWT + refresh tokens</td></tr>
<tr><td>Хостинг</td><td>Docker + Kubernetes или VPS</td></tr>
<tr><td>Параметр</td><td>Значение</td></tr>
</table>
<table>
<br>
<br>
<h2>5. API (основные эндпоинты)</h2>
<br>
<pre>POST /api/auth/register — регистрация
POST /api/auth/login — вход
POST /api/auth/refresh — обновление токена
GET /api/profile — профиль текущего пользователя
PUT /api/profile — обновление профиля
GET /api/profile/:id — профиль другого пользователя
POST /api/achievements — добавить достижение
GET /api/diary — дневник (список)
POST /api/diary — новая запись
DELETE /api/diary/:id — удалить запись
GET /api/events — календарь
POST /api/events — добавить событие
DELETE /api/events/:id — удалить событие
GET /api/chats — список чатов
GET /api/chats/:id/messages — сообщения чата
POST /api/chats/:id/messages — отправить сообщение
WS /ws/chat — WebSocket для чата
POST /api/vote/:userId — проголосовать за пользователя
GET /api/ranking — рейтинг (топ)
GET /api/coach/students — ученики тренера
POST /api/parent/link — привязать ребёнка
GET /api/admin/users — список пользователей (админ)
DELETE /api/admin/users/:id — удалить пользователя (админ)
POST /api/admin/users/:id/reset-password — сброс пароля (админ)
GET /api/report/pdf — PDF-отчёт для тренера
POST /api/upload/avatar — загрузка аватара
POST /api/upload/video — загрузка видео
POST /api/upload/photo — загрузка фото
</pre>
<br>
<br>
<h3>3.12. Аналитика и дашборды</h3>
<br>
<p><strong>Дашборд спортсмена — главный экран аналитики:</strong></p>
<br>
<p><strong>График прогресса (50 м в/с):</strong></p>
<p>- Линейный график: дата по оси X, время по оси Y</p>
<p>- Целевая линия (23″) и текущая линия тренда</p>
<p>- Автоматический расчёт скорости прогресса (секунд в месяц)</p>
<p>- Прогноз: когда будет достигнута цель при текущем темпе</p>
<br>
<p><strong>Радарная диаграмма навыков:</strong></p>
<p>- 6 осей: старт, поворот, подводная фаза, гребок, выносливость, финиш</p>
<p>- Оценки 1-10 выставляет тренер или сам спортсмен</p>
<p>- Сравнение с предыдущим месяцем</p>
<br>
<p><strong>Круговые диаграммы тренировок:</strong></p>
<p>- Распределение по типам: скорость / техника / выносливость / ОФП</p>
<p>- За текущий месяц и за всё время</p>
<br>
<p><strong>Тепловая карта активности:</strong></p>
<p>- Календарь GitHub-style: каждый день — квадратик</p>
<p>- Цвет зависит от километража (0 — серый, 5+ км — ярко-голубой)</p>
<p>- Видно пропуски тренировок и интенсивные периоды</p>
<br>
<p><strong>Счётчики (KPI):</strong></p>
<p>- Всего тренировок, общий километраж, лучший результат</p>
<p>- Среднее самочувствие, динамика пульса, средний сон</p>
<p>- Недельная/месячная нагрузка</p>
<br>
<p><strong>Сравнительная аналитика:</strong></p>
<p>- Сравнение своего прогресса со средним по возрастной группе</p>
<p>- Сравнение с товарищами по клубу (анонимно)</p>
<p>- Процентиль: «Ты быстрее 78% пловцов твоего возраста»</p>
<br>
<p><strong>Экспорт данных:</strong></p>
<p>- CSV-выгрузка всех тренировок</p>
<p>- Excel-отчёт с графиками (автоматическая генерация)</p>
<p>- PDF-дашборд для тренера</p>
<br>
<p><strong>Технологии:</strong></p>
<p>- Chart.js / ECharts / D3.js для визуализации</p>
<p>- Данные агрегируются на бэкенде (SQL-запросы с GROUP BY)</p>
<p>- Кэширование агрегаций в Redis (обновление раз в час)</p>
<br>
<p><strong>API для аналитики:</strong></p>
<pre>GET /api/analytics/progress/:metric — график прогресса по метрике
GET /api/analytics/radar — радарная диаграмма
GET /api/analytics/heatmap — тепловая карта (год)
GET /api/analytics/distribution — распределение типов тренировок
GET /api/analytics/kpi — ключевые показатели
GET /api/analytics/compare — сравнение с группой
GET /api/analytics/export/csv — CSV-выгрузка
GET /api/analytics/export/dashboard — PDF-дашборд
</pre>
<br>
<p><strong>Дашборд тренера:</strong></p>
<p>- Сводка по всем ученикам: таблица с сортировкой по любому столбцу</p>
<p>- Групповой график прогресса (все ученики на одном графике)</p>
<p>- Выделение отстающих (красная зона) и лидеров (зелёная зона)</p>
<p>- Уведомления: ученик не тренировался 3+ дня → алерт тренеру</p>
<p>- Экспорт сводного отчёта по группе</p>
<br>
<p><strong>Дашборд родителя:</strong></p>
<p>- Упрощённая версия: график прогресса ребёнка, счётчики</p>
<p>- Уведомления о новых достижениях и значках</p>
<p>- Еженедельный email-отчёт (опционально)</p>
<br>
<br>
<h2>6. База данных (основные таблицы)</h2>
<br>
<pre>users: id, login, password_hash, name, sport, role, birth_date, age,
country, city, club, coach, rank, goal, phone, email,
avatar_url, photo_url, stars, quiz_score, games_won,
created_at, updated_at
achievements: id, user_id, title, date, description
diary_entries: id, user_id, date, type, km, best_time, feel, note
events: id, user_id, title, date, location
messages: id, chat_id, from_user_id, to_user_id, text, read, created_at
chats: id, type (direct/group), name
chat_members: chat_id, user_id
vitamins: id, user_id, date, vitamin_type, taken
sleep_log: id, user_id, date, hours, pulse
tests: id, user_id, test_type, value, date
parent_links: parent_id, child_id
votes: voter_id, target_id, created_at
</pre>
<br>
<br>
<h2>7. Этапы разработки</h2>
<br>
<tr><th>Язык интерфейса</th><th>Русский</th></tr>
<tr><td>Адаптивность</td><td>Mobile-first, поддержка десктопа</td></tr>
<tr><td>Браузеры</td><td>Chrome 90+, Safari 14+, Firefox 90+</td></tr>
<tr><td>Производительность</td><td>First paint < 2 сек, взаимодействие < 100 мс</td></tr>
<tr><td>Доступность</td><td>WCAG 2.1 AA</td></tr>
<tr><td>Масштабируемость</td><td>До 100 000 пользователей</td></tr>
<tr><td>Резервное копирование</td><td>Ежедневный бэкап БД</td></tr>
<tr><td>Этап</td><td>Содержание</td><td>Срок</td></tr>
</table>
<table>
<br>
<p>**Итого:** ~10 недель на MVP командой из 2-3 разработчиков.</p>
<br>
<table>
<tr><th>1</th><th>База данных, API авторизации, регистрация</th><th>2 недели</th></tr>
<tr><td>2</td><td>Профиль, дневник, календарь</td><td>2 недели</td></tr>
<tr><td>3</td><td>Чаты (WebSocket) + игры</td><td>2 недели</td></tr>
<tr><td>4</td><td>Рейтинг, кабинет тренера, кабинет родителя</td><td>1 неделя</td></tr>
<tr><td>5</td><td>Инструменты (нормативы, сравнение, видео, витамины)</td><td>1 неделя</td></tr>
<tr><td>6</td><td>Админ-панель, PDF-отчёт</td><td>1 неделя</td></tr>
<tr><td>7</td><td>PWA, тестирование, деплой</td><td>1 неделя</td></tr>
</table>
</body>
</html>

414
TZ_GALIKON.md Normal file
View File

@ -0,0 +1,414 @@
# Техническое задание: Галикон
## 1. Общее описание
**Название:** Галикон — мобильное веб-приложение для спортсменов, тренеров и родителей.
**Цель:** Единая платформа для юных спортсменов (дети от 10 лет): дневник тренировок, контроль здоровья, рейтинги, чаты, игры, нормативы, сравнение с чемпионами. Аналогов в мире нет.
**Пользователи:**
- Спортсмен (основной пользователь)
- Тренер (видит своих учеников)
- Родитель (видит профиль ребёнка)
- Администратор (управление пользователями)
---
## 2. Технический стек
| Слой | Технология |
|------|-----------|
| Фронтенд | React / Vue 3 + TypeScript, PWA |
| Бэкенд | Node.js (Express/Fastify) или Go |
| База данных | PostgreSQL |
| Кэш | Redis |
| Файлы | S3-совместимое хранилище (MinIO) |
| Чат | WebSocket (Socket.io) |
| Push-уведомления | Firebase Cloud Messaging / Web Push API |
| Авторизация | JWT + refresh tokens |
| Хостинг | Docker + Kubernetes или VPS |
---
## 3. Функциональные требования
### 3.1. Регистрация и вход
**Регистрация — 8 шагов:**
1. ФИО (string, обязательно)
2. Логин (латиница, уникальный) + пароль (хеширование bcrypt, минимум 6 символов)
3. Вид спорта (select из 39 олимпийских видов)
4. Роль: спортсмен / тренер / родитель (если родитель — поле «Имя ребёнка»)
5. Дата рождения → возраст вычисляется автоматически. Аватарка (эмодзи на выбор) или загрузка фото (JPEG/PNG, макс 5 МБ)
6. Страна (select) → город (datalist с подсказками по стране)
7. Клуб, тренер (ФИО), разряд/звание, цель (произвольный текст)
8. Телефон (обязательно, валидация формата) + Email (обязательно)
**Вход:**
- Логин + пароль
- JWT access token (15 мин) + refresh token (30 дней)
- Rate limiting: 5 попыток → блокировка на 1 минуту
- Автовыход через 30 минут бездействия
**Безопасность:**
- Пароли: bcrypt с солью
- CSP-заголовки
- Санитизация всех пользовательских вводов (XSS-защита)
- HTTPS обязательно
- CORS только для доверенных доменов
---
### 3.2. Профиль спортсмена
**Отображение:**
- Аватар, ФИО, вид спорта, роль
- Дата рождения, возраст, страна, город
- Клуб, тренер, разряд, цель
- Телефон, email
**Значки (геймификация):**
Автоматический подсчёт по данным пользователя:
- 🏊 Первая тренировка (1+ запись в дневнике)
- 📖 10 тренировок
- 🔥 30 тренировок
- 🏆 Рекордсмен (есть достижения)
- 🎯 Снайпер (победа в игре «Угадай число»)
- ⚡ Молния (реакция < 300 мс)
- 🧠 Знаток (викторина 5+/8)
- 💪 100 км (суммарный километраж > 100)
**Достижения:**
Пользователь добавляет: название, дата, описание. Отображаются списком.
**Отчёт для тренера (PDF):**
- Генерация PDF на сервере (Puppeteer / wkhtmltopdf)
- Содержит: ФИО, спорт, клуб, тренер, разряд, цель, значки, достижения, последние 10 записей дневника
---
### 3.3. Дневник тренировок
**Поля записи:**
- Дата (date, обязательно)
- Тип тренировки (select: Скорость / Техника / Выносливость / ОФП / Соревнование)
- Километраж (число, км)
- Лучшее время (строка)
- Самочувствие (1-5)
- Заметка (текст)
**История:**
- Список записей, сортировка по дате (новые сверху)
- Удаление записи
**Агрегация (для тренера):**
- Всего тренировок
- Суммарный километраж
- Среднее самочувствие
- График прогресса по времени (библиотека Chart.js)
---
### 3.4. Календарь соревнований
**Добавление события:**
- Название (string)
- Дата (date)
- Место (string)
**Отображение:**
- Предстоящие (сортировка по дате)
- Прошедшие (сортировка по дате, обратная)
**Дополнительно (желательно):**
- Push-уведомление за день до события
- Цветовое кодирование по типу (соревнование / сборы / тренировка)
---
### 3.5. Чаты
**Архитектура:**
- WebSocket-соединение (Socket.io)
- Комнаты: личные (1-на-1), групповые
- Сообщения хранятся в PostgreSQL
- Индикатор «прочитано/не прочитано»
**Функции:**
- Список чатов с другими пользователями
- Фильтр по роли: Все / Спортсмены / Тренеры / Родители
- Отправка текстовых сообщений
- Счётчик непрочитанных
- Групповые чаты (создание, добавление участников)
**Встроенные игры (в чате):**
1. **Крестики-нолики** — пошаговая игра, синхронизация через WebSocket
2. **Угадай число (1-100)** — 7 попыток, победа < 5 попыток = +2 звезды
3. **Реакция** — измерение времени реакции, рекорд < 300 мс = +1 звезда
4. **Спорт-викторина** — 8 вопросов, результат 5+/8 = +1-5 звёзд
---
### 3.6. Рейтинговая система
**Звёзды начисляются за:**
- Победы в играх
- Высокие результаты викторины
- Голоса других пользователей
**Рейтинг:**
- Топ-5 спортсменов по звёздам
- Отображение: место, ФИО, звёзды, результаты викторины, победы в играх
- Топ-3 выделены золотом/серебром/бронзой
---
### 3.7. Инструменты
**Нормативы:**
- Статическая таблица разрядов по плаванию (50 м бассейн): МСМК → 2 юношеский
- Дистанции: 50 м, 100 м, 400 м вольный стиль
**Сравнение с чемпионами:**
- Данные Калеба Дрессела по возрастам (14-18 лет)
- Пользователь вводит своё время и возраст → сравнение
- Показывает: текущий результат → КМС → результат Дрессела в этом возрасте
**Анализ видео:**
- Загрузка видео (MP4, макс 200 МБ)
- Плеер с покадровой перемоткой (шаг 0.033 сек, 0.1 сек, 1 сек)
- Счётчик текущего кадра
- Play/Pause
**Витамины:**
- Чек-лист на сегодня: D3, Омега-3, Магний, Цинк, BCAA
- Сохранение истории по дням
**Сон и пульс:**
- Запись часов сна и утреннего пульса
- Средние значения за 7 дней
**Анализы:**
- Гемоглобин, Ферритин, Витамин D, Витамин B12
- История значений с датами
**Видеоуроки:**
- Список поисковых запросов для YouTube (12 тем по технике плавания)
---
### 3.8. Кабинет тренера
**Поиск учеников:**
- Автоматически: все пользователи, у которых поле «Тренер» совпадает с ФИО тренера
**Отображение по каждому ученику:**
- Аватар, ФИО, вид спорта, разряд, цель
- Суммарный километраж
- Последние 5 тренировок (дата, тип, км, время)
---
### 3.9. Кабинет родителя
**Привязка ребёнка:**
- Родитель вводит логин ребёнка → привязка (сохраняется в профиле родителя)
**Отображение:**
- Профиль ребёнка (как у спортсмена)
- Статистика: всего тренировок, км, среднее самочувствие
- Значки ребёнка
- Дневник тренировок (последние 15 записей)
- Цель и тренер ребёнка
- Кнопка «Отвязать»
---
### 3.10. Админ-панель
**Доступ:**
- Отдельный мастер-пароль администратора
**Функции:**
- Просмотр всех пользователей (ФИО, роль, логин, спорт, клуб, звёзды)
- Удаление пользователя
- Сброс пароля пользователя
---
### 3.11. PWA (Progressive Web App)
**Требования:**
- manifest.json с иконками (192x192, 512x512)
- Service Worker для офлайн-доступа
- Установка на домашний экран (iOS/Android)
- Режим standalone (без адресной строки браузера)
- Splash screen на iOS
---
## 4. Нефункциональные требования
| Параметр | Значение |
|----------|---------|
| Язык интерфейса | Русский |
| Адаптивность | Mobile-first, поддержка десктопа |
| Браузеры | Chrome 90+, Safari 14+, Firefox 90+ |
| Производительность | First paint < 2 сек, взаимодействие < 100 мс |
| Доступность | WCAG 2.1 AA |
| Масштабируемость | До 100 000 пользователей |
| Резервное копирование | Ежедневный бэкап БД |
---
## 5. API (основные эндпоинты)
```
POST /api/auth/register — регистрация
POST /api/auth/login — вход
POST /api/auth/refresh — обновление токена
GET /api/profile — профиль текущего пользователя
PUT /api/profile — обновление профиля
GET /api/profile/:id — профиль другого пользователя
POST /api/achievements — добавить достижение
GET /api/diary — дневник (список)
POST /api/diary — новая запись
DELETE /api/diary/:id — удалить запись
GET /api/events — календарь
POST /api/events — добавить событие
DELETE /api/events/:id — удалить событие
GET /api/chats — список чатов
GET /api/chats/:id/messages — сообщения чата
POST /api/chats/:id/messages — отправить сообщение
WS /ws/chat — WebSocket для чата
POST /api/vote/:userId — проголосовать за пользователя
GET /api/ranking — рейтинг (топ)
GET /api/coach/students — ученики тренера
POST /api/parent/link — привязать ребёнка
GET /api/admin/users — список пользователей (админ)
DELETE /api/admin/users/:id — удалить пользователя (админ)
POST /api/admin/users/:id/reset-password — сброс пароля (админ)
GET /api/report/pdf — PDF-отчёт для тренера
POST /api/upload/avatar — загрузка аватара
POST /api/upload/video — загрузка видео
POST /api/upload/photo — загрузка фото
```
---
### 3.12. Аналитика и дашборды
**Дашборд спортсмена — главный экран аналитики:**
**График прогресса (50 м в/с):**
- Линейный график: дата по оси X, время по оси Y
- Целевая линия (23″) и текущая линия тренда
- Автоматический расчёт скорости прогресса (секунд в месяц)
- Прогноз: когда будет достигнута цель при текущем темпе
**Радарная диаграмма навыков:**
- 6 осей: старт, поворот, подводная фаза, гребок, выносливость, финиш
- Оценки 1-10 выставляет тренер или сам спортсмен
- Сравнение с предыдущим месяцем
**Круговые диаграммы тренировок:**
- Распределение по типам: скорость / техника / выносливость / ОФП
- За текущий месяц и за всё время
**Тепловая карта активности:**
- Календарь GitHub-style: каждый день — квадратик
- Цвет зависит от километража (0 — серый, 5+ км — ярко-голубой)
- Видно пропуски тренировок и интенсивные периоды
**Счётчики (KPI):**
- Всего тренировок, общий километраж, лучший результат
- Среднее самочувствие, динамика пульса, средний сон
- Недельная/месячная нагрузка
**Сравнительная аналитика:**
- Сравнение своего прогресса со средним по возрастной группе
- Сравнение с товарищами по клубу (анонимно)
- Процентиль: «Ты быстрее 78% пловцов твоего возраста»
**Экспорт данных:**
- CSV-выгрузка всех тренировок
- Excel-отчёт с графиками (автоматическая генерация)
- PDF-дашборд для тренера
**Технологии:**
- Chart.js / ECharts / D3.js для визуализации
- Данные агрегируются на бэкенде (SQL-запросы с GROUP BY)
- Кэширование агрегаций в Redis (обновление раз в час)
**API для аналитики:**
```
GET /api/analytics/progress/:metric — график прогресса по метрике
GET /api/analytics/radar — радарная диаграмма
GET /api/analytics/heatmap — тепловая карта (год)
GET /api/analytics/distribution — распределение типов тренировок
GET /api/analytics/kpi — ключевые показатели
GET /api/analytics/compare — сравнение с группой
GET /api/analytics/export/csv — CSV-выгрузка
GET /api/analytics/export/dashboard — PDF-дашборд
```
**Дашборд тренера:**
- Сводка по всем ученикам: таблица с сортировкой по любому столбцу
- Групповой график прогресса (все ученики на одном графике)
- Выделение отстающих (красная зона) и лидеров (зелёная зона)
- Уведомления: ученик не тренировался 3+ дня → алерт тренеру
- Экспорт сводного отчёта по группе
**Дашборд родителя:**
- Упрощённая версия: график прогресса ребёнка, счётчики
- Уведомления о новых достижениях и значках
- Еженедельный email-отчёт (опционально)
---
## 6. База данных (основные таблицы)
```sql
users: id, login, password_hash, name, sport, role, birth_date, age,
country, city, club, coach, rank, goal, phone, email,
avatar_url, photo_url, stars, quiz_score, games_won,
created_at, updated_at
achievements: id, user_id, title, date, description
diary_entries: id, user_id, date, type, km, best_time, feel, note
events: id, user_id, title, date, location
messages: id, chat_id, from_user_id, to_user_id, text, read, created_at
chats: id, type (direct/group), name
chat_members: chat_id, user_id
vitamins: id, user_id, date, vitamin_type, taken
sleep_log: id, user_id, date, hours, pulse
tests: id, user_id, test_type, value, date
parent_links: parent_id, child_id
votes: voter_id, target_id, created_at
```
---
## 7. Этапы разработки
| Этап | Содержание | Срок |
|------|-----------|------|
| 1 | База данных, API авторизации, регистрация | 2 недели |
| 2 | Профиль, дневник, календарь | 2 недели |
| 3 | Чаты (WebSocket) + игры | 2 недели |
| 4 | Рейтинг, кабинет тренера, кабинет родителя | 1 неделя |
| 5 | Инструменты (нормативы, сравнение, видео, витамины) | 1 неделя |
| 6 | Админ-панель, PDF-отчёт | 1 неделя |
| 7 | PWA, тестирование, деплой | 1 неделя |
**Итого:** ~10 недель на MVP командой из 2-3 разработчиков.

110
design.md Normal file
View File

@ -0,0 +1,110 @@
<!-- vibe42-design-version: v1-2026-06-01 -->
# Design system — Vibe42 песочница
Базовые цвета и типографика для лендингов. Можно отклоняться, но начинай с этого.
## Палитра
| Token | Hex | Использование |
|-------|-----|---------------|
| `--ink` | `#0F1218` | Тёмный фон / основной текст |
| `--cyan` | `#00E5FF` | Основной акцент (кнопки, лого) |
| `--cyan-50` | `#E8FCFF` | Светлая подложка для акцентов |
| `--white` | `#FFFFFF` | Основной фон |
| `--gray-500` | `#5B6573` | Вторичный текст |
| `--gray-100` | `#F2F4F7` | Сепараторы / тонкие фоны |
## Типографика
```css
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif;
```
| Уровень | Размер | Вес | line-height |
|---------|--------|-----|-------------|
| h1 (hero) | 56px | 800 | 1.05 |
| h2 (section) | 36px | 700 | 1.15 |
| h3 | 22px | 700 | 1.3 |
| body | 17px | 400 | 1.6 |
| small | 14px | 400 | 1.5 |
На мобиле — h1 уменьши до 36px, h2 до 28px.
## Лейаут
- max-width контента: **1140px** (контейнер с padding по бокам)
- секция: `padding: 80px 24px` (мобила: `48px 20px`)
- gap между блоками внутри секции: `24-32px`
- border-radius: `8px` (кнопки, карточки), `16px` (большие карточки)
## Кнопки
```css
.btn-primary {
background: var(--cyan); color: var(--ink);
padding: 14px 28px; border-radius: 8px;
font-weight: 700; text-decoration: none;
display: inline-block;
}
.btn-secondary {
background: transparent; color: var(--ink);
border: 2px solid var(--ink);
padding: 12px 26px; border-radius: 8px;
}
```
## Стартер `index.html`
```html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Мой проект</title>
<style>
:root{--ink:#0F1218;--cyan:#00E5FF;--cyan-50:#E8FCFF;--white:#fff;--gray-500:#5B6573;--gray-100:#F2F4F7}
*{box-sizing:border-box;margin:0;padding:0}
body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;color:var(--ink);background:var(--white)}
.container{max-width:1140px;margin:0 auto;padding:80px 24px}
.hero{background:var(--ink);color:var(--white)}
.hero h1{font-size:56px;font-weight:800;line-height:1.05;margin-bottom:24px}
.hero p{font-size:20px;color:#9aa3b2;max-width:600px;margin-bottom:32px}
.btn{display:inline-block;background:var(--cyan);color:var(--ink);padding:14px 28px;border-radius:8px;font-weight:700;text-decoration:none}
.btn:hover{background:#1be5ff}
.section h2{font-size:36px;font-weight:700;margin-bottom:24px}
.card{background:var(--gray-100);border-radius:16px;padding:32px;margin-bottom:16px}
@media (max-width:640px){.hero h1{font-size:36px}.section h2{font-size:28px}.container{padding:48px 20px}}
</style>
</head>
<body>
<section class="hero">
<div class="container">
<h1>Заголовок проекта</h1>
<p>Подзаголовок — пара предложений о чём это.</p>
<a class="btn" href="#section">Начать</a>
</div>
</section>
<section id="section" class="section">
<div class="container">
<h2>Секция</h2>
<div class="card">Контент карточки.</div>
<div class="card">Контент карточки.</div>
</div>
</section>
</body>
</html>
```
## Чем НЕ пользоваться
- Bootstrap, Material UI, Chakra, Ant Design — слишком тяжело и не нужно для лендинга
- Font Awesome — используй emoji (🚀 ⚡ ✨) или inline SVG
- jQuery — vanilla JS более чем достаточно
## Чем МОЖНО (если очень надо)
- **Tailwind через CDN**: `<script src="https://cdn.tailwindcss.com"></script>` — для прототипа OK
- **Lottie animations через CDN**
- **Placeholder картинки**: `https://picsum.photos/800/600`, `https://placehold.co/600x400`
- **Шрифты Google Fonts через `<link>`** в head

1515
index.html Normal file

File diff suppressed because it is too large Load Diff

1
manifest.json Normal file
View File

@ -0,0 +1 @@
{"name":"Галикон","short_name":"Галикон","description":"Приложение для спортсменов — дневник тренировок, здоровье, рейтинги","start_url":".","display":"standalone","background_color":"#0F1218","theme_color":"#00E5FF","icons":[{"src":"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%230F1218'/><text y='.9em' font-size='70' x='50' text-anchor='middle'>🏊</text></svg>","sizes":"any","type":"image/svg+xml"}]}

11
sw.js Normal file
View File

@ -0,0 +1,11 @@
self.addEventListener('install', e => { self.skipWaiting() })
self.addEventListener('activate', e => { e.waitUntil(clients.claim()) })
self.addEventListener('fetch', e => {
e.respondWith(
caches.match(e.request).then(r => r || fetch(e.request).then(res => {
const clone = res.clone()
caches.open('galikon-v1').then(c => c.put(e.request, clone))
return res
}).catch(() => caches.match(e.request)))
)
})

View File

@ -0,0 +1,131 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Мотивационный отчёт — Кайрат Гали</title>
<style>
body{font:16px/1.7 Arial,sans-serif;max-width:750px;margin:30px auto;padding:20px;color:#1a1a1a;background:#fff}
h1{font-size:30px;border-bottom:4px solid #FF4D00;padding-bottom:12px}
h1 span{color:#FF4D00}
h2{font-size:20px;margin-top:28px;color:#FF4D00;border-left:4px solid #FF4D00;padding-left:14px}
.stats{display:flex;gap:16px;flex-wrap:wrap;margin:20px 0}
.stat{background:linear-gradient(135deg,#fff5f0,#fff);border:1px solid #fdd;border-radius:14px;padding:18px 24px;min-width:110px;text-align:center}
.stat .num{font-size:32px;font-weight:900;color:#FF4D00}
.stat .lbl{font-size:11px;color:#888;text-transform:uppercase;letter-spacing:.5px;margin-top:4px}
.rec{background:#fff;border:1px solid #eee;border-radius:10px;padding:16px 20px;margin:10px 0;border-left:4px solid #FF4D00;font-size:15px}
.moto{background:linear-gradient(135deg,#FF4D00,#ff6b33);color:#fff;padding:24px 28px;border-radius:16px;margin:24px 0;font-size:20px;font-weight:800;text-align:center;line-height:1.5}
.goal-box{background:linear-gradient(135deg,#0a0a0a,#1a1a1a);color:#fff;padding:28px;border-radius:16px;margin:20px 0;text-align:center}
.goal-box .from-to{font-size:48px;font-weight:900}
.goal-box .from-to span{color:#FF4D00}
.goal-box .sub{color:#888;font-size:14px;margin-top:8px}
table{width:100%;border-collapse:collapse;margin:12px 0}
th,td{padding:10px 12px;text-align:left;border-bottom:1px solid #eee}
th{color:#888;font-size:12px;text-transform:uppercase}
.step{display:flex;gap:16px;align-items:flex-start;margin:12px 0;padding:16px;background:#fafafa;border-radius:12px}
.step .num{width:36px;height:36px;border-radius:8px;background:#FF4D00;color:#fff;display:flex;align-items:center;justify-content:center;font-weight:900;font-size:18px;flex-shrink:0}
.step .body h4{margin:0 0 4px;font-size:15px}
.step .body p{margin:0;font-size:13px;color:#666}
@media print{body{margin:0;padding:10px}}
</style>
</head>
<body>
<h1>&#x1F3CA; Мотивационный отчёт<br><span>Кайрат Гали Аскарович</span></h1>
<p style="color:#666">Плавание · QazSwimAcademy · 14 лет · 8 класс</p>
<p style="color:#888;font-size:14px">1-й детский разряд · 3-й взрослый разряд</p>
<div class="goal-box">
<div class="from-to">34″ <span>&#x2192;</span> 23″</div>
<div class="sub">50 метров вольным стилем — твоя главная цель</div>
</div>
<div class="stats">
<div class="stat"><div class="num">3</div><div class="lbl">Золота Олимпиады<br>(будущая цель)</div></div>
<div class="stat"><div class="num">5</div><div class="lbl">Мировых рекордов<br>(потенциал)</div></div>
<div class="stat"><div class="num">12</div><div class="lbl">Лет в спорте</div></div>
</div>
<h2>&#x1F4CA; Текущие результаты</h2>
<table>
<tr><th>Дистанция</th><th>Стиль</th><th>Результат</th><th>Прогресс</th></tr>
<tr><td>50 м</td><td>Вольный стиль</td><td><strong>34.00″</strong></td><td>3 взр. разряд ✓</td></tr>
<tr><td>100 м</td><td>Вольный стиль</td><td>1:22.94</td><td>Цель: 1:10</td></tr>
<tr><td>400 м</td><td>Вольный стиль</td><td>7:09.64</td><td>116 место на Весёлый Дельфин</td></tr>
<tr><td>50 м</td><td>Брасс</td><td>48.00″</td><td>Второй стиль</td></tr>
<tr><td>100 м</td><td>Брасс</td><td>1:52.17</td><td>41 место</td></tr>
</table>
<h2>&#x1F3AF; План: 34″ → 23″</h2>
<div class="step">
<div class="num">1</div>
<div class="body"><h4>Закрепиться на 32″ (месяц 1-2)</h4><p>Перестать бороться с водой. Отработать скольжение. Каждую тренировку — 4×50 м. Записывать лучшее время дня.</p></div>
</div>
<div class="step">
<div class="num">2</div>
<div class="body"><h4>Выйти из 30″ (месяц 3-4)</h4><p>Добавить 2 спринтерские тренировки в неделю. Частота гребков 50+ циклов в минуту. Планка 3 мин, скручивания.</p></div>
</div>
<div class="step">
<div class="num">3</div>
<div class="body"><h4>Штурм 27″ — КМС (месяц 5-8)</h4><p>Объём воды 20+ км в неделю. Старт с тумбы 15 мин каждую тренировку. Первые 15 метров — ключ к скорости.</p></div>
</div>
<div class="step">
<div class="num">4</div>
<div class="body"><h4>Пробить 25″ (месяц 9-12)</h4><p>3 скоростные тренировки в неделю. Контрольные старты каждые 2 недели. Подводная съёмка.</p></div>
</div>
<div class="step">
<div class="num">5</div>
<div class="body"><h4>Цель: 23″ — МС (месяц 13-18)</h4><p>Сборы, соревнования. Выход на республиканский уровень. Последние 5 метров без вдоха.</p></div>
</div>
<h2>&#x1F4DD; Персональные рекомендации</h2>
<div class="rec">&#x1F6A8; <strong>Старт и выход</strong> — ты теряешь 1-1.5″. 10 стартов с тумбы каждую тренировку. Дельфиньи удары под водой — минимум 5.</div>
<div class="rec">&#x1F504; <strong>Поворот</strong> — ты теряешь 0.5-1.0″. Не замедляйся перед стенкой — ускоряйся. Считай гребки от флажков.</div>
<div class="rec">&#x1F4C9; <strong>100 м: провал на второй половине</strong> — вторые 50 м на 15″ хуже. Плыви серии 4×75 м с удержанием темпа.</div>
<div class="rec">&#x1F4CF; <strong>Длинный гребок</strong> — на 400 м ты плывёшь 1:47/100 м. Цель: 38-42 гребка на 50 м. Бери лопатки и колобашку.</div>
<div class="rec">&#x1F4A4; <strong>Восстановление</strong> — 5 мин растяжки после каждой тренировки. Контрастный душ. Массажный ролик вечером.</div>
<h2>&#x1F30D; Твой путь к NCAA</h2>
<div class="step">
<div class="num">13</div>
<div class="body"><h4>Сейчас (14 лет)</h4><p>Английский 3 раза в неделю. Снимать каждый старт на видео. GPA 4.0+.</p></div>
</div>
<div class="step">
<div class="num">15</div>
<div class="body"><h4>Через 1 год</h4><p>Swimcloud.com. TOEFL 60+. 50 м в/с за 29-31″.</p></div>
</div>
<div class="step">
<div class="num">16</div>
<div class="body"><h4>Через 2 года</h4><p>TOEFL 80+. NCSA. Письма тренерам 15-20 университетов. 50 м в/с за 25-26″.</p></div>
</div>
<div class="step">
<div class="num">18</div>
<div class="body"><h4>Выпускной класс</h4><p>Стипендия $40-70 тыс/год. Stanford, Texas, Cal Berkeley. National Letter of Intent.</p></div>
</div>
<h2>&#x1F3C6; Международные старты</h2>
<table>
<tr><th>Год</th><th>Возраст</th><th>Турнир</th><th>Цель</th></tr>
<tr><td>2026</td><td>14</td><td>Весёлый Дельфин — этапы 1-3</td><td>34″ → 32″</td></tr>
<tr><td>2027</td><td>15</td><td>Чемпионат РК + Кубок Сальникова</td><td>Призёр, 31″ → 29″</td></tr>
<tr><td>2028</td><td>16</td><td>Чемпионат Азии среди юниоров</td><td>Медаль, 29″ → 27″</td></tr>
<tr><td>2029</td><td>17</td><td>FINA World Juniors + Азиатские игры</td><td>Полуфинал, 27″ → 25″</td></tr>
<tr><td>2030</td><td>18</td><td>Чемпионат мира FINA</td><td>Полуфинал, 25″ → 23″</td></tr>
<tr><td>2032</td><td>20</td><td>Олимпийские игры — Брисбен</td><td>Участие, 23″ → 22″</td></tr>
</table>
<div class="moto" style="margin-top:28px">
«Ты уже быстрее 90% детей твоего возраста в Казахстане.<br>
До КМС — 9 секунд. До NCAA — 4 года.<br>
До Олимпиады — 6 лет.<br><br>
Каждый день на тренировке — это шаг к мечте.<br>
<strong>Не останавливайся.</strong>»
</div>
<p style="text-align:center;color:#999;font-size:12px;margin-top:24px">Отчёт сгенерирован в Галиконе · Июнь 2026</p>
</body>
</html>