В какой-то момент я понял, что живу в режиме вечного поиска. Договор аренды — где-то в почте, чеки на технику — в телеге, настройки ноутбука — в заметках, список задач — в пяти разных приложениях, а важные решения — в голове. Я попробовал собрать это как проект: git, структура папок, метаданные, шифрование, хуки, генерация коротких сводок и нормальные бэкапы. Рассказываю, как я это сделал, где облажался и какие куски кода реально помогают поддерживать порядок.

Почему git вообще подходит для личного архива, а не только для кода

Я раньше думал, что git для жизни звучит как мем. Но потом словил штуку, знакомую любому айтишнику: контекст теряется быстрее, чем кажется. Ты переезжаешь, меняешь телефон, ставишь новую систему, подписываешь новый контракт, и внезапно оказывается, что половина важных деталей лежит в разных местах, да ещё и без версий.

Git хорош не потому что модно, а потому что даёт три конкретные вещи:

  • История. Не просто финальная версия файла, а цепочка изменений. Ты обновил резюме, добавил новый проект, потом удалил, потом снова вернул. Ты поменял провайдера, тарифы, условия. Ты ведёшь лог своих домашних сетевых настроек, и наконец-то понимаешь, когда и почему оно сломалось.

  • Дифы. Когда ты обновил список доступов или настройки, сразу видно, что изменилось. И это не магия, это просто удобный взгляд на изменения.

  • Репликация. Репозиторий можно клонировать, зеркалировать, хранить на разных носителях, проверять целостность, автоматизировать бэкапы. В отличие от условных заметок в приложении, где ты зависишь от сервиса и его экспорта.

И тут вопрос к тебе. У тебя есть хотя бы один файл, который ты точно не хочешь потерять, но не уверен, где он лежит? У меня таких было десятки. Я устал.

Структура репозитория: как не утонуть в папках и перфекционизме

Главная ловушка личного архива в том, что хочется сделать идеально. Красивые схемы, таксономия, стандарты, всё по феншую. Я так и сделал. И, конечно, забросил через неделю.

Потом я сделал две вещи, которые реально спасли проект.

Первая вещь — это папка inbox. Всё новое падает туда вообще без разборки. Получил документ, файл, чек, письмо, экспорт — просто закинул. Разбор потом. Это снимает порог входа.

Вторая вещь — это простое ядро данных. Мне оказалось достаточно трёх слоёв:

  • Сырьё как есть. Оригинальные файлы, выгрузки, pdf, сканы, всё, что пришло.

  • Извлечённые факты. Небольшие yaml-карточки, где есть дата, тип, стороны, суммы, срок, ссылки на исходники.

  • Короткие сводки. Один файл, который я могу открыть на телефоне и быстро понять состояние дел.

Вот как у меня выглядит структура, без претензий на универсальность.

  • 00_inbox
    временная свалка, но контролируемая;

  • 10_profile
    базовая инфа, контакты, важные логины и доступы не храню тут, про это ниже;

  • 20_timeline
    помесячные записи, что произошло и что изменилось;

  • 30_documents
    договоры, аренда, страховки, учеба, визы, что угодно;

  • 40_finance
    бюджеты, подписки, платежи, возвраты, чеки;

  • 50_projects
    личные проекты, учебные штуки, портфолио, резюме;

  • 60_configs
    настройки устройств, сети, dotfiles, заметки по железу;

  • 90_exports
    выгрузки сервисов, чтобы не зависеть от того, что завтра они закроются.

Пример карточки документа, которую реально удобно обновлять.

type: contract
date_signed: 2025-09-01
title: apartment_rent
party_a: me
party_b: landlord
valid_until: 2026-08-31
amount:
  value: 25000
  currency: TRY
attachments:
  - ../30_documents/2025-09-01_rent_contract.pdf
notes:
  - deposit equals one month
  - utilities excluded

Такие yaml-файлы потом можно индексировать, проверять и собирать в сводки.

Приватность и безопасность: личный архив без паранойи не работает

Как только ты начинаешь складывать личные документы в одно место, оно становится супервкусной целью. Тут не надо быть безопасником, чтобы понять, что потери будут неприятные.

Я для себя разложил угрозы максимально просто:

  • Потеря устройства. Ноут украли, телефон утопил, диск умер.

  • Случайная утечка. Не тот файл отправил, не ту папку синхронизировал, не туда запушил.

  • Компрометация облака. Условно, хакнули сервис, утекли токены, или просто кто-то получил доступ к аккаунту.

Что я сделал в итоге.

Репозиторий лежит в зашифрованном контейнере, чтобы физический доступ к диску не решал ничего. Дальше я шифрую критичные файлы перед тем, как отправлять в удалённое хранилище. Не потому что я не доверяю диску, а потому что бэкап вне дома должен быть таким, чтобы его не было страшно потерять.

Пример скрипта на bash, который шифрует выбранные папки с помощью age и кладёт результат в отдельную директорию, чтобы не смешивать с рабочими файлами.

#!/usr/bin/env bash
set -euo pipefail

repo_dir="$(cd "$(dirname "$0")/.." && pwd)"
out_dir="$repo_dir/.encrypted"
recipients_file="$repo_dir/keys/recipients.txt"

mkdir -p "$out_dir"

include_dirs=(
  "10_profile"
  "20_timeline"
  "30_documents"
  "40_finance"
)

recipient_args=()
while IFS= read -r r; do
  [ -n "$r" ] && recipient_args+=(-r "$r")
done < "$recipients_file"

for d in "${include_dirs[@]}"; do
  find "$repo_dir/$d" -type f ! -name "*.age" -print0 | while IFS= read -r -d '' f; do
    rel="${f#$repo_dir/}"
    out="$out_dir/$rel.age"
    mkdir -p "$(dirname "$out")"
    age "${recipient_args[@]}" -o "$out" "$f"
  done
done

echo "encrypted written to $out_dir"

И да, ключи нельзя хранить рядом. Я держу приватный ключ отдельно, плюс резерв на втором носителе. Не суперудобно, зато потом спишь спокойнее.

Автоматизация, чтобы архив не превратился в кладбище файлов

Самое обидное — когда ты красиво начал, а потом перестал поддерживать. Я видел это у себя пару раз. Поэтому я добавил минимум автоматики, который не бесит, но держит дисциплину:

  • Первое правило: inbox нельзя коммитить. Иначе ты просто легализуешь свалку.

  • Второе правило: у важных файлов должны быть даты и понятные имена. Без этого поиск превращается в археологию.

  • Третье правило: метаданные должны проходить проверку. Иначе yaml карточки быстро деградируют.

Вот мой pre-commit hook, который ловит самые тупые ошибки.

#!/usr/bin/env bash
set -euo pipefail

fail() { echo "hook failed: $1" >&2; exit 1; }

staged="$(git diff --cached --name-only)"

echo "$staged" | grep -q '^00_inbox/' && fail "move files out of 00_inbox before commit"

# проверяем, что yaml-карточки документов содержат ключевые поля
changed_yaml="$(echo "$staged" | grep -E '^(30_documents|40_finance)/.*\.yaml$' || true)"
for f in $changed_yaml; do
  python3 scripts/validate_cards.py "$f"
done

# запрещаем огромные бинарники в обычном git
changed_bin="$(echo "$staged" | grep -E '\.(pdf|zip|png|jpg)$' || true)"
for f in $changed_bin; do
  size="$(wc -c < "$f")"
  if [ "$size" -gt 25000000 ]; then
    fail "file too big for normal git: $f"
  fi
done

echo "ok"

А вот валидатор карточек на Python. Очень простой, но уже ловил мне косяки.

#!/usr/bin/env python3
import sys
import yaml

REQUIRED = ["type", "title"]

def die(msg: str) -> None:
    print(msg, file=sys.stderr)
    sys.exit(1)

path = sys.argv[1]
with open(path, "r", encoding="utf-8") as f:
    doc = yaml.safe_load(f)

if not isinstance(doc, dict):
    die(f"{path}: root must be a mapping")

for k in REQUIRED:
    if k not in doc or doc[k] in (None, ""):
        die(f"{path}: missing {k}")

# опциональная проверка даты, если она есть
for date_key in ("date_signed", "date", "paid_at"):
    if date_key in doc and isinstance(doc[date_key], str):
        if len(doc[date_key]) < 10:
            die(f"{path}: suspicious date in {date_key}")

print(f"{path}: ok")

Честно, эти две штуки сделали больше, чем любые красивые идеи. Потому что поддержка — это рутина, а рутина любит простые барьеры.

Тяжёлые файлы и целостность: LFS, манифесты и почему хэши спасают нервы

В какой-то момент в архиве появляются сканы, фото, большие pdf, экспорты, иногда даже видео. Если это всё бездумно коммитить, репозиторий начнёт пухнуть и умирать. Я пошёл по гибридной схеме:

  • Текст, yaml, небольшие документы живут в обычном git.

  • Крупные бинарники отправляю в git lfs, чтобы клон не превращался в скачивание всего мира.

  • Самые тяжёлые штуки, типа сырых экспортов и архивов, держу во внешнем vault, а в репо храню индекс и контро��ьные суммы.

  • Контрольные суммы вообще underrated вещь. Когда ты переносишь архивы между дисками, ты не хочешь гадать, битый файл или нет. Ты хочешь проверить и забыть.

Скрипт на bash, который делает sha256 манифест для папки.

#!/usr/bin/env bash
set -euo pipefail

dir="${1:-90_exports}"
out="${2:-90_exports_manifest.sha256}"

find "$dir" -type f -print0 | sort -z | xargs -0 sha256sum > "$out"
echo "written $out"

А индекс файла я веду так.

type: export
date: 2026-01-10
source: bank_app
scope: transactions_2025
archive:
  path: /vault/personal/exports/2026-01-10_bank_2025.csv.zst
  sha256: 9b1c0f3d...cafe1234
notes:
  - contains categories and merchant names
  - imported into local ledger

Выглядит занудно, но это ровно та занудность, которая потом экономит часы. Особенно когда прошло полгода и ты вообще не помнишь, что где лежит.

Сводки и поисковый кайф: один файл, который заменяет миллион вкладок

Самая приятная часть личного архива — это когда ты перестаёшь искать. Не в смысле, что всё идеально, а в смысле, что у тебя появляется понятная точка входа.

Я сделал себе генератор сводки. Он берёт profile, последние изменения из timeline, список активных подписок, ближайшие даты продлений, и делает один markdown-файл. Его можно открыть на телефоне, перед поездкой, перед переездом, перед любым мутным событием, когда надо быстро вспомнить контекст.

Вот пример генератора на Python. Он специально без наворотов, чтобы работал везде.

#!/usr/bin/env python3
import os
import glob
import yaml
from datetime import datetime

REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))

def load_yaml(path: str):
    with open(path, "r", encoding="utf-8") as f:
        return yaml.safe_load(f)

def newest_files(pattern: str, limit: int = 5):
    files = glob.glob(os.path.join(REPO, pattern))
    files.sort(reverse=True)
    return files[:limit]

profile = load_yaml(os.path.join(REPO, "10_profile", "profile.yaml"))

lines = []
lines.append("# Личный дайджест\n")
lines.append(f"Обновлено: {datetime.now().strftime('%Y-%m-%d')}\n\n")

lines.append("## Контакты и базовое\n")
for k in ("name", "city", "email"):
    if k in profile:
        lines.append(f"- {k}: {profile[k]}\n")

lines.append("\n## Последние события\n")
for p in newest_files("20_timeline/*.md", 3):
    base = os.path.basename(p)
    lines.append(f"\n### {base}\n")
    with open(p, "r", encoding="utf-8") as f:
        chunk = f.read().strip().splitlines()[:20]
    lines.extend([x + "\n" for x in chunk])

lines.append("\n## Подписки и платежи\n")
subs_path = os.path.join(REPO, "40_finance", "subscriptions.yaml")
if os.path.exists(subs_path):
    subs = load_yaml(subs_path).get("active", [])
    for s in subs:
        lines.append(f"- {s.get('name','unknown')} next {s.get('next_charge','?')}  {s.get('amount','')}\n")

out = os.path.join(REPO, "10_profile", "digest.md")
with open(out, "w", encoding="utf-8") as f:
    f.write("".join(lines))

print("written:", out)

И вот тут у меня в конце дайджеста появляется маленький ритуал, который неожиданно оказался важнее всех скриптов. Я записываю коротко и суть.

Что сейчас самое слабое место? Где я точно забуду или затяну, если не ткнуть себя носом? Какие две вещи надо сделать на этой неделе, чтобы потом не разгребать месяц? Что я откладываю уже третий раз подряд? И есть ли что-то, что пора выкинуть из архива, потому что оно только захламляет и создаёт ложное ощущение контроля?

Прикол в том, что когда это пишешь рядом с фактами, оно перестаёт быть абстрактным. Не просто «надо бы заняться документами», а конкретно «обновить контакты», «продлить подписку», «закинуть экспорт», «проверить, что бэкап вообще открывается, а не лежит для галочки». Иногда я там же оставляю себе одну тупую, но полезную заметку: где я последний раз сломал систему. Например, когда кинул что-то в inbox и забыл разобрать, или когда сохранил файл как final_final2.pdf и сам же потом матерился.

И это, честно, очень разгружает голову. Потому что раньше всё это было в фоне: я помню, что где-то что-то важно, но не помню, что именно, и оно зудит. А тут ты открываешь один файл, видишь картину, понимаешь, что у тебя под контролем, а что нет, и закрываешь без ощущения вечного незавершённого квеста.

Если захочешь попробовать, не начинай с криптографии и хуков. Начни с простого: сделай репо, папку inbox, один профильный файл и один таймлайн за месяц. Поймай удовольствие от того, что ты что-то нашёл за 10 секунд, а не за 10 минут. А потом уже докрутишь шифрование, проверки и генераторы. Эта штука реально растёт постепенно, и в этом её кайф: ты просто перестаёшь терять важное.