Как это устроено внутри
CostView хранит финансы команд — поэтому страница не про «банковский уровень безопасности» в кавычках, а про конкретные технические решения, которые реально работают в коде.
Шифрование чувствительных данных
API-ключи платёжных провайдеров (Brocard и т.д.) шифруются в БД алгоритмом AES-256-GCM. Master-ключ хранится в env сервера, отдельно от базы — дамп БД сам по себе бесполезен без сервера. Пароли пользователей хранятся как bcrypt-хеш с солью; восстановить исходный пароль из БД невозможно.
Бэкапы
Hetzner Cloud Backups делают еженедельные снимки сервера на стороне провайдера, плюс ежедневный pg_dump базы внутри сервера с ретеншном 14 дней. Восстановление до любой точки за последние 7 дней — за минуты.
Защита логина
Сессии — JWT, секрет ротируется. Rate-limit на /login и /forgot-password: 5 попыток за 15 минут с одной пары email+IP, потом блок ещё на 15 минут. Soft-suspend для пользователей: данные сохраняются, но войти нельзя — обратимая операция, никаких потерь.
Доступ внутри команды (RBAC)
Пять ролей: OWNER, ADMIN, FINANCE, TEAM_LEAD, BUYER. Каждая операция (создать карту, выплатить зарплату, поменять план) проверяется на сервере — клиентскому фильтру не доверяем. TEAM_LEAD видит только свою команду; BUYER — только свои связки.
Изоляция между организациями
Каждый запрос к данным идёт с фильтром по organizationId, который выводится из сессии — не из URL и не из тела запроса. Подменить orgId в запросе нельзя: сервер использует только тот, что привязан к текущему пользователю.
Журнал админских действий
Append-only лог любогоадминского действия: смена тарифа, выдача триала, wipe данных, удаление организации, блокировка пользователя. Записи нельзя редактировать. Если возникает вопрос «кто и когда что-то сделал в моей организации» — у нас есть ответ.
Privacy в нашей админке
Мы как админы и support видим метаданные организаций (количество транзакций, активных юзеров, активацию по 6 точкам, статус интеграции с Brocard) — но не суммы. Конкретные транзакции, балансы кошельков и API-ключи нам недоступны через интерфейс. Это сознательная граница, а не недосмотр.
Сетевой периметр
TLS через Let's Encrypt с автообновлением. Caddy reverse-proxy спереди, приложение и Postgres в одной internal-сети Docker — Postgres не выставлен на публичный интерфейс. SSH только по ключу (без паролей), fail2ban против перебора.
Право на забвение
Полный экспорт всех данных организации в ZIP-архив CSV — одной кнопкой в /settings/export, без модерации и подтверждений. Удаление организации — owner-кнопка в /settings/profile с подтверждением через slug. После удаления стираются связанные пользователи без других организаций и временные демо-аккаунты.
Soft-block авто-синков на правки оператора
Если оператор вручную правит транзакцию, пришедшую через Brocard sync, она помечается как «отредактирована локально». Следующий синк уже не перетирает её — человеческое значение побеждает данные провайдера до явного сброса флага.
На случай если что-то покажется недостаточным
Я отвечаю в TG в течение часа — на любые вопросы по безопасности, на просьбу подробнее раскрыть какую-то секцию или показать конкретный код. Контакты на странице «О проекте».