Author SHA1 Message Date
ddadmin 1ac325d14c chore(repo): добавлен пустой коммит для проверки нового origin
Deploy MkDocs to VPS / deploy (push) Successful in 8s
2026-10-22 10:20:11 +02:00
ddadmin 2732622919 fix(docs): исправлена ссылка на практику Airflow
- Зачем: прежний путь к заданиям возвращал 404.
- Что: обновлена ссылка и отмечен результат проверки в списке задач.
- Проверка: новая ссылка возвращает 200, строгая сборка MkDocs проходит;
  проверены 734 внутренние ссылки и якоря без ошибок.
2026-10-18 17:25:49 +02:00
ddadmin 56133ccfae docs(docs): добавлен черновик проработки учебного маршрута
- Зачем: нужны письменные указания по порядку и глубине изучения материалов.
- Что: описаны первый разбор Python, дальнейшие направления для SQL и Airflow; добавлена задача в бэклог.
- Проверка: проверены относительные ссылки, отсутствие приватных идентификаторов и пробелов в конце строк; git diff --cached --check прошел.
2026-09-27 16:23:46 -04:00
ddadmin 806417c1bd docs(docs): обновлены ссылки и основная программа роадмапа
Deploy MkDocs to VPS / deploy (push) Successful in 7s
- Зачем: восстановлен доступ к GitHub, изменились учебные стенды и требования к основной программе.
- Что: ссылки для менти возвращены на GitHub; ClickHouse, Kafka и курсовая Clickstream включены в основную программу; уточнены подготовка окружения Python, управление памятью, практика Airflow и вход в DEV1.
- Что: обновлены описание публикации через Gitea и бэклог; убрана ссылка на неподходящий курс ClickHouse.
- Проверка: строгая сборка MkDocs и проверка пробелов прошли; ссылки и задания сверены с учебными репозиториями.
2026-09-27 15:36:07 -04:00
ddadmin 242a066f42 docs(links): исправлены ссылки после переноса в Gitea
Deploy MkDocs to VPS / deploy (push) Successful in 5s
- Зачем:
  - старые ссылки на GitHub-репозитории возвращали 404.
- Что:
  - ссылки на учебные стенды переведены на публичные репозитории Gitea.
  - отсутствующий jupyter-spark-docker заменён официальным Jupyter Docker Stacks.
  - ссылки на каталоги SQL и данных переведены на Gitea.
- Проверка:
  - mkdocs build --strict.
  - HTTP-проверка всех изменённых URL вернула 200.
2026-08-05 04:10:54 -04:00
ddadmin 4ad904efd0 docs(site): дополнены инструкции восстановления публикации
Deploy MkDocs to VPS / deploy (push) Successful in 13s
- Зачем:
  - runbook требовал незафиксированного контекста для первого деплоя и восстановления сайта на чистой VPS.
- Что:
  - добавлены prerequisites, установка пакетов, первый workflow, UFW и проверенный атомарный откат.
  - спецификация и PRD обновлены по факту завершённого переноса на VPS.
  - локальные команды Snap uv заменены на persistent Python venv.
- Проверка:
  - mkdocs build --strict выполнен через persistent venv пользователя gitea-runner.
  - последовательность rollback проверена на временном дереве releases и symlink.
2026-08-05 03:14:52 -04:00
ddmitry 690b1fdb25 Merge pull request 'fix(site): закрыта выдача сайта по IP' (#4) from docs/gitea-vps-site-runbook into main
Deploy MkDocs to VPS / deploy (push) Successful in 6s
Reviewed-on: #4
2026-08-05 09:55:03 +03:00
ddadmin 515e221c52 fix(site): закрыта выдача сайта по IP
- Зачем:
  - стандартный nginx-vhost отдавал welcome page по IP, а HTTPS по IP получал сертификат de.dementev.space.
- Что:
  - default vhost настроен на HTTP 404 и отказ TLS для IP и неизвестного SNI.
  - runbook дополнен точной процедурой Certbot, восстановлением и проверками.
  - завершённая задача публикации перенесена в раздел «Сделано».
- Проверка:
  - live и bootstrap-конфигурации прошли nginx -t; доменный HTTPS отдаёт 200, неизвестный Host — 404, TLS по IP отклоняется.
  - mkdocs build --strict выполнен через persistent venv пользователя gitea-runner.
2026-08-05 02:48:12 -04:00
ddmitry 4e67059f7a Merge pull request 'fix(site): сборка runner переведена со Snap uv на venv' (#3) from fix/gitea-runner-python-venv into main
Deploy MkDocs to VPS / deploy (push) Successful in 6s
Reviewed-on: #3
2026-08-04 23:16:48 +03:00
ddadmin 2a1da643c1 fix(site): сборка runner переведена со Snap uv на venv
- Зачем:
  - Snap uv не запускался внутри ограниченного systemd-сервиса без cap_dac_override.
- Что:
  - workflow переведён на постоянный Python venv с pinned requirements.
  - повторные сборки проверяют зависимости через pip без их переустановки.
  - Snap удалён из PATH runner, runbook дополнен python3-venv и описанием окружения.
- Проверка:
  - от имени gitea-runner дважды выполнены pip install, pip check и mkdocs build --strict; второй запуск переиспользовал окружение.
  - обновлённый systemd unit прошёл systemd-analyze verify и успешно перезапущен.
2026-08-04 16:15:30 -04:00
ddmitry 09f2c839f7 Merge pull request 'ci(site): добавлена публикация через Gitea Actions' (#2) from infra/gitea-vps-site-publishing into main
Deploy MkDocs to VPS / deploy (push) Failing after 3s
Reviewed-on: #2
2026-08-04 23:03:13 +03:00
ddmitry c5e9bfe6b3 Merge pull request 'docs(project): согласована публикация сайта через Gitea и VPS' (#1) from docs/gitea-vps-site-publishing into main
Deploy MkDocs to GitHub Pages / build (push) Canceled after 0s
Deploy MkDocs to GitHub Pages / deploy (push) Canceled after 0s
Reviewed-on: #1
2026-08-04 22:59:17 +03:00
ddadmin 1edda33f87 ci(site): добавлена публикация через Gitea Actions
- Зачем:
  - основной сайт не должен зависеть от заблокированной учётной записи GitHub.
- Что:
  - добавлены строгая сборка и атомарная публикация через repository-scoped runner.
  - добавлены воспроизводимые конфигурации systemd, nginx и эксплуатационный runbook.
  - проектная документация и ссылки на репозиторий обновлены для Gitea.
- Проверка:
  - выполнены mkdocs build --strict, Bash/YAML-проверки и локальный HTTP smoke-check.
  - runner зарегистрирован, ограничен средствами systemd и виден в Gitea как online.
2026-08-04 15:16:33 -04:00
ddadmin 8584fc225b docs(project): добавлена спецификация публикации сайта
- Зачем:
  - нужен согласованный вариант публикации сайта без зависимости от GitHub Pages.
- Что:
  - описан контур Gitea Actions, host runner, nginx и резерв на GitHub Pages.
  - в архитектурный документ добавлена ссылка на новую спецификацию.
- Проверка:
  - git diff --cached --check.
2026-08-04 10:01:58 -04:00
16 changed files with 981 additions and 72 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
mkdocs-material==9.6.14
mkdocs-same-dir==0.1.3
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
readonly venv_dir="/var/lib/gitea-runner/venvs/site"
if [[ $# -ne 1 ]]; then
echo "Usage: $0 SOURCE_DIR" >&2
exit 2
fi
source_dir=$(realpath "$1")
requirements_file="${source_dir}/.gitea/requirements-site.txt"
if [[ ! -f $requirements_file ]]; then
echo "Requirements file not found: ${requirements_file}" >&2
exit 2
fi
mkdir -p "$(dirname "$venv_dir")"
if [[ ! -x "${venv_dir}/bin/python" ]]; then
python3 -m venv "$venv_dir"
fi
"${venv_dir}/bin/python" -m pip install \
--disable-pip-version-check \
--no-input \
--requirement "$requirements_file"
"${venv_dir}/bin/python" -m pip check
cd "$source_dir"
"${venv_dir}/bin/python" -m mkdocs build --strict
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
readonly deploy_root="/srv/de-roadmap"
readonly releases_root="${deploy_root}/releases"
readonly keep_releases=3
if [[ $# -ne 2 ]]; then
echo "Usage: $0 SITE_DIR COMMIT_SHA-RUN_ID" >&2
exit 2
fi
source_dir=$(realpath "$1")
release_id=$2
if [[ ! $release_id =~ ^[0-9a-f]{40}-[0-9]+$ ]]; then
echo "Invalid release id: ${release_id}" >&2
exit 2
fi
if [[ ! -f "${source_dir}/index.html" ]]; then
echo "Built site has no index.html: ${source_dir}" >&2
exit 2
fi
if [[ ! -d $releases_root || ! -w $releases_root || ! -w $deploy_root ]]; then
echo "Deployment directories are missing or not writable" >&2
exit 1
fi
readonly release_dir="${releases_root}/${release_id}"
readonly staging_dir="${releases_root}/.${release_id}.tmp"
readonly next_link="${deploy_root}/.current.${release_id}.tmp"
if [[ -e $release_dir || -e $staging_dir || -e $next_link ]]; then
echo "Release path already exists: ${release_id}" >&2
exit 1
fi
cleanup() {
rm -rf -- "$staging_dir"
rm -f -- "$next_link"
}
trap cleanup EXIT
umask 0022
mkdir "$staging_dir"
cp -a "${source_dir}/." "$staging_dir/"
chmod -R u=rwX,go=rX "$staging_dir"
mv "$staging_dir" "$release_dir"
ln -s "releases/${release_id}" "$next_link"
mv -Tf "$next_link" "${deploy_root}/current"
mapfile -t old_releases < <(
find "$releases_root" \
-mindepth 1 \
-maxdepth 1 \
-type d \
-regextype posix-extended \
-regex '.*/[0-9a-f]{40}-[0-9]+' \
-printf '%T@ %f\n' \
| sort -nr \
| awk -v keep="$keep_releases" 'NR > keep { print $2 }'
)
for old_release in "${old_releases[@]}"; do
if [[ $old_release =~ ^[0-9a-f]{40}-[0-9]+$ && $old_release != "$release_id" ]]; then
rm -rf -- "${releases_root:?}/${old_release}"
fi
done
trap - EXIT
echo "Published release ${release_id}"
+39
View File
@@ -0,0 +1,39 @@
name: Deploy MkDocs to VPS
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: site-production
cancel-in-progress: false
jobs:
deploy:
runs-on: de-roadmap-host
timeout-minutes: 15
steps:
- name: Check out the triggering commit
env:
COMMIT_SHA: ${{ gitea.sha }}
REPOSITORY_URL: ${{ gitea.server_url }}/${{ gitea.repository }}.git
run: |
set -euo pipefail
[[ "$COMMIT_SHA" =~ ^[0-9a-f]{40}$ ]]
test ! -e source
mkdir source
git -C source init .
git -C source remote add origin "$REPOSITORY_URL"
git -C source fetch --no-tags --depth=1 origin "$COMMIT_SHA"
test "$(git -C source rev-parse FETCH_HEAD)" = "$COMMIT_SHA"
git -C source -c advice.detachedHead=false checkout --detach FETCH_HEAD
- name: Build the site strictly
run: source/.gitea/scripts/build-site.sh source
- name: Publish the complete release atomically
env:
RELEASE_ID: ${{ gitea.sha }}-${{ gitea.run_id }}
run: source/.gitea/scripts/deploy-site.sh source/site "$RELEASE_ID"
+12 -5
View File
@@ -4,8 +4,11 @@
- Root `README.md` describes the learning roadmap (RU) and serves as the main page of the MkDocs site. - Root `README.md` describes the learning roadmap (RU) and serves as the main page of the MkDocs site.
- `dwh-modeling/` contains the article and demo DWH model; SQL lives in `dwh-modeling/sql` as ordered scripts `01_...sql`–`09_...sql` (07–09 are homework DDL, template and solution). - `dwh-modeling/` contains the article and demo DWH model; SQL lives in `dwh-modeling/sql` as ordered scripts `01_...sql`–`09_...sql` (07–09 are homework DDL, template and solution).
- `postgres-bookings/` is a Dockerized PostgreSQL + demo “bookings” DB; start it first, then apply DWH scripts against the `demo` database. - `postgres-bookings/` is a Dockerized PostgreSQL + demo “bookings” DB; start it first, then apply DWH scripts against the `demo` database.
- `mkdocs.yml` — MkDocs Material config; `docs_dir: .` (repo root = site root). Excluded dirs: `project/`, `postgres-bookings/`, `.github/`, `.claude/`. - `mkdocs.yml` — MkDocs Material config; `docs_dir: .` (repo root = site root). Excluded dirs: `project/`, `postgres-bookings/`, `.gitea/`, `.github/`, `.claude/`.
- `.github/workflows/deploy-site.yml` — CI/CD: push to `main` → build → deploy to GitHub Pages. - `.gitea/workflows/deploy-site.yml` — основной CI/CD: push в `main` → строгая
сборка → атомарная публикация на VPS через repository-scoped Gitea Runner.
- `.github/workflows/deploy-site.yml` — сохранённый workflow для резервной
публикации на GitHub Pages; Gitea его не исполняет.
- `project/` — PRD, ADR, and TODO.md (excluded from site). `project/TODO.md` is the prioritized project backlog: check it when planning or proposing work, and mark items done there when you complete them. - `project/` — PRD, ADR, and TODO.md (excluded from site). `project/TODO.md` is the prioritized project backlog: check it when planning or proposing work, and mark items done there when you complete them.
## Build, Test, and Development Commands ## Build, Test, and Development Commands
@@ -52,10 +55,12 @@ All `.md` files MUST render correctly on both GitHub and the MkDocs Material sit
- Avoid: em-dash `—`, en-dash `–` — slug behavior differs between GitHub and MkDocs. - Avoid: em-dash `—`, en-dash `–` — slug behavior differs between GitHub and MkDocs.
## MkDocs Site Commands ## MkDocs Site Commands
- Initialize or update the persistent local environment:
`python3 -m venv "${HOME}/.cache/de-roadmap-mkdocs" && "${HOME}/.cache/de-roadmap-mkdocs/bin/python" -m pip install -r .gitea/requirements-site.txt`
- Local preview (user starts, ask user to run via `!`): - Local preview (user starts, ask user to run via `!`):
`uv run --with 'mkdocs-material==9.6.14' --with 'mkdocs-same-dir==0.1.3' mkdocs serve` `"${HOME}/.cache/de-roadmap-mkdocs/bin/python" -m mkdocs serve`
- Build with strict validation (catches broken links/anchors): - Build with strict validation (catches broken links/anchors):
`uv run --with 'mkdocs-material==9.6.14' --with 'mkdocs-same-dir==0.1.3' mkdocs build --strict` `"${HOME}/.cache/de-roadmap-mkdocs/bin/python" -m mkdocs build --strict`
- Visual check via Playwright (when `mkdocs serve` is running on port 8000): - Visual check via Playwright (when `mkdocs serve` is running on port 8000):
`npx playwright screenshot --viewport-size='1280,800' 'http://127.0.0.1:8000/#anchor' /path/to/screenshot.png` `npx playwright screenshot --viewport-size='1280,800' 'http://127.0.0.1:8000/#anchor' /path/to/screenshot.png`
Then read the screenshot with the Read tool to inspect rendering. Use `--viewport-size='1280,2000'` for tall pages. Then read the screenshot with the Read tool to inspect rendering. Use `--viewport-size='1280,2000'` for tall pages.
@@ -75,5 +80,7 @@ Pull requests should focus on one topic, include a brief context, list of change
## Security & Configuration Tips ## Security & Configuration Tips
- Do not commit personal `.env` files or credentials; use local overrides only. - Do not commit personal `.env` files or credentials; use local overrides only.
- Gitea Runner работает в host mode: не расширяйте его scope, не добавляйте
пользователя `gitea-runner` в `sudo` или `docker` и не выдавайте ему запись
вне `/var/lib/gitea-runner` и `/srv/de-roadmap`.
- Demo credentials and ports in `postgres-bookings` are for local training only—never reuse them in shared or production environments. - Demo credentials and ports in `postgres-bookings` are for local training only—never reuse them in shared or production environments.
+148 -59
View File
@@ -4,7 +4,7 @@
Он подойдёт тем, кто хочет: Он подойдёт тем, кто хочет:
- системно войти в профессию с нуля или близкого к нулю уровня; - системно войти в профессию с нуля или близкого к нулю уровня;
- закрыть пробелы в базе (SQL, Git, Python, DWH, Airflow, Greenplum); - закрыть пробелы в базе (SQL, Git, Python, DWH, Airflow, Greenplum, Kafka, ClickHouse);
- подготовиться к собеседованиям и первым рабочим задачам. - подготовиться к собеседованиям и первым рабочим задачам.
Роадмап можно проходить самостоятельно или вместе со мной в формате менторства. Роадмап можно проходить самостоятельно или вместе со мной в формате менторства.
@@ -13,9 +13,9 @@
### Оглавление ### Оглавление
- [Основные знания](#основные-знания) — Linux, Git, SQL, Python, методологии, Docker - [Основные знания](#основные-знания) — Linux, Git, SQL, Python, методологии, Docker
- [Практика и инструменты](#практика-и-инструменты) — Airflow, Greenplum, курсовая работа - [Практика и инструменты](#практика-и-инструменты) - Airflow, Greenplum, Streaming, ClickHouse, две курсовые
- [Карьера и менторство](#карьера-и-менторство) — резюме, собеседования, испытательный срок - [Карьера и менторство](#карьера-и-менторство) — резюме, собеседования, испытательный срок
- [Расширенные навыки](#расширенные-навыки) — Streaming, ClickHouse, Lakehouse, dbt - [Расширенные навыки](#расширенные-навыки) - Lakehouse, dbt
- [Софт скиллы](#софт-скиллы) - [Софт скиллы](#софт-скиллы)
- [Дополнительные материалы](#дополнительные-материалы) - [Дополнительные материалы](#дополнительные-материалы)
@@ -25,6 +25,11 @@
- выполнять практику и домашки, а не только смотреть материалы; - выполнять практику и домашки, а не только смотреть материалы;
- возвращаться к разделам по мере появления реальных задач. - возвращаться к разделам по мере появления реальных задач.
Основная программа включает две курсовые: сначала хранилище на Greenplum,
затем [Clickstream на ClickHouse](#большая-курсовая-clickstream).
Streaming и ClickHouse входят в обязательную часть подготовки к трудоустройству.
Lakehouse и dbt можно изучать после нее, под задачи и интересующие вакансии.
--- ---
## Основные знания ## Основные знания
@@ -85,12 +90,17 @@ SQL и моделирование данных специально идут р
#### Повышение знаний SQL #### Повышение знаний SQL
**Перед DEV1: запустите учебную базу.** Для практики рекомендую
[стенд PostgreSQL с базой bookings](https://github.com/dementev-dev/de-roadmap/tree/main/postgres-bookings).
В README стенда описаны запуск в Docker, подключение через `psql` и DBeaver.
Это наше первое знакомство с Docker: пока достаточно научиться запускать
и останавливать стенд, смотреть его статус и подключаться к базе.
Подробный [блок Docker](#docker) будет дальше.
Смотрим курс от Postgres Pro [DEV1](https://postgrespro.ru/education/courses/DEV1) Смотрим курс от Postgres Pro [DEV1](https://postgrespro.ru/education/courses/DEV1)
Темы - от "Введение" до "SQL" включительно, "Управление доступом", "Резервное копирование". Для лучшего усваивания материала проделываем все примеры и домашние задания из конспектов лекций. Темы - от "Введение" до "SQL" включительно, "Управление доступом", "Резервное копирование". Для лучшего усваивания материала проделываем все примеры и домашние задания из конспектов лекций.
С темой "PL/pgSQL" можно ознакомиться обзорно. С темой "PL/pgSQL" можно ознакомиться обзорно.
Для развития навыков инженера будет полезно лабораторные работы делать не в виртуальной машине, а в docker контейнере. Предложенный (не обязательный) вариант - в каталоге `postgres-bookings` репозитория.
Для дальнейшего закрепления материала - читаем книгу [PostgreSQL. Основы языка SQL](https://postgrespro.ru/education/books/sqlprimer) Для дальнейшего закрепления материала - читаем книгу [PostgreSQL. Основы языка SQL](https://postgrespro.ru/education/books/sqlprimer)
- Глава 8 - Индексы + ДЗ - Глава 8 - Индексы + ДЗ
@@ -98,7 +108,7 @@ SQL и моделирование данных специально идут р
- Глава 10 - Повышение производительности + ДЗ - Глава 10 - Повышение производительности + ДЗ
Вопросы оптимизации запросов хорошо описаны в курсе [QPT](https://postgrespro.ru/education/courses/QPT) от Postgres Pro. Полученные навыки применимы для работы в том числе с Greenplum, и частично, другими БД. Вопросы оптимизации запросов хорошо описаны в курсе [QPT](https://postgrespro.ru/education/courses/QPT) от Postgres Pro. Полученные навыки применимы для работы в том числе с Greenplum, и частично, другими БД.
На момент написания, видеолекции были доступны только для старой версии Postgres 13, но ее вполне достаточно. На странице курса выбирайте материалы и видеозаписи для PostgreSQL 16.
#### Моделирование данных #### Моделирование данных
Понимание того, **как устроены данные и зачем они нужны**, — ключ к качественным ETL-процессам. Понимание того, **как устроены данные и зачем они нужны**, — ключ к качественным ETL-процессам.
@@ -120,7 +130,9 @@ SQL и моделирование данных специально идут р
- Теория про Slowly Changing Dimensions: [SCD](dwh-modeling/SCD.md) - Теория про Slowly Changing Dimensions: [SCD](dwh-modeling/SCD.md)
- (Опционально) Ральф Кимбалл — «Инструментарий хранения и анализа данных» (The Data Warehouse Toolkit) - первые 3 главы - (Опционально) Ральф Кимбалл — «Инструментарий хранения и анализа данных» (The Data Warehouse Toolkit) - первые 3 главы
- Практика по моделированию статусов клиента: [домашка STG → ODS → DDS → DM](dwh-modeling/Homework_Customer_Status_DDS_DM.md) - Практика по моделированию статусов клиента: [домашка STG → ODS → DDS → DM](dwh-modeling/Homework_Customer_Status_DDS_DM.md)
- Еще про Data Vault: - Data Vault и Anchor Modeling изучаем обзорно, для знакомства с основными
понятиями. Глубокий разбор и самостоятельное проектирование на этом этапе
не требуются. Материалы для знакомства:
- Конспект и примеры из этого репозитория: [DataVault.md](dwh-modeling/DataVault.md) - Конспект и примеры из этого репозитория: [DataVault.md](dwh-modeling/DataVault.md)
- [DataVault за 10 минут - Youtube](https://www.youtube.com/watch?v=9oQs_wJ045I) - [DataVault за 10 минут - Youtube](https://www.youtube.com/watch?v=9oQs_wJ045I)
- Статья [«Что такое Data Vault: моделирование КХД для архитектора Big Data»](https://bigdataschool.ru/blog/what-is-data-vault/) — обзор, плюсы/минусы, контекст применения. - Статья [«Что такое Data Vault: моделирование КХД для архитектора Big Data»](https://bigdataschool.ru/blog/what-is-data-vault/) — обзор, плюсы/минусы, контекст применения.
@@ -139,13 +151,36 @@ SQL и моделирование данных специально идут р
### Python ### Python
- Если совсем не знакомы с Python, начинаем с курса ["Поколение Python": курс для начинающих – Stepik](https://stepik.org/course/58852/info) Если совсем не знакомы с Python, начинаем с курса ["Поколение Python": курс для начинающих - Stepik](https://stepik.org/course/58852/info).
Перед курсом для продвинутых подготовьте рабочую среду. Она пригодится для
экспериментов с кодом и домашних заданий.
- Виртуальные окружения (venv) изолируют зависимости проекта:
- [Habr: как настроить виртуальное окружение](https://habr.com/ru/articles/889670/)
- [SkillFactory: Виртуальные окружения в Python](https://blog.skillfactory.ru/venv-virtualnoe-okruzhenie-v-python/)
- [Создание venv и установка пакетов: документация Python](https://docs.python.org/3/tutorial/venv.html)
- JupyterLab позволяет выполнять код по ячейкам и сохранять пояснения рядом с результатами:
- [Блог Практикума: что такое Jupyter Notebook](https://practicum.yandex.ru/blog/chto-takoe-jupyter-notebook/)
- [Установка JupyterLab](https://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html)
Создайте venv, установите в него JupyterLab и запустите из этого же окружения.
В новом ноутбуке выполните несколько ячеек, сохраните `.ipynb`, перезапустите
ядро и выполните все ячейки по порядку. В Git сохраняйте ноутбуки и скрипты,
а каталог `.venv/` добавьте в `.gitignore`.
Теперь продолжаем изучать Python:
- Изучаем глубже и "оттачиваем" live coding: ["Поколение Python": курс для продвинутых – Stepik](https://stepik.org/course/68343/info) - Изучаем глубже и "оттачиваем" live coding: ["Поколение Python": курс для продвинутых – Stepik](https://stepik.org/course/68343/info)
- Продолжение "базы", спрашиваемой на собеседованиях, по Python: ["Поколение Python": курс для профессионалов](https://stepik.org/course/82541/promo). Курс очень полезный, но платный. Вместо него можно почитать "продвинутые" темы дальше. - Продолжение "базы", спрашиваемой на собеседованиях, по Python: ["Поколение Python": курс для профессионалов](https://stepik.org/course/82541/promo). Курс очень полезный, но платный. Вместо него можно почитать "продвинутые" темы дальше.
- "Продвинутые" темы: - "Продвинутые" темы:
- [Полезные функции](https://pyneng.readthedocs.io/ru/latest/book/10_useful_functions/index.html) - [Полезные функции](https://pyneng.readthedocs.io/ru/latest/book/10_useful_functions/index.html)
- [Работа с файлами в формате CSV, JSON, YAML](https://pyneng.readthedocs.io/ru/latest/book/17_serialization/index.html) - [Работа с файлами в формате CSV, JSON, YAML](https://pyneng.readthedocs.io/ru/latest/book/17_serialization/index.html)
- [Итераторы, итерируемые объекты и генераторы](https://pyneng.readthedocs.io/ru/latest/book/13_iterator_generator/index.html) - [Итераторы, итерируемые объекты и генераторы](https://pyneng.readthedocs.io/ru/latest/book/13_iterator_generator/index.html)
- Управление памятью (документация на английском):
- [Объекты, ссылки и изменяемость](https://docs.python.org/3/reference/datamodel.html#objects-values-and-types) - почему два имени могут указывать на один список и что происходит при его изменении.
- [Как Python управляет памятью](https://docs.python.org/3/faq/design.html#how-does-python-manage-memory) - подсчет ссылок и сборка циклов в CPython; особенности других реализаций Python.
- [Модуль gc](https://docs.python.org/3/library/gc.html) - справочник для экспериментов со сборщиком мусора. Детали поколений и порогов смотрите для своей версии Python.
- [Декораторы Python: пошаговое руководство](https://habr.com/ru/companies/otus/articles/727590/) - [Декораторы Python: пошаговое руководство](https://habr.com/ru/companies/otus/articles/727590/)
- Работа с датой/временем: [официальная документация по модулю datetime](https://docs.python.org/3/library/datetime.html) - Работа с датой/временем: [официальная документация по модулю datetime](https://docs.python.org/3/library/datetime.html)
- [Сложность алгоритмов. Разбор Big O](https://habr.com/ru/articles/782608/) — короткий материал, чтобы понимать O(n) vs O(n²) на собеседованиях и в коде - [Сложность алгоритмов. Разбор Big O](https://habr.com/ru/articles/782608/) — короткий материал, чтобы понимать O(n) vs O(n²) на собеседованиях и в коде
@@ -154,12 +189,6 @@ SQL и моделирование данных специально идут р
- Введение в [ООП](https://metanit.com/python/tutorial/7.1.php) - Введение в [ООП](https://metanit.com/python/tutorial/7.1.php)
- [Яндекс Учебник: «Объектная модель Python: классы, поля и методы»](https://education.yandex.ru/handbook/python/article/obuektnaya-model-python-klassy-polya-i-metody) - [Яндекс Учебник: «Объектная модель Python: классы, поля и методы»](https://education.yandex.ru/handbook/python/article/obuektnaya-model-python-klassy-polya-i-metody)
- [Real Python: OOP in Python (tutorial)](https://realpython.com/python3-object-oriented-programming/) - [Real Python: OOP in Python (tutorial)](https://realpython.com/python3-object-oriented-programming/)
- Виртуальные окружения (venv) — изолируют зависимости проекта; настройте перед установкой Jupyter и библиотек
- [Habr: как настроить виртуальное окружение](https://habr.com/ru/articles/889670/)
- [SkillFactory: Виртуальные окружения в Python](https://blog.skillfactory.ru/venv-virtualnoe-okruzhenie-v-python/)
- Jupyter Lab
- [Блог Практикума: «Что такое Jupyter Notebook: как установить и открыть»](https://practicum.yandex.ru/blog/chto-takoe-jupyter-notebook/)
- Готовая реализация Jupyter Lab, включающая в себя Spark, в Docker: [jupyter-spark-docker](https://github.com/dementev-dev/jupyter-spark-docker)
- Pandas - Pandas
- [GeeksforGeeks: “Why Pandas is Used in Python”](https://www.geeksforgeeks.org/pandas/why-pandas-is-used-in-python/) - [GeeksforGeeks: “Why Pandas is Used in Python”](https://www.geeksforgeeks.org/pandas/why-pandas-is-used-in-python/)
- [Skillbox: «Для чего нужна библиотека Pandas»](https://skillbox.ru/media/code/rabotaem-s-pandas-osnovnye-ponyatiya-i-realnye-dannye/) - [Skillbox: «Для чего нужна библиотека Pandas»](https://skillbox.ru/media/code/rabotaem-s-pandas-osnovnye-ponyatiya-i-realnye-dannye/)
@@ -173,10 +202,14 @@ SQL и моделирование данных специально идут р
**Когда блок Python считаем пройденным:** **Когда блок Python считаем пройденным:**
- создаете venv, устанавливаете в него пакеты и запускаете JupyterLab; можете повторить вычисления в ноутбуке после перезапуска ядра;
- вы без подсказок пишете небольшие скрипты с циклами, функциями, обработкой ошибок и работой с коллекциями; - вы без подсказок пишете небольшие скрипты с циклами, функциями, обработкой ошибок и работой с коллекциями;
- умеете читать и модифицировать чужой код, в том числе с использованием pandas и DataFrame; - умеете читать и модифицировать чужой код, в том числе с использованием pandas и DataFrame;
- уверенно проходите простой live-coding по Python для DE: прочитать CSV/JSON, отфильтровать, сгруппировать данные и посчитать агрегаты. - уверенно проходите простой live-coding по Python для DE: прочитать CSV/JSON, отфильтровать, сгруппировать данные и посчитать агрегаты.
- можете отвечать как на простые вопросы собеседований (циклы, списки, словари), так и продвинутые (итераторы, декораторы, управление памятью, базовые понятия ООП) - можете отвечать как на простые вопросы собеседований (циклы, списки, словари), так и продвинутые (итераторы, декораторы, базовые понятия ООП);
- на примере со списком объясняете разницу между объектом и ссылкой на него,
почему `del` одного имени не обязательно уничтожает объект и зачем CPython
нужен сборщик циклического мусора.
### Методологии разработки ### Методологии разработки
@@ -284,11 +317,20 @@ Apache Airflow — инструмент для оркестрации ETL-про
Материалы: Материалы:
- [Учебник по Airflow](https://github.com/dementev-dev/airflow-manual) - [Учебник по Airflow](https://github.com/dementev-dev/airflow-manual)
- [Практические задания на стенде](https://github.com/dementev-dev/airflow-manual/blob/main/educational-tasks.md)
Задания выполняем параллельно с чтением учебника. Начинаем с простых DAG
и SQL, затем обрабатываем файлы, загружаем CSV в PostgreSQL и добавляем
проверки качества. Дальше расширяем ETL, разбираем ветвление, повторные
попытки и логирование. Здесь Python и SQL впервые работают вместе
в пайплайне, которым управляет Airflow.
**Когда блок Airflow считаем пройденным:** **Когда блок Airflow считаем пройденным:**
- вы можете объяснить, что такое DAG, задачи, операторы и сенсоры, и как между ними задаются зависимости; - вы можете объяснить, что такое DAG, задачи, операторы и сенсоры, и как между ними задаются зависимости;
- на базе учебного стенда подготавливаете, отлаживаете и запускаете свои DAG'и с расписанием и несколькими шагами (например, загрузка данных и последующие трансформации); - на базе учебного стенда подготавливаете, отлаживаете и запускаете свои DAG'и с расписанием и несколькими шагами (например, загрузка данных и последующие трансформации);
- расширяете загрузку CSV в PostgreSQL: меняете генерацию данных, схему таблицы и загрузку новой колонки;
- добавляете свою проверку качества и убеждаетесь, что она обнаруживает подготовленную ошибку в данных;
- уверенно смотрите логи, находите место падения и понимаете, как перезапустить задачу. - уверенно смотрите логи, находите место падения и понимаете, как перезапустить задачу.
### Greenplum ### Greenplum
@@ -324,7 +366,8 @@ Apache Airflow — инструмент для оркестрации ETL-про
- можете объяснить, в чём практическая разница между MPP-хранилищем и одиночным Postgres на уровне типичных задач DE и собеседований. - можете объяснить, в чём практическая разница между MPP-хранилищем и одиночным Postgres на уровне типичных задач DE и собеседований.
### Курсовая работа ### Курсовая работа
Курсовая работа — важный майлстоун роадмапа: ваш первый end-to-end data-проект. После неё у вас есть ключевые технические навыки для старта карьеры в Data Engineering. Первая курсовая собирает изученное в один проект: загрузку данных из PostgreSQL,
слои хранилища в Greenplum и управление обработкой через Airflow.
Курсовая выполняется на том же стенде [airflow-dwh-gp-lab](https://github.com/dementev-dev/airflow-greenplum), который вы уже использовали для практики по Greenplum. Курсовая выполняется на том же стенде [airflow-dwh-gp-lab](https://github.com/dementev-dev/airflow-greenplum), который вы уже использовали для практики по Greenplum.
@@ -342,6 +385,86 @@ Apache Airflow — инструмент для оркестрации ETL-про
- автоматическая проверка (валидационный DAG) проходит без ошибок; - автоматическая проверка (валидационный DAG) проходит без ошибок;
- вы можете на собеседовании за 5–10 минут рассказать архитектуру проекта, его цели и показать ключевые части кода. - вы можете на собеседовании за 5–10 минут рассказать архитектуру проекта, его цели и показать ключевые части кода.
После этой работы переходим к потокам событий и ClickHouse. Они понадобятся
для [большой курсовой Clickstream](#большая-курсовая-clickstream).
### Streaming (NiFi + Kafka)
В первой курсовой мы загружали данные из базы. Теперь разберем прием потока
событий: как доставить их в хранилище и продолжить чтение после остановки
обработчика. NiFi помогает собрать поток обработки визуально, Kafka хранит
события в распределенном журнале и позволяет потребителям читать их независимо.
Материалы:
- [Apache NiFi с нуля за 3 часа (Youtube-плейлист)](https://youtube.com/playlist?list=PL4MpKy3QjNp_rOEEibc4Ro8UK4g8vLX6_&si=W_hidjHmBOZ_aUfS) — первые 4 видео, дальше — по желанию
- [Лучший Гайд по Kafka для Начинающих За 1 Час (Youtube)](https://www.youtube.com/watch?v=hbseyn-CfXY)
Практика — на стенде [nifi-kafka-postgres-lab](https://github.com/dementev-dev/nifi-kafka-postgres-lab) (Docker Compose с NiFi, Kafka и Postgres):
- настраиваем в NiFi простой генератор данных и поток в Postgres;
- строим поток NiFi → Kafka → NiFi → Postgres.
**Перед большой курсовой нужно уметь:**
- объяснить связь между топиком, партицией, consumer group и offset;
- отправить сообщения в Kafka и прочитать их потребителем;
- показать на учебном потоке, откуда продолжится чтение после перезапуска,
и объяснить, почему при повторной доставке могут появиться дубли.
В [курсовой Clickstream](#большая-курсовая-clickstream) события и заказы
поступают через Kafka в ClickHouse. Вернемся к этим вопросам, когда будем
разбирать прием данных и их обработку в хранилище.
### ClickHouse
ClickHouse используем для аналитики по событиям и заказам. Здесь нужно
разобраться, как хранить данные, выбирать ключ сортировки и строить витрины.
Затем применим это в большой курсовой.
Материалы:
- Бесплатный курс [ClickHouse от Yandex Cloud](https://yandex.cloud/ru/training/clickhouse) берем за основу.
Практика:
Упражнения по самой СУБД можно выполнять локально на
[clickhouse-learning-cluster](https://github.com/dementev-dev/clickhouse-learning-cluster):
четыре узла ClickHouse в Docker Compose, репликация, шардинг и HAProxy.
Задания по облачной инфраструктуре требуют Yandex Cloud и оплаты ресурсов.
**Когда готовы переходить к курсовой:**
- создаете таблицы семейства MergeTree и объясняете выбор `ORDER BY` и `PARTITION BY`;
- различаете шардирование и репликацию, понимаете роль таблиц Distributed;
- загружаете данные, пишете аналитические запросы и можете объяснить,
как устройство таблицы влияет на чтение данных.
### Большая курсовая: Clickstream
На стенде [clickstream-data-platform](https://github.com/dementev-dev/clickstream-data-platform)
работаем с хранилищем интернет-магазина. Генератор создает события посетителей
и заказы, Kafka доставляет их в ClickHouse. Данные проходят слои STG, ODS,
DDS и DM; Airflow управляет обработкой, Superset показывает отчеты.
Часть хранилища уже работает. В заданиях вы строите свои витрины, разбираете
готовые загрузки и меняете их, сверяя результат с исходными данными.
Проверки качества и мониторинг нужны здесь для конкретных задач: заметить
потери и дубли, найти причину расхождения, проверить результат своей правки.
Начните с запуска по README репозитория, затем прочитайте
[путеводитель по стенду](https://github.com/dementev-dev/clickstream-data-platform/blob/main/docs/handbook/README.md)
и переходите к [учебным заданиям](https://github.com/dementev-dev/clickstream-data-platform/blob/main/docs/labs/README.md).
В основной программе семь ступеней: пять витрин DM, свой график в Superset,
самостоятельная нарезка сессий, изменение расчета сессий в конвейере,
проверки и обработка заказов, разбор сырых событий, мониторинг.
Факультативные расследования можно взять после основной программы.
**Когда большую курсовую считаем пройденной:**
- выполнены семь ступеней основной программы и проверки из заданий;
- пять учебных витрин проходят `homework_check`, в Superset построен свой график;
- можете проследить путь события от Kafka до отчета, объяснить свои изменения
и показать, как проверяли их корректность.
--- ---
## Карьера и менторство ## Карьера и менторство
@@ -394,49 +517,12 @@ Apache Airflow — инструмент для оркестрации ETL-про
--- ---
## Расширенные навыки ## Расширенные навыки
Эти темы выходят за рамки базового минимума для старта в Data Engineering, но дают более полное представление об экосистеме. После двух курсовых можно расширить стек: попробовать обработку файлов
Их цель — понимать, зачем и когда используется тот или иной инструмент, а не осваивать его на уровне администратора или DevOps-инженера. в Lakehouse и управление SQL-моделями через dbt. Выбирайте тему под задачи,
с которыми хотите работать.
[[к оглавлению]](#оглавление) [[к оглавлению]](#оглавление)
Мы кратко знакомимся с:
- **Streaming** (NiFi + Kafka) — инструментами для построения потоковых и интеграционных пайплайнов;
- **ClickHouse** — колоночной СУБД для высоконагруженной аналитики;
- **Lakehouse** (Spark, Iceberg, Trino) — архитектурой, построенной на разделении compute и storage;
- **dbt** — подходом к трансформации данных как кода.
Практика ограничивается минимальным рабочим примером (запуск в Docker, простой пайплайн или SQL-модель).
Этого достаточно, чтобы уверенно говорить об инструменте на собеседовании и понимать его место в архитектуре — а всё остальное при необходимости осваивается уже на проекте.
### Streaming (NiFi + Kafka)
NiFi — визуальный конструктор потоков данных, Kafka — распределённая очередь сообщений. Вместе они закрывают типичный сценарий: принять данные, буферизовать, доставить в хранилище.
Материалы:
- [Apache NiFi с нуля за 3 часа (Youtube-плейлист)](https://youtube.com/playlist?list=PL4MpKy3QjNp_rOEEibc4Ro8UK4g8vLX6_&si=W_hidjHmBOZ_aUfS) — первые 4 видео, дальше — по желанию
- [Лучший Гайд по Kafka для Начинающих За 1 Час (Youtube)](https://www.youtube.com/watch?v=hbseyn-CfXY)
Практика — на стенде [nifi-kafka-postgres-lab](https://github.com/dementev-dev/nifi-kafka-postgres-lab) (Docker Compose с NiFi, Kafka и Postgres):
- настраиваем в NiFi простой генератор данных и поток в Postgres;
- строим поток NiFi → Kafka → NiFi → Postgres.
Знакомство с Kafka здесь пригодится и дальше: стенд по ClickHouse в следующей секции принимает данные именно через Kafka.
### ClickHouse
ClickHouse — колоночная СУБД для аналитики на больших объёмах: миллиарды строк, агрегации за секунды. В российских компаниях это фактический стандарт для витрин, отчётности и продуктовой аналитики, поэтому на собеседованиях тема всплывает часто.
Материалы:
- Бесплатный курс [ClickHouse от Yandex Cloud](https://yandex.cloud/ru/training/clickhouse) — берём за основу, в нём много упражнений
- Платный курс [ClickHouse для аналитика – Stepik](https://stepik.org/course/100210/promo?search=6551441002)
Практика:
- Упражнения курса Яндекса можно выполнять в их облаке (с оплатой за ресурсы) или бесплатно у себя — на учебном кластере [clickhouse-learning-cluster](https://github.com/dementev-dev/clickhouse-learning-cluster): 4 узла ClickHouse в Docker Compose, репликация, шардинг, балансировка через HAProxy.
- Следующий шаг — стенд [clickstream-ch-kafka-superset-demo](https://github.com/dementev-dev/clickstream-ch-kafka-superset-demo), имитирующий полноценное аналитическое хранилище на ClickHouse: Kafka, Airflow, дашборды в Superset, мониторинг (Prometheus/Grafana), слои STG → ODS → DDS → DM. Внутри — собственный продвинутый курс «Кликстрим на ClickHouse» с уроками прямо на стенде.
### Lakehouse (Spark, Iceberg, Trino) ### Lakehouse (Spark, Iceberg, Trino)
Lakehouse — архитектурный подход, который соединяет гибкость Data Lake с гарантиями классического DWH. Lakehouse — архитектурный подход, который соединяет гибкость Data Lake с гарантиями классического DWH.
@@ -480,9 +566,12 @@ dbt (data build tool) — инструмент для трансформации
**Когда блок расширенных навыков считаем пройденным:** **Когда блок расширенных навыков считаем пройденным:**
- вы можете на собеседовании кратко объяснить, когда уместны Streaming (NiFi/Kafka), ClickHouse, Lakehouse-стек и dbt, и чем они дополняют базовый стек (Postgres, Airflow, Greenplum); Оценивайте выбранную тему по результату практики:
- понимаете типичные сценарии: потоковые интеграции и очереди (NiFi + Kafka), аналитические витрины и отчёты на ClickHouse, Lakehouse-архитектура (Spark/Iceberg/Trino), трансформации данных как код (dbt);
- не боитесь увидеть эти инструменты в описании вакансии и можете поддержать содержательный разговор об их месте в архитектуре. - для Lakehouse можете записать таблицу через Spark, прочитать ее через Trino
и объяснить роль Iceberg, каталога и объектного хранилища;
- для dbt можете изменить SQL-модель, выполнить сборку и тесты,
посмотреть зависимости в документации проекта.
--- ---
+5 -4
View File
@@ -1,6 +1,6 @@
site_name: "DE Roadmap — Data Engineering с нуля до middle" site_name: "DE Roadmap — Data Engineering с нуля до middle"
site_url: https://de.dementev.space/ site_url: https://de.dementev.space/
site_description: "Роадмап по Data Engineering: SQL, Python, Airflow, Greenplum и далее" site_description: "Роадмап по Data Engineering: SQL, Python, Airflow, Greenplum, Kafka и ClickHouse"
site_author: Dmitry Dementev site_author: Dmitry Dementev
repo_url: https://github.com/dementev-dev/de-roadmap repo_url: https://github.com/dementev-dev/de-roadmap
@@ -13,6 +13,7 @@ exclude_docs: |
project/ project/
postgres-bookings/ postgres-bookings/
.github/ .github/
.gitea/
.claude/ .claude/
site/ site/
AGENTS.md AGENTS.md
@@ -75,12 +76,12 @@ markdown_extensions:
extra: extra:
social: social:
- icon: fontawesome/brands/telegram
link: https://t.me/dementev_dev
name: Написать в Telegram
- icon: fontawesome/brands/github - icon: fontawesome/brands/github
link: https://github.com/dementev-dev/de-roadmap link: https://github.com/dementev-dev/de-roadmap
name: GitHub name: GitHub
- icon: fontawesome/brands/telegram
link: https://t.me/dementev_dev
name: Написать в Telegram
plugins: plugins:
- same-dir - same-dir
+3
View File
@@ -1,6 +1,9 @@
# ADR: Архитектура сайта de-roadmap # ADR: Архитектура сайта de-roadmap
> Архитектурный документ. Проектные цели и требования — в [PRD](./PRD.md). > Архитектурный документ. Проектные цели и требования — в [PRD](./PRD.md).
> Решения о публикации и custom domain заменены спецификацией
> [«Публикация сайта через Gitea Actions и VPS»](./specs/2026-08-04-gitea-vps-site-publishing.md).
> Решения о MkDocs, структуре файлов и ссылках остаются актуальными.
--- ---
+12 -4
View File
@@ -8,7 +8,13 @@
### Текущее состояние ### Текущее состояние
Роадмап по Data Engineering живёт как GitHub-репозиторий ([dementev-dev/de-roadmap](https://github.com/dementev-dev/de-roadmap)): Роадмап по Data Engineering живет как Git-репозиторий. Основной origin
и работа над материалами остаются в собственной Gitea
([ddmitry/de-roadmap](https://git.dementev.space/ddmitry/de-roadmap)).
После восстановления аккаунта GitHub изменения зеркалируются туда средствами
Gitea. Ссылки для менти ведут на [GitHub](https://github.com/dementev-dev/de-roadmap),
откуда удобно клонировать стенды и делать свои форки. Сайт по-прежнему
публикуется через Gitea Actions на VPS; GitHub Pages сохраняется как резерв.
- Основной контент — монолитный `README.md` (~700 строк) с полным учебным планом. - Основной контент — монолитный `README.md` (~700 строк) с полным учебным планом.
- Дополнительные материалы — в подпапках (`dwh-modeling/`, `postgres-bookings/`): теория DWH-моделирования, SCD, Data Vault, домашние задания, скрипты. - Дополнительные материалы — в подпапках (`dwh-modeling/`, `postgres-bookings/`): теория DWH-моделирования, SCD, Data Vault, домашние задания, скрипты.
@@ -74,7 +80,8 @@ GitHub README — рабочий, но не презентабельный фо
**Деплой:** **Деплой:**
- [x] Автоматическая сборка и публикация при пуше в `main`. - [x] Автоматическая сборка и публикация при пуше в `main`.
- [x] Бесплатный хостинг (GitHub Pages). - [x] Публикация без дополнительных расходов: собственная VPS как основной
контур, GitHub Pages как резерв.
**Совместимость с репо:** **Совместимость с репо:**
@@ -84,7 +91,8 @@ GitHub README — рабочий, но не презентабельный фо
### 4.2. Желательные (Спринт 2+) ### 4.2. Желательные (Спринт 2+)
- [x] Кастомный домен: `de.dementev.space` (подключён 2026-03-27). - [x] Кастомный домен: `de.dementev.space` (подключён 2026-03-27, переведён на
VPS 2026-08-05).
- [x] Тёмная тема (переключатель light/dark). - [x] Тёмная тема (переключатель light/dark).
- [x] Сворачиваемые блоки (`<details>`) — точечно, для подсказок/решений в домашках (2026-03-29). - [x] Сворачиваемые блоки (`<details>`) — точечно, для подсказок/решений в домашках (2026-03-29).
- [x] Кнопка «Написать в Telegram» — floating-кнопка + иконки в футере (2026-03-29). - [x] Кнопка «Написать в Telegram» — floating-кнопка + иконки в футере (2026-03-29).
@@ -158,7 +166,7 @@ GitHub README — рабочий, но не презентабельный фо
| Кириллические якоря рендерятся по-разному | Средняя | Среднее | Тестирование конкретного генератора; при необходимости — латинские id | | Кириллические якоря рендерятся по-разному | Средняя | Среднее | Тестирование конкретного генератора; при необходимости — латинские id |
| Генератор сайта перестаёт поддерживаться | Низкая | Среднее | Контент в plain Markdown — миграция на другой генератор за день | | Генератор сайта перестаёт поддерживаться | Низкая | Среднее | Контент в plain Markdown — миграция на другой генератор за день |
| Накладные расходы на поддержку растут | Низкая | Среднее | Принцип «сайт опционален»: если мешает — удаляем конфиг, репо работает | | Накладные расходы на поддержку растут | Низкая | Среднее | Принцип «сайт опционален»: если мешает — удаляем конфиг, репо работает |
| GitHub Pages ограничения (bandwidth, размер) | Очень низкая | Низкое | Для статического сайта с текстом — не актуально | | VPS временно недоступна | Низкая | Высокое | Опубликованный сайт не зависит от Gitea; GitHub Pages сохраняется как ручной резерв |
--- ---
+43
View File
@@ -4,8 +4,29 @@
## P1 ## P1
- [ ] **Проверить синхронизацию GitHub-зеркала `airflow-greenplum`.**
Проверка через `git ls-remote` 2026-09-27: GitHub отстает от Gitea
на коммит `4ed7e6f`, меняющий только `docs/agents/triage-labels.md`.
Учебные материалы совпадают. У `airflow-manual`, `mini-lakehouse-lab`
и `de-roadmap` ветки `main` в Gitea и GitHub совпали; прежнее подозрение
об их отставании по ответам API не подтвердилось.
## P2 ## P2
- [ ] **Проработать инструкции по прохождению крупных блоков.**
Начать с Python: определить части внешних курсов, глубину изучения
и практику для бесплатной альтернативы. Далее связать DEV1, книгу и QPT,
затем главы Airflow с существующими заданиями.
[Черновик обсуждения](specs/2026-09-27-learning-route.md).
- [ ] **Дополнить практику Kafka перед Clickstream.**
В `nifi-kafka-postgres-lab` добавить опыты на существующем потоке:
остановить потребителя и дочитать накопившиеся сообщения; прочитать
события двумя независимыми consumer groups; повторить чтение и проверить
дубли в PostgreSQL. Для каждого опыта описать исходное состояние,
действия и проверку результата. Идея согласована 2026-09-27;
реализация в репозитории стенда еще не начата.
- [ ] **Перенос учебника Airflow в de-roadmap.** - [ ] **Перенос учебника Airflow в de-roadmap.**
Перенести 9 глав учебника из `airflow-manual` в `airflow/` (de-roadmap). Перенести 9 глав учебника из `airflow-manual` в `airflow/` (de-roadmap).
В `airflow-manual` оставить только стенд (`airflow-docker/`). В `airflow-manual` оставить только стенд (`airflow-docker/`).
@@ -41,6 +62,28 @@
## Сделано ## Сделано
- [x] **Исправлена ссылка на практику Airflow** — 2026-10-18:
`educational-tasks.md` перенесён в корень `airflow-manual`; ссылка в роадмапе
обновлена, новая страница возвращает HTTP 200. Проверены HTTP-ответы
118 внешних адресов; единственный полученный 404 исправлен. Ответы
403/502 и капча не подтверждают недоступность материала для читателя;
доступность видео YouTube по HTTP-статусу не определяется.
- [x] **Актуализация маршрута и учебных ссылок** - 2026-09-27:
ссылки на стенды, SQL и данные, кнопки репозитория на сайте возвращены
на GitHub; рабочий origin и публикация сайта остаются в Gitea.
Streaming и ClickHouse включены в основную программу перед трудоустройством,
`clickstream-data-platform` стал второй, большой курсовой с критериями
прохождения. Ссылка на курс ClickHouse для аналитика удалена.
venv и JupyterLab перенесены перед курсом Python для продвинутых;
в альтернативу курсу для профи добавлены материалы по управлению памятью
и критерий проверки понимания.
- [x] **Публикация сайта перенесена на Gitea Actions и VPS** —
2026-08-05: настроены repository-scoped host runner, строгая сборка MkDocs,
атомарные релизы, nginx и TLS для `de.dementev.space`; GitHub Pages сохранён
как неактивный резерв.
- [x] **Подраздел «Linux и терминал» в блоке базовых инструментов** — - [x] **Подраздел «Linux и терминал» в блоке базовых инструментов** —
2026-07-12: видео-интро («Девопс на троечку», покрытие проверено по 2026-07-12: видео-интро («Девопс на троечку», покрытие проверено по
субтитрам) + три статьи (навигация и grep — habr, права — FirstVDS, субтитрам) + три статьи (навигация и grep — habr, права — FirstVDS,
+283
View File
@@ -0,0 +1,283 @@
# Эксплуатация публикации `de.dementev.space`
Этот runbook реализует спецификацию
[`2026-08-04-gitea-vps-site-publishing.md`](../../specs/2026-08-04-gitea-vps-site-publishing.md).
Команды рассчитаны на Ubuntu 26.04 и Gitea 1.27.
## Зафиксированные параметры
- Gitea Runner: `2.3.0`, Linux amd64.
- SHA256: `1e9fb1bea022fdf40993ecbc1a13e87db1bfd3d7f42666e37f15f71d840d53b3`.
- Runner: repository-scoped, метка `de-roadmap-host:host`.
- Пользователь сервиса: `gitea-runner`, без `sudo` и Docker.
- Корень публикации: `/srv/de-roadmap`.
- Хранение: текущий релиз и две предыдущие версии.
- Окружение сборки: `/var/lib/gitea-runner/venvs/site`.
- Публичный IPv4 VPS: `167.224.64.252`.
## Предварительные условия
- Есть пользователь с `sudo` и рабочий SSH-доступ к VPS.
- Есть доступ к управлению DNS-зоной `dementev.space`.
- В репозитории `ddmitry/de-roadmap` включены Gitea Actions.
## Подготовка VPS
Установить Git, HTTP-сервер, Certbot, UFW и Python venv:
```bash
sudo apt-get update
sudo apt-get install \
ca-certificates \
certbot \
curl \
git \
jq \
nginx \
python3-certbot-nginx \
python3-venv \
ufw
```
Получить административный checkout, из которого устанавливаются tracked-файлы:
```bash
git clone https://git.dementev.space/ddmitry/de-roadmap.git
cd de-roadmap
```
Создать пользователя и каталоги:
```bash
sudo useradd \
--system \
--home-dir /var/lib/gitea-runner \
--create-home \
--shell /usr/sbin/nologin \
gitea-runner
sudo install -d -o gitea-runner -g gitea-runner -m 0755 \
/var/lib/gitea-runner/workspaces \
/srv/de-roadmap \
/srv/de-roadmap/releases
sudo install -d -o root -g root -m 0755 /etc/gitea-runner
```
Скачать runner во временный каталог, сверить checksum и установить root-owned
бинарник в `/usr/local/bin/gitea-runner`:
```bash
runner_tmp_dir=$(mktemp -d /tmp/de-roadmap-runner.XXXXXX)
curl -fsSLo "${runner_tmp_dir}/gitea-runner" \
https://dl.gitea.com/gitea-runner/2.3.0/gitea-runner-2.3.0-linux-amd64
printf '%s %s\n' \
'1e9fb1bea022fdf40993ecbc1a13e87db1bfd3d7f42666e37f15f71d840d53b3' \
"${runner_tmp_dir}/gitea-runner" \
| sha256sum --check
sudo install -o root -g root -m 0755 \
"${runner_tmp_dir}/gitea-runner" /usr/local/bin/gitea-runner
rm "${runner_tmp_dir}/gitea-runner"
rmdir "$runner_tmp_dir"
```
Из корня репозитория установить конфигурацию и unit:
```bash
sudo install -o root -g root -m 0644 \
project/ops/gitea-vps-site/gitea-runner.yaml \
/etc/gitea-runner/config.yaml
sudo install -o root -g root -m 0644 \
project/ops/gitea-vps-site/gitea-runner.service \
/etc/systemd/system/gitea-runner.service
sudo systemd-analyze verify /etc/systemd/system/gitea-runner.service
```
## Регистрация runner
Repository registration token получают в Gitea:
`ddmitry/de-roadmap` → Settings → Actions → Runners. Токен не сохраняют в Git
или shell history. Временный файл с токеном создают с владельцем
`gitea-runner:gitea-runner` и режимом `0600`. После регистрации файл
`/var/lib/gitea-runner/.runner` должен принадлежать тому же пользователю и
иметь режим `0600`.
Token-file должен содержать ровно 40 символов без завершающего перевода строки.
При извлечении JSON-ответа через `jq` использовать `jq --join-output '.token'`,
а не `jq --raw-output`, который добавляет newline.
```bash
sudo -u gitea-runner \
/usr/local/bin/gitea-runner \
--config /etc/gitea-runner/config.yaml \
register \
--no-interactive \
--instance https://git.dementev.space \
--token-file /var/lib/gitea-runner/.registration-token \
--name de-roadmap-vps
sudo rm /var/lib/gitea-runner/.registration-token
sudo chmod 0600 /var/lib/gitea-runner/.runner
sudo systemctl daemon-reload
sudo systemctl enable --now gitea-runner
systemctl is-enabled gitea-runner
systemctl is-active gitea-runner
```
Временный файл с токеном удаляют сразу после успешной регистрации. В Gitea на
странице Settings → Actions → Runners runner `de-roadmap-vps` должен перейти в
состояние online и показывать метку `de-roadmap-host`.
## Nginx и первичная публикация
Из корня репозитория установить bootstrap-конфигурацию nginx, создать ссылку,
отключить стандартный сайт Ubuntu и только затем перечитать проверенную
конфигурацию:
```bash
sudo install -o root -g root -m 0644 \
project/ops/gitea-vps-site/nginx.conf \
/etc/nginx/sites-available/de-roadmap
sudo ln -s \
/etc/nginx/sites-available/de-roadmap \
/etc/nginx/sites-enabled/de-roadmap
sudo unlink /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
```
Первый server block в `nginx.conf` возвращает `404` для неизвестных HTTP Host,
не раскрывает версию nginx и отклоняет TLS handshake для IP или неизвестного
SNI. Поэтому сертификат `de.dementev.space` не выдаётся при обращении к VPS по
IP. Если проверка конфигурации не прошла, отключить новый virtual host,
восстановить стандартный сайт и перечитать проверенную конфигурацию:
```bash
sudo unlink /etc/nginx/sites-enabled/de-roadmap
sudo ln -s \
/etc/nginx/sites-available/default \
/etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
```
Файл `project/ops/gitea-vps-site/nginx.conf` предназначен только для запуска до
выпуска сертификата. После выпуска сертификата Certbot изменяет установленный
virtual host. Повторная установка bootstrap-файла поверх рабочего конфига
удалит TLS-директивы.
## Окружение сборки
Скрипт `.gitea/scripts/build-site.sh` создаёт persistent venv при первом запуске
и переиспользует его в следующих сборках. `pip install` выполняется каждый раз,
чтобы применить изменения `.gitea/requirements-site.txt`, но уже установленные
версии пакетов не переустанавливаются.
## Первый деплой
В Gitea открыть Actions → Deploy MkDocs to VPS, выбрать ветку `main` и нажать
Run workflow. Job `deploy` должен завершиться успешно. Проверить опубликованный
release и локальную выдачу nginx до переключения DNS:
```bash
readlink -f /srv/de-roadmap/current
curl --fail --header 'Host: de.dementev.space' http://127.0.0.1/
```
Затем разрешить SSH, HTTP и HTTPS в UFW. Если SSH работает не на стандартном
порту `22`, сначала разрешить фактический порт вместо профиля `OpenSSH`:
```bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose
```
Ожидается политика `deny (incoming)` и разрешения только для SSH, `80/tcp` и
`443/tcp`.
## DNS и TLS
1. Уменьшить TTL записи `de.dementev.space`.
2. Направить `A` на VPS; удалить или корректно направить `AAAA`.
3. Убедиться, что сайт доступен извне по HTTP:
```bash
curl --fail --head http://de.dementev.space/
```
4. Выпустить сертификат и включить перенаправление HTTP на HTTPS:
```bash
sudo certbot --nginx \
--non-interactive \
--agree-tos \
--email me@dementev.space \
--redirect \
-d de.dementev.space
```
5. В созданном Certbot HTTP-блоке для `de.dementev.space` добавить
`server_tokens off;`, затем проверить и перечитать конфигурацию:
```bash
sudoedit /etc/nginx/sites-available/de-roadmap
sudo nginx -t
sudo systemctl reload nginx
```
6. Проверить перенаправление, HTTPS, сертификат и автоматическое продление:
```bash
curl --head http://de.dementev.space/
curl --fail --head https://de.dementev.space/
! curl --insecure --head https://167.224.64.252/
sudo certbot certificates
systemctl is-enabled certbot.timer
systemctl is-active certbot.timer
```
Ожидаются `301 Moved Permanently`, затем `200 OK`, отказ TLS по IP,
действующий сертификат и состояния таймера `enabled` и `active`.
7. Вернуть обычный DNS TTL.
## Проверка и откат
Активная версия определяется ссылкой `/srv/de-roadmap/current`. Для ручного
отката сначала выбрать точный release id из сохранённых каталогов, затем создать
временную ссылку и атомарно заменить `current`:
```bash
find /srv/de-roadmap/releases \
-mindepth 1 \
-maxdepth 1 \
-type d \
-printf '%f\n' \
| sort
rollback_release='<COMMIT_SHA>-<RUN_ID>'
rollback_link='/srv/de-roadmap/.current.rollback'
[[ "$rollback_release" =~ ^[0-9a-f]{40}-[0-9]+$ ]]
sudo test -d "/srv/de-roadmap/releases/${rollback_release}"
sudo test ! -e "$rollback_link"
sudo -u gitea-runner \
ln -s "releases/${rollback_release}" "$rollback_link"
sudo -u gitea-runner \
mv -Tf "$rollback_link" /srv/de-roadmap/current
readlink -f /srv/de-roadmap/current
curl --fail --head https://de.dementev.space/
```
Откат не удаляет более новые releases. Перед их ручным удалением всегда
проверять результат `readlink -f /srv/de-roadmap/current`.
Диагностика:
```bash
sudo systemctl status gitea-runner
sudo journalctl -u gitea-runner
sudo nginx -t
readlink -f /srv/de-roadmap/current
curl --fail --head https://de.dementev.space/
```
@@ -0,0 +1,45 @@
[Unit]
Description=Gitea Actions runner for de-roadmap
Documentation=https://docs.gitea.com/usage/actions
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=gitea-runner
Group=gitea-runner
WorkingDirectory=/var/lib/gitea-runner
ExecStart=/usr/local/bin/gitea-runner daemon --config /etc/gitea-runner/config.yaml
Restart=always
RestartSec=10s
TimeoutStopSec=45s
KillMode=mixed
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
UMask=0022
NoNewPrivileges=true
PrivateDevices=true
PrivateTmp=true
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectSystem=strict
ReadWritePaths=/var/lib/gitea-runner /srv/de-roadmap
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
CapabilityBoundingSet=
SystemCallArchitectures=native
MemoryMax=1G
CPUQuota=100%
TasksMax=128
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,37 @@
log:
level: info
runner:
file: /var/lib/gitea-runner/.runner
capacity: 1
timeout: 15m
shutdown_timeout: 30s
insecure: false
fetch_timeout: 5s
fetch_interval: 2s
fetch_interval_max: 10s
workdir_cleanup_age: 24h
idle_cleanup_interval: 10m
labels:
- "de-roadmap-host:host"
allocate_pty: false
cache:
enabled: false
container:
valid_volumes: []
docker_host: "-"
require_docker: false
host:
workdir_parent: /var/lib/gitea-runner/workspaces
health_check:
enabled: true
min_free_disk_space_mb: 1024
interval: 30s
timeout: 10s
metrics:
enabled: false
+34
View File
@@ -0,0 +1,34 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
server_tokens off;
ssl_reject_handshake on;
return 404;
}
server {
listen 80;
listen [::]:80;
server_name de.dementev.space;
root /srv/de-roadmap/current;
index index.html;
charset utf-8;
server_tokens off;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
try_files $uri $uri/ =404;
}
location ~ /\. {
deny all;
}
}
@@ -0,0 +1,126 @@
# Публикация сайта через Gitea Actions и VPS
Статус: публикация на VPS реализована 2026-08-05. После восстановления
доступа к GitHub выбран встроенный push mirror Gitea для синхронизации
репозиториев; рабочий origin остается в Gitea. Инструкции по
восстановлению и эксплуатации находятся в
[`project/ops/gitea-vps-site/README.md`](../ops/gitea-vps-site/README.md).
## Проблема
Сайт `de.dementev.space` публиковался через GitHub Actions и GitHub Pages. После блокировки учётной записи GitHub основной домен стал недоступен, хотя исходный Markdown и конфигурация MkDocs сохранились, а основной Git-репозиторий уже размещён в собственной Gitea.
Публикация сайта не должна зависеть от доступности учётной записи GitHub. При этом рабочий процесс из исходной архитектуры сохраняется: изменение попадает в `main`, сайт собирается и обновляется автоматически без отдельного ручного деплоя.
## Цели
- Публиковать `de.dementev.space` с существующей VPS.
- Запускать сборку и публикацию автоматически после push в `main` в Gitea.
- Не заменять работающую версию сайта, если получение исходников или строгая сборка MkDocs завершились ошибкой.
- Ограничить права runner каталогами, необходимыми для сборки и публикации сайта.
- Сохранить GitHub Pages как заранее собираемый резерв на случай проблем с VPS.
- Сохранить минимальные накладные расходы и нулевые дополнительные расходы на хостинг.
## Не цели
- Автоматическое переключение между VPS и GitHub Pages.
- Жёсткие требования к времени восстановления или высокой доступности.
- Перенос еженедельной проверки внешних ссылок с GitHub Actions в Gitea Actions.
- Изменение существующих файлов в `.github/workflows/`.
- Добавление динамического приложения, авторизации или серверной базы данных.
## Исходное состояние на 2026-08-04
- MkDocs Material собирает статический каталог `site/`; `site_url` уже равен `https://de.dementev.space/`.
- Публичный репозиторий `ddmitry/de-roadmap` в Gitea является текущим `origin`.
- Gitea Actions для репозитория включены, но подходящего runner пока нет.
- Gitea видит существующие GitHub workflows, однако они зависят от GitHub Pages, GitHub-токенов и сторонних actions.
- На VPS, выбранной для сайта, пока нет HTTP-сервера; публично доступен только SSH.
## Выбранное решение
### Основной контур публикации
Gitea становится источником событий для основной публикации. На VPS с сайтом работает repository-scoped Gitea runner, зарегистрированный только для `de-roadmap`. Runner использует host mode и отдельную метку, предназначенную только для этого workflow.
Workflow хранится отдельно в `.gitea/workflows/deploy-site.yml`. Gitea выбирает `.gitea/workflows` раньше `.github/workflows`, поэтому GitHub-specific workflows сохраняются в репозитории, но не исполняются Gitea.
Workflow запускается после push в `main` и вручную. Он получает конкретный commit из публичного Gitea-репозитория обычным Git, создаёт изолированное Python-окружение, устанавливает закреплённые версии зависимостей и выполняет строгую сборку MkDocs. Сторонние `uses:` не применяются, поэтому сборка не зависит от GitHub Actions Marketplace.
### Изоляция runner
Runner работает как отдельный непривилегированный системный пользователь. У него нет `sudo`, членства в группе `docker` и доступа на запись к конфигурации nginx, сертификатам или другим сервисам VPS.
Пользователь runner может записывать только в собственный рабочий каталог и каталог релизов сайта. Workflow не запускается для pull request из недоверенных веток. Потребление памяти, CPU и количество процессов ограничиваются средствами менеджера сервисов операционной системы.
### Публикация и восстановление после ошибки
Каждая успешная сборка создаёт отдельную версию статического сайта. Новая версия становится активной только после завершения всех проверок. Переключение между версиями выполняется атомарно; частично собранный каталог никогда не становится корнем сайта.
Ошибка получения исходников, установки зависимостей или сборки оставляет активной предыдущую версию. Как минимум одна предыдущая успешная версия сохраняется для быстрого ручного отката.
### HTTP и HTTPS
Статические файлы обслуживает штатный nginx из репозитория Ubuntu. Nginx только читает активную версию сайта и не требует перезагрузки при обычной публикации контента.
TLS-сертификат для `de.dementev.space` получает и продлевает Certbot с интеграцией nginx. Перед переключением проверяются локальная сборка и конфигурация nginx, а DNS TTL заранее уменьшается. Затем DNS направляется на VPS, проверяется публичная доступность по HTTP и выпускается сертификат. Короткий интервал между переключением DNS и готовностью HTTPS допустим, поскольку жёсткого требования к непрерывной доступности нет.
### Резерв на GitHub Pages
Изменения из основной Gitea передаются на GitHub встроенным push mirror.
Ссылки для учащихся ведут на GitHub-зеркала, основной домен остается на VPS.
Workflow в `.github/workflows/deploy-site.yml` сохранен для резервной
публикации. Перед использованием резерва нужно проверить настройки Pages
и успешный деплой: наличие зеркала репозитория само по себе этого не подтверждает.
GitHub Pages считается тёплым резервом контента и холодным резервом домена. При отказе VPS владелец вручную переключает DNS и при необходимости повторно активирует custom domain в настройках GitHub Pages. Допустимы задержка распространения DNS и ожидание выпуска TLS-сертификата; автоматический failover не требуется.
## Отклонённые варианты
- **Периодический pull с VPS:** проще инфраструктурно, но не даёт опыта работы с Gitea runner и менее наглядно связывает push с результатом сборки.
- **Runner рядом с Gitea:** усложняет доставку результата на VPS и позволяет сборкам влиять на ресурсы Git-сервера.
- **Jobs в Docker:** дают лучшую изоляцию, но требуют доступа runner к Docker и отдельного механизма передачи результата в каталог nginx. Для одного доверенного репозитория это лишняя сложность.
- **Caddy вместо nginx:** упрощает автоматический TLS, но штатный nginx лучше соответствует предпочтению владельца и доступен с обновлениями безопасности из основного репозитория Ubuntu. Certbot закрывает задачу TLS отдельно.
- **Cloudflare Pages, GitLab Pages или другой внешний Pages-сервис:** уменьшают нагрузку на VPS, но добавляют новую внешнюю учётную запись и зависимость, от которой как раз уходим.
- **Ожидание разблокировки GitHub:** сохраняет старую архитектуру, но оставляет сайт недоступным на неопределённый срок.
## Риски и меры
| Риск | Мера |
|------|------|
| Workflow исполняет команды непосредственно на VPS | Repository-scoped runner, отдельный пользователь без `sudo` и Docker, узкие права на запись, запуск только из `main`, системные лимиты ресурсов |
| Ошибка сборки ломает опубликованный сайт | Сборка в отдельной версии и атомарное переключение только после успеха |
| Сторонний action выполняет неожиданный код | Workflow состоит из собственных команд и не использует `uses:` |
| Gitea временно недоступна | Уже опубликованный сайт обслуживается независимо от Gitea |
| VPS недоступна или потеряна | Исходники остаются в Gitea; GitHub Pages служит ручным резервом после проверки резервной публикации |
| После переключения DNS HTTPS ещё не готов | DNS TTL уменьшается заранее; Certbot запускается сразу после подтверждения публичного HTTP; короткий перерыв принят как допустимый |
| Сертификат GitHub Pages не готов во время аварии | Допускается задержка; на время восстановления используется стандартный адрес GitHub Pages |
| GitHub-резерв отстает от Gitea | Проверяем результат push mirror, совпадение коммитов и резервную сборку; до успешной проверки резерв не считается готовым |
## Проверка реализации
- Runner после перезагрузки VPS автоматически подключается к Gitea и принимает только jobs с выделенной меткой.
- Push тестового изменения в `main` запускает ровно один Gitea workflow и публикует соответствующий commit.
- Gitea не запускает workflows из `.github/workflows/`, а сами файлы остаются без изменений.
- Workflow не обращается к GitHub за actions и не требует GitHub-токенов.
- Ошибка `mkdocs build --strict` завершает workflow с ошибкой и не изменяет публичную версию сайта.
- Успешная сборка переключает сайт целиком, без периода частично обновлённого содержимого.
- Пользователь runner не может использовать `sudo`, Docker или изменять конфигурацию nginx.
- `https://de.dementev.space/` отдаёт собранный сайт с действующим сертификатом после переключения DNS.
- Nginx и runner восстанавливаются после перезагрузки VPS без ручного запуска.
- После восстановления GitHub и настройки синхронизации резервная сборка получает тот же commit и остаётся доступна по стандартному адресу GitHub Pages.
## Влияние на документацию
Эта спецификация заменяет решения о публикации и custom domain из `project/ADR.md`. Решения того документа о MkDocs Material, структуре файлов и dual-compatible links остаются актуальными.
Документация проекта описывает Gitea Actions и VPS как основной контур
публикации. Ссылки репозитория в `mkdocs.yml` направлены на GitHub для менти;
рабочий origin остается в Gitea.
## Синхронизация GitHub
Способ синхронизации выбран: встроенный Gitea push mirror. Рабочие изменения
вносятся в Gitea, GitHub используется как зеркало для чтения и создания
учебных форков. Нужно отдельно проверить работу зеркал всех стендов и
готовность резервной публикации Pages.
@@ -0,0 +1,86 @@
# Как проходить материалы роадмапа
Статус: черновик для обсуждения. Базовая актуализация опубликована отдельно
в коммите `806417c`. Здесь прорабатываем следующий этап: письменные указания
по порядку занятий, глубине чтения и выполнению заданий.
## Задача
На занятиях ментор регулярно объясняет, какие части внешнего курса нужны
целиком, где достаточно нескольких упражнений и когда переходить к стенду.
Эти указания должны быть доступны рядом с материалами, до начала работы.
Предлагаемый формат: в README оставить общий маршрут. Подробные инструкции
к крупным блокам вынести на отдельные страницы со ссылками из этих разделов.
У каждого шага должны быть понятны материал, глубина изучения, практика
и результат, с которым можно переходить дальше.
## Какие вопросы должна закрыть инструкция
- Какие части внешних курсов Python нужны для дальнейшей практики?
- Насколько подробно изучать устройство PostgreSQL в QPT?
- Какие главы книги прочитать перед конкретными лекциями DEV1?
- Как поддерживать SQL-практику после перехода к следующему блоку?
- Когда запускать каждый стенд и какие задания на нем выполнять?
Объем упражнений связываем с проверяемыми умениями. Индивидуальные сроки
и сокращения программы не превращаем в требования ко всем учащимся.
## Что уже определено
- Docker впервые используем на DEV1: запускаем PostgreSQL, проверяем статус,
подключаемся к базе. Подробный блок Docker остается дальше.
- Data Vault и Anchor Modeling изучаем обзорно.
- venv и JupyterLab осваиваем перед Python для продвинутых.
- Greenplum остается первой курсовой; Kafka, ClickHouse и Clickstream входят
в основную программу. Lakehouse и dbt идут после нее.
- Задания Python и SQL в Airflow уже есть. Для них нужна привязка к чтению
учебника и моменту выполнения.
- Опыты с Kafka записаны отдельной задачей в [TODO](../TODO.md).
## Первый блок для проработки: Python
Собрать инструкцию к существующим курсам и бесплатным материалам.
Начальный вариант границ для проверки:
| Тема | Как проходить | Как проверить результат |
|---|---|---|
| Вложенные списки и матрицы | Выборочные упражнения на механику | Самостоятельно обойти и изменить вложенный список |
| Словари, функции, файлы | Подробно, с практикой | Прочитать данные, преобразовать их и сохранить результат |
| Turtle и Monte Carlo | Можно пропустить в основном маршруте | Отдельная проверка не нужна |
| Память и ссылки, исключения, итераторы и генераторы | Включить и в курс, и в бесплатную альтернативу | Объяснить поведение небольшого примера и самостоятельно изменить его |
Два варианта после advanced Python должны приводить к одному набору умений:
выбранные части Python Professional или последовательность бесплатных
материалов с упражнениями. Особенно проверить покрытие управления памятью
и обработки исключений.
Перед публикацией нужно сверить актуальное оглавление обоих курсов,
подобрать точные разделы и определить достаточную практику. Проценты заданий
из отдельной встречи не заменяют этого отбора. Также нужно уточнить глубину
ООП, pandas и декораторов для дальнейших заданий Airflow.
## Следующие кандидаты
Для DEV1 связать лекции, главы книги и практику на `postgres-bookings`.
Например, чтение о транзакциях поставить перед темой MVCC. На входе пояснить,
где выполняются команды: терминал, `psql`, редактор SQL в DBeaver.
Для QPT описать результат первого прохода и возвращение к теме позже.
Предлагаемый результат: прочитать план, сопоставить оценки с фактическими
строками, сформулировать и проверить гипотезу. Повторная практика должна
использовать уже знакомую базу и конкретный запрос.
Для Airflow сопоставить главы учебника с существующими заданиями.
В каждом переходе обозначить, что сначала разбираем по готовому примеру,
что делаем самостоятельно и как проверяем результат.
На переходах между крупными блоками напомнить о короткой регулярной практике
SQL, а после Python добавить и его поддержание. Объем подбирать по учебной
нагрузке; календарные сроки всей программы пока не фиксировать.
## Как оценить первый результат
На примере Python проверить, может ли читатель определить свой следующий шаг,
объем чтения и практики, способ проверки и условие перехода дальше.
После этого решить, подходит ли такой формат для остальных блоков.