diff --git a/project/ADR.md b/project/ADR.md new file mode 100644 index 0000000..3292cd4 --- /dev/null +++ b/project/ADR.md @@ -0,0 +1,350 @@ +# ADR: Архитектура сайта de-roadmap + +> Архитектурный документ. Проектные цели и требования — в [PRD](./PRD.md). + +--- + +## 1. Ключевые архитектурные требования + +Из PRD вытекают четыре жёстких ограничения, определяющих выбор инструментов: + +1. **Сайт опционален.** Репозиторий должен полноценно работать без сайта. Удалили конфиг — всё как было. +2. **Dual-compatible links.** Внутренние ссылки между `.md` файлами должны работать и на GitHub, и на сайте. +3. **Один файл = один источник правды.** Не должно быть копий или генерируемых `.md`. Редактируем один раз — рендерится везде. +4. **Zero-effort deploy.** Push в `main` → сайт обновился. Без ручных шагов, без локальной сборки. + +--- + +## 2. Выбор генератора статического сайта + +### Рассмотренные варианты + +| Критерий | MkDocs Material | Docusaurus | Hugo | Astro | +|----------|----------------|------------|------|-------| +| Язык/экосистема | Python | Node.js (React) | Go | Node.js | +| Порог входа | Минимальный — `pip install`, один YAML | Средний — npm, React-компоненты | Средний — Go templates | Высокий — фреймворк | +| Поддержка Markdown «как есть» | Отличная, расширения через плагины | Хорошая, но MDX-ориентирован | Хорошая, но shortcodes вместо стандартного MD | Хорошая | +| Навигация по длинной странице | TOC sidebar из коробки | Есть, но заточен под многостраничность | Зависит от темы | Зависит от темы | +| Поиск | Встроенный (lunr.js), работает offline | Algolia (внешний сервис) или плагин | Нет из коробки | Нет из коробки | +| Тёмная тема | Из коробки, переключатель | Из коробки | Зависит от темы | Зависит от темы | +| GitHub Pages деплой | Одна команда / готовый Action | Готовый Action | Готовый Action | Готовый Action | +| Dual-compatible links | Поддерживает с настройкой `use_directory_urls` | Преобразует ссылки, может ломать GitHub | Преобразует ссылки | Преобразует ссылки | +| Один мейнтейнер, Python-стек | ✅ Идеально | ❌ Node.js | ⚠️ Go, но бинарник | ❌ Node.js | + +### Решение: MkDocs Material + +**Почему:** + +- Python-based — совпадает со стеком автора, `pip install` и готово. +- Лучшая из коробки поддержка длинных страниц с TOC — именно наш сценарий. +- Встроенный поиск без внешних сервисов. +- Самый простой конфиг — один `mkdocs.yml`. +- Крупнейшее комьюнити среди генераторов документации, активно развивается. +- Dual-compatible links решаемы (см. раздел 4). + +**Почему не Docusaurus:** Node.js-зависимость, ориентирован на многостраничные доки с MDX-компонентами — overkill для «красивый рендер Markdown». Преобразование ссылок может конфликтовать с GitHub-форматом. + +**Почему не Hugo:** Быстрый, но Go-шаблоны сложнее отлаживать. Нет встроенного поиска. Для нашего объёма контента скорость сборки не критична. + +**Почему не Astro:** Полноценный веб-фреймворк — избыточен. Подошёл бы, если бы мы строили маркетинговый сайт с интерактивом, но это не текущая цель. + +--- + +## 3. Структура файлов + +### Решение открытого вопроса: `docs/` vs корень репо + +**Решение: `docs_dir: .` (корень репо = корень сайта), с исключениями.** + +Причина: не создаём отдельную папку `docs/`, не дублируем и не перемещаем файлы. MkDocs умеет работать с корнем репо как источником, исключая ненужное. + +```yaml +# mkdocs.yml (в корне репо) +docs_dir: . +``` + +### Решение открытого вопроса: README.md как index + +**Решение: плагин `awesome-pages` или конфигурация `nav` с явным указанием.** + +MkDocs по умолчанию ищет `index.md`. Но мы хотим сохранить `README.md` (GitHub его рендерит на главной репо). Есть два пути: + +- **Вариант A:** Симлинк `docs/index.md → ../README.md`. Но мы не используем `docs/`. +- **Вариант B (выбран):** В `mkdocs.yml` явно указать `README.md` как главную: + +```yaml +nav: + - Роадмап: README.md + - Моделирование данных: + - Введение: dwh-modeling/README.md + - SCD: dwh-modeling/SCD.md + - Data Vault: dwh-modeling/DataVault.md + - "Домашка: STG → DDS → DM": dwh-modeling/Homework_Customer_Status_DDS_DM.md +``` + +MkDocs Material корректно обрабатывает `README.md` файлы — рендерит их как `index.html` соответствующей директории. + +### Исключения из сборки + +Файлы и папки, которые не должны попасть на сайт: + +```yaml +exclude_docs: | + project/ # проектная документация (PRD, ADR) + postgres-bookings/ # скрипты стенда (не контент сайта) + AGENTS.md # конфигурация для AI-агентов + LICENSE # лицензия (есть в footer) + .gitignore +``` + +### Итоговая структура репо + +``` +de-roadmap/ +├── mkdocs.yml ← конфиг сайта (единственный новый файл в корне) +├── README.md ← главная страница сайта И главная страница GitHub +├── dwh-modeling/ +│ ├── README.md ← подстраница «Введение в DWH» +│ ├── SCD.md ← подстраница +│ ├── DataVault.md ← подстраница +│ └── Homework_*.md ← подстраница +├── postgres-bookings/ ← исключён из сайта +├── project/ ← PRD, ADR — исключены из сайта +│ ├── PRD.md +│ └── ADR.md +├── .github/ +│ └── workflows/ +│ └── deploy-site.yml ← CI/CD pipeline +├── AGENTS.md ← исключён из сайта +└── LICENSE +``` + +--- + +## 4. Стратегия ссылок (Dual Compatibility) + +### Проблема + +GitHub рендерит ссылки вида `[текст](dwh-modeling/SCD.md)` как переход к файлу. +MkDocs по умолчанию преобразует `.md` → `.html` и может менять структуру URL. + +### Решение + +Комбинация настроек MkDocs: + +```yaml +use_directory_urls: true # /dwh-modeling/SCD/ вместо /dwh-modeling/SCD.html +``` + +И ссылки в Markdown пишем **всегда как относительные пути к `.md` файлам**: + +```markdown + +[Теория про SCD](dwh-modeling/SCD.md) +[Введение в DWH](dwh-modeling/README.md) +``` + +MkDocs Material автоматически резолвит `.md` ссылки в правильные URL сайта. + +### Кириллические якоря + +GitHub генерирует якоря из кириллических заголовков с URL-encoding: +`## Базы данных` → `#базы-данных` + +MkDocs Material по умолчанию делает то же самое через расширение `toc`: + +```yaml +markdown_extensions: + - toc: + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower + permalink: true +``` + +**Риск:** поведение может различаться на edge cases (спецсимволы, эмодзи в заголовках). Митигация — на этапе MVP протестировать все существующие якорные ссылки в README. + +--- + +## 5. CI/CD Pipeline + +### GitHub Actions Workflow + +```yaml +# .github/workflows/deploy-site.yml +name: Deploy MkDocs to GitHub Pages + +on: + push: + branches: [main] + workflow_dispatch: # ручной запуск для отладки + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - run: pip install mkdocs-material + + - run: mkdocs build --strict + # --strict: падает на warnings (битые ссылки, отсутствующие файлы) + + - uses: actions/upload-pages-artifact@v3 + with: + path: site/ + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 +``` + +### Что даёт `--strict` + +Сборка упадёт, если: +- Есть ссылка на несуществующий `.md` файл. +- Есть битый якорь. +- Есть warning от MkDocs. + +Это наш автотест ссылок — бесплатно, в CI. + +--- + +## 6. Конфигурация MkDocs Material + +### Минимальный `mkdocs.yml` для MVP + +```yaml +site_name: "DE Roadmap — Data Engineering с нуля до middle" +site_url: https://dementev-dev.github.io/de-roadmap/ +site_description: "Роадмап по Data Engineering: SQL, Python, Airflow, Greenplum и далее" +site_author: Dmitry Dementev + +repo_url: https://github.com/dementev-dev/de-roadmap +repo_name: dementev-dev/de-roadmap + +docs_dir: . +site_dir: site + +# Исключаем из сборки +exclude_docs: | + project/ + postgres-bookings/ + AGENTS.md + LICENSE + .gitignore + .github/ + site/ + +nav: + - Роадмап: README.md + - Моделирование данных: + - Введение: dwh-modeling/README.md + - SCD: dwh-modeling/SCD.md + - Data Vault: dwh-modeling/DataVault.md + - "Домашка: STG → DDS → DM": dwh-modeling/Homework_Customer_Status_DDS_DM.md + +theme: + name: material + language: ru + palette: + - scheme: default + primary: indigo + accent: indigo + toggle: + icon: material/brightness-7 + name: Тёмная тема + - scheme: slate + primary: indigo + accent: indigo + toggle: + icon: material/brightness-4 + name: Светлая тема + features: + - navigation.top # кнопка «наверх» + - navigation.tracking # URL обновляется при скролле + - search.suggest # подсказки в поиске + - search.highlight # подсветка найденного + - toc.follow # TOC следит за скроллом + - content.code.copy # кнопка копирования кода + +markdown_extensions: + - toc: + permalink: true + - admonition # сворачиваемые блоки (Спринт 2) + - pymdownx.details # для
+ - pymdownx.superfences # вложенные блоки кода + - pymdownx.highlight # подсветка синтаксиса + - attr_list # атрибуты для элементов + +plugins: + - search: + lang: ru +``` + +### Что уже включено в MVP (бесплатно с Material) + +- Тёмная/светлая тема с переключателем. +- Полнотекстовый поиск на русском. +- TOC (оглавление) в правом sidebar. +- Кнопка «наверх» на длинной странице. +- URL обновляется при скролле (можно дать ссылку на конкретный раздел). +- Подсветка синтаксиса в блоках кода. +- Кнопка копирования кода. +- Ссылка на GitHub-репозиторий в шапке. + +--- + +## 7. Кастомный домен (Спринт 2) + +Домен `dementev.space` уже есть. Для подключения: + +1. Создать CNAME-запись: `roadmap.dementev.space → dementev-dev.github.io`. +2. Добавить файл `CNAME` в корень репо с содержимым `roadmap.dementev.space`. +3. В `mkdocs.yml` обновить `site_url`. +4. Включить HTTPS в настройках GitHub Pages. + +--- + +## 8. Риски и митигации + +| Риск | Митигация | +|------|-----------| +| `docs_dir: .` подхватывает лишние файлы | `exclude_docs` со списком исключений; `--strict` ловит проблемы | +| Кириллические якоря ведут себя по-разному | Тестируем все якорные ссылки из README при первом деплое | +| `README.md` содержит GitHub-специфичный синтаксис | Проверяем рендер; при необходимости используем MkDocs-совместимые альтернативы | +| Зависимость от `mkdocs-material` | Активный проект (30k+ stars), Python-пакет; при необходимости — заморозить версию в `requirements.txt` | +| `exclude_docs` — относительно новая фича MkDocs | Альтернатива: `.mkdocsignore` или плагин `mkdocs-exclude`; протестировать на MVP | + +--- + +## 9. Порядок действий (Спринт 1) + +1. Создать ветку `feature/site`. +2. Добавить `mkdocs.yml` в корень репо. +3. Добавить `.github/workflows/deploy-site.yml`. +4. Добавить `project/PRD.md` и `project/ADR.md`. +5. Проверить локально: `pip install mkdocs-material && mkdocs serve`. +6. Протестировать все внутренние ссылки и якоря. +7. При необходимости — адаптировать ссылки для dual compatibility. +8. Merge в `main` → автодеплой → проверить `https://dementev-dev.github.io/de-roadmap/`. +9. Включить GitHub Pages (Settings → Pages → Source: GitHub Actions). diff --git a/project/PRD.md b/project/PRD.md new file mode 100644 index 0000000..89c995d --- /dev/null +++ b/project/PRD.md @@ -0,0 +1,168 @@ +# PRD: Сайт для de-roadmap + +> Проектный документ. Техническая архитектура — в отдельном ADR. + +--- + +## 1. Контекст и мотивация + +### Текущее состояние + +Роадмап по Data Engineering живёт как GitHub-репозиторий ([dementev-dev/de-roadmap](https://github.com/dementev-dev/de-roadmap)): + +- Основной контент — монолитный `README.md` (~700 строк) с полным учебным планом. +- Дополнительные материалы — в подпапках (`dwh-modeling/`, `postgres-bookings/`): теория DWH-моделирования, SCD, Data Vault, домашние задания, скрипты. +- 109 коммитов, контент активно развивается. +- Основной поток менти приходит через маркетплейс ОМ (Осознанная Меркантильность) — платформу менторства с системой отзывов, ранжированием менторов и модерацией. Участие платное (абонентская плата + аукцион за позицию в выдаче). +- Роадмап изначально создавался для себя — как конспект подходов к обучению. Со временем стал использоваться и для менти (удобная структура прохождения), и на ознакомительных созвонах с лидами из ОМ (демонстрация программы и подхода к обучению). +- Отдельного маркетингового продвижения роадмапа не было, органических приходов «по ссылке из интернета» — ноль. Сайта ментора тоже пока нет — приходить некуда. + +### Проблема + +GitHub README — рабочий, но не презентабельный формат: + +- Нет удобной навигации по длинному документу (только ручной скролл или оглавление-ссылки). +- Выглядит как «техническая документация», а не как продукт ментора. +- GitHub README плохо индексируется поисковыми системами — роадмап в таком виде даже потенциально не может привлекать органический трафик и «продавать сам себя». +- Неудобно давать ссылку потенциальному менти — GitHub-интерфейс отвлекает (issues, commits, файловое дерево). +- Нет мобильной адаптации контента (GitHub на телефоне — страдание). + +### Чего НЕ решаем этим проектом + +- **Лидогенерацию и воронку продаж.** Основной поток тёплых лидов идёт через маркетплейс ОМ, и конкурировать с ним по объёму нереалистично — даже топовые менторы не добирают сравнимое количество лидов из других источников. В перспективе сайт может стать элементом маркетинговой воронки (Habr → сайт → менторство), но это отдалённая цель, не влияющая на текущие решения. Сейчас сайт — витрина экспертизы, а не маркетинговый инструмент. +- **Масштабирование менторского бизнеса.** Сейчас приоритет — выпустить текущих менти, а не набрать новых. +- **Создание LMS / интерактивного курса.** Формат остаётся «структурированный текст + ссылки», без трекинга прогресса и автопроверок. + +--- + +## 2. Цели + +| # | Цель | Метрика успеха | +|---|------|----------------| +| 1 | Удобная читаемая версия роадмапа | Сайт с навигацией, поиском, мобильной версией | +| 2 | Репозиторий остаётся полностью рабочим без сайта | Все `.md` файлы читаемы на GitHub, ссылки между ними работают | +| 3 | Минимальные накладные расходы на поддержку | Обновил `.md` → запушил → сайт обновился автоматически | +| 4 | Презентабельный вид для демонстрации на созвонах | Ссылка, которую удобно показать лиду из ОМ при обсуждении программы | + +--- + +## 3. Целевая аудитория + +**Основная:** менти (текущие и потенциальные) — джуны и переходящие в DE из смежных областей. Приходят по рекомендации из ОМ или по прямой ссылке от ментора. Им нужно быстро оценить объём программы и найти нужный раздел. + +**Вторичная:** коллеги-инженеры, которые наткнулись на репозиторий через GitHub/поиск. Для них важна полнота контента и техническая достоверность, а не «продающие» элементы. + +--- + +## 4. Требования + +### 4.1. Обязательные (MVP) + +**Контент и структура:** + +- [ ] Главная страница сайта = полный текст текущего `README.md` (одна длинная страница, не разбиваем). +- [ ] Подстраницы из существующих `.md` файлов (`dwh-modeling/README.md`, `SCD.md`, `DataVault.md`, домашки). +- [ ] Автоматическое оглавление (Table of Contents) по заголовкам H2/H3 на главной странице. +- [ ] Внутренние ссылки работают и на GitHub, и на сайте (dual-compatible links). + +**Навигация:** + +- [ ] Боковая панель с разделами сайта (основной README + подразделы). +- [ ] Оглавление текущей страницы (правый sidebar / TOC). +- [ ] Полнотекстовый поиск по сайту. + +**Деплой:** + +- [ ] Автоматическая сборка и публикация при пуше в `main`. +- [ ] Бесплатный хостинг (GitHub Pages). + +**Совместимость с репо:** + +- [ ] Все `.md` файлы остаются читаемыми на GitHub «как есть». +- [ ] `README.md` в корне репо продолжает рендериться на главной странице репозитория. +- [ ] Добавление сайта не ломает существующую структуру — если удалить конфиг сайта, репо работает как раньше. + +### 4.2. Желательные (Спринт 2+) + +- [ ] Кастомный домен (например, `roadmap.dementev.space`). +- [ ] Тёмная тема (переключатель light/dark). +- [ ] Сворачиваемые блоки (collapsible sections / admonitions) для длинных списков материалов. +- [ ] Кнопка «Написать в Telegram» (floating или в footer) — не агрессивный CTA, просто удобство. +- [ ] Иконки/бейджи для статуса разделов (пройден / в процессе / не начат) — пока декоративные, без бэкенда. +- [ ] Яндекс.Метрика или аналогичная аналитика (понимать, сколько людей заходят). + +### 4.3. Явно НЕ делаем + +- Разбивку основного README на отдельные страницы. +- Интерактивный трекинг прогресса менти. +- Систему авторизации / личный кабинет. +- Блог или раздел новостей (для этого есть Telegram-канал). +- SEO-оптимизацию и маркетинговые landing pages. + +--- + +## 5. Ограничения + +- **Бюджет: 0 ₽** (кроме домена, если решим подключить кастомный — `dementev.space` уже есть). +- **Время на поддержку: минимальное.** Рабочий процесс = «редактирую `.md` → push → сайт обновляется». Не должно быть отдельного шага сборки, ручного деплоя или npm-зависимостей, требующих обновления. +- **Стек автора: Python-first.** Решение на Python-тулинге предпочтительнее, чем на Node.js/Ruby (проще отлаживать при необходимости). +- **Один мейнтейнер.** Сайт поддерживает один человек — сложность решения должна быть соответствующей. + +--- + +## 6. Итерации + +### Спринт 1 — MVP: «Сайт, который просто работает» + +**Scope:** + +- Конфигурация генератора статического сайта. +- CI/CD pipeline (GitHub Actions → GitHub Pages). +- Главная страница = README. +- Подстраницы из `dwh-modeling/`. +- Фикс внутренних ссылок для dual compatibility. + +**Definition of Done:** + +- Сайт доступен по URL `https://dementev-dev.github.io/de-roadmap/`. +- Все ссылки внутри README работают и на сайте, и на GitHub. +- При пуше в `main` сайт автоматически пересобирается за < 2 минут. +- Контент на GitHub выглядит ровно так же, как до добавления сайта. + +### Спринт 2 — «Удобство и навигация» + +**Scope:** + +- Кастомный домен. +- Тёмная тема. +- Сворачиваемые блоки для длинных секций. +- Кнопка «Написать ментору» (Telegram). +- Базовая аналитика. + +### Спринт 3 — «Контент и визуал» (по необходимости) + +**Scope:** + +- Визуальная карта роадмапа (интерактивная диаграмма прохождения). +- Страница «О менторе» / «Отзывы выпускников» (когда будут выпускники). +- Расширение контента: новые разделы роадмапа → автоматически появляются на сайте. + +--- + +## 7. Риски + +| Риск | Вероятность | Влияние | Митигация | +|------|-------------|---------|-----------| +| Ссылки ломаются при конвертации (GitHub vs сайт) | Средняя | Высокое | Стратегия dual-compatible links в ADR; автотест ссылок в CI | +| Кириллические якоря рендерятся по-разному | Средняя | Среднее | Тестирование конкретного генератора; при необходимости — латинские id | +| Генератор сайта перестаёт поддерживаться | Низкая | Среднее | Контент в plain Markdown — миграция на другой генератор за день | +| Накладные расходы на поддержку растут | Низкая | Среднее | Принцип «сайт опционален»: если мешает — удаляем конфиг, репо работает | +| GitHub Pages ограничения (bandwidth, размер) | Очень низкая | Низкое | Для статического сайта с текстом — не актуально | + +--- + +## 8. Открытые вопросы + +1. **Домен.** Использовать GitHub Pages URL или сразу подключить кастомный домен? Можно решить в Спринте 2. +2. **README.md в корне vs docs/.** Оставляем README.md в корне (GitHub его рендерит) и используем его же как `index.md` для сайта, или делаем симлинк / копию? → Решение в ADR. +3. **Структура `docs/` директории.** Нужно ли вообще создавать `docs/`, или генератор может работать прямо с корнем репо? → Решение в ADR.