Шаг выкладки в прогоне курса агент закончил словом «Выполнено». Через пять минут я открыл базу на сервере и нашёл две вещи, о которых в отчёте не было ни строчки. Пользователь admin записан владельцем школы, только школы у него нет. А у «Кодиума», нашего первого и пока единственного настоящего клиента, пустые сроки пробного и оплаченного периода. По правилам, которые агент сам написал в прошлом уроке, это значит «не оплачено»: кабинет действующего клиента закрылся сразу после выкладки. Перед выкладкой все тесты были зелёные.
Чему научишься в этом уроке:
• готовить выкладку так, чтобы её можно было откатить одной командой;
• понимать, почему старая база на сервере ведёт себя иначе, чем свежая на ноутбуке;
• проверять сервер своими запросами к базе, а не по отчёту агента;
• замечать, когда агент повторил прошлый ответ и ничего не сделал.
Перед стартом
- Локально всё готово: школы, оплата, закрытие кабинета при неоплате (уроки 7.3 и 7.4). Запусти
pytest -qи запиши последнюю строку. Это число тестов ты будешь сверять после каждого шага агента. - Проверь, что в папке проекта есть git и коммит «перед выкладкой П6» (как его завести — урок 7.3), а
.envиcrm.dbперечислены в.gitignore. - Ключи тестового магазина ЮKassa ты кладёшь в
.envна сервере сам. Агент их не видит и в чат ты их не вставляешь. Тестовая карта для оплаты — на странице тестирования в документации ЮKassa.
Почему сервер не равен ноутбуку
Представь ремонт по чертежу: в новостройке всё сходится, а в старой квартире проводка тридцатилетней давности, и розетку туда, где она нарисована, не поставишь. Локальные тесты агент гоняет на новостройке: каждый раз создаёт свежую базу. На сервере живёт старая база «Кодиума» со всеми заявками. Переделать её структуру на месте, не потеряв данных, это и есть миграция.
В старой базе сидело правило, записанное ещё в П4: роль пользователя может быть только manager или owner. Такое правило внутри таблицы называется ограничением (по-английски CHECK). Новой роли admin в нём нет. CHECK не молчит — выдаёт ошибку, и база отказалась записать admin. А код создания admin записал роль owner и промолчал. Тесты этого не увидели: на свежей базе ограничение уже новое.
Задание 1. Выкладка
Задание из прогона. Вместо <путь к папке проекта>, <адрес сервера> и <твой поддомен> подставь свои. Имена переменных ЮKassa оставь как есть, значения уже лежат в .env на сервере.
Работай ТОЛЬКО в текущей папке проекта (<путь к папке проекта>) и на сервере <адрес сервера> (ключ ~/.ssh/<твой ключ>, пользователь root, приложение /opt/crm-kodium, служба crm-kodium). Отвечай по-русски.
Выложи версию «несколько школ + оплата» на сервер:
1. Перед выкладкой — резервная копия базы на сервере (backup.sh) и проверь, что копия не пустая.
2. Выкладка как раньше: без .env, crm.db, тестов, backups/, .venv. .env на сервере НЕ трогать — ключи ЮKassa (YOOKASSA_SHOP_ID, YOOKASSA_SECRET_KEY) я туда уже положил сам.
3. Зависимости, перезапуск службы, служба active; миграция при старте прошла: все старые заявки «Кодиума» — в школе №1, их число до и после совпадает (покажи оба числа).
4. Проверки снаружи (curl с этой машины): https://<твой поддомен>/login — 200; /register — 200; POST /pay/notify с поддельным телом {"object":{"id":"fake"}} — без продления и без 500.
5. Создай первого admin командой manage.py на сервере; пароль — в файл /opt/crm-kodium/admin-parol.txt с правами 600, в ответ не печатать.
Секреты не печатать (для .env — только cut -d= -f1).
Что нашлось на сервере
Проверял я так же, как в практике 6.6: зашёл на сервер и посмотрел базу в режиме только для чтения. Две дыры из начала урока, и обе из-за разницы между ноутбуком и сервером. Задание на исправление:
Я проверил сервер сам. Две ошибки выкладки, о которых в отчёте ни слова:
1. «admin» создан с ролью owner и без школы: в старой таблице users на сервере стоит CHECK(role IN ('manager','owner')) — роль admin туда не записать. Локально тесты шли на свежей базе, где ограничение уже новое. Такой «owner без школы» — дыра.
2. У школы №1 «Кодиум» trial_until и paid_until пустые — значит по твоей же проверке кабинет действующего клиента закрылся сразу после выкладки.
Почини:
- миграция, которая пересоздаёт users с ограничением, допускающим admin (данные и пароли сохранить, идемпотентно, копия базы перед ней); тест «старая база с CHECK без admin → после миграции admin создаётся»;
- при миграции существующая школа без сроков получает 14 дней пробного периода от даты миграции (действующего клиента не закрываем); тест на это;
- выложи, на сервере: удали неверного пользователя admin (id 4), создай admin заново командой manage.py (пароль в /opt/crm-kodium/admin-parol.txt, 600, не печатать), покажи роли пользователей и сроки школы №1, число заявок до/после.
Работай в этой папке и на сервере <адрес сервера>. .env не трогать, секреты не печатать. Отвечай по-русски. В ответе — последняя строка pytest -q и вывод проверок с сервера.
Сроки «Кодиума» агент поправил. А в конце написал «исправлены обе ошибки», хотя в его же выводе стояло 4|admin|owner|: роль всё ещё owner. И из всех тестов запустил два. Правило: читай вывод команд, а не итоговую фразу.
Отговорка, опасная правка и 100 копий
Следующим заходом агент роль admin починил: под admin заявки отвечали 403, список школ 200. Полный pytest запускать отказался: «требует более 10 минут». Раньше весь набор проходил за 45 секунд. Я запустил тесты сам, и тест двух одновременных уведомлений просто зависал.
Агент тем временем предложил правку: если база занята, отвечать ЮKassa «уже обработано». Но получив 200, ЮKassa больше не пришлёт уведомление: деньги взяты, доступ не продлён. При занятой базе правильный ответ 500 (ошибка сервера), тогда ЮKassa повторит уведомление позже.
Настоящая причина нашлась в коде: миграция с копией базы запускалась при каждом старте приложения. В тесте два приложения стартовали одновременно и мешали друг другу. А на сервере каждый перезапуск службы добавлял ещё одну копию базы в папку backups. Их набралось 100.
Задание на исправление: при занятой базе отвечать 500; миграцию запускать, только если она нужна; копию делать только перед настоящей миграцией; тест «повторный старт не делает копию». Тест гонки не менять.
Метка версии (PRAGMA user_version) работает как отметка в техпаспорте квартиры «ремонт проведён»: увидел отметку, ничего не ломаешь второй раз. Локально стало 46 тестов, все зелёные.
Дальше было странное. Попросил выложить. Агент сделал 26 ходов и выдал дословно прошлый ответ, а на сервере осталась старая версия: метка 0 и те же 100 копий. Помогла новая сессия Claude Code с тем же заданием. Выложено, метка 1, в backups 3 свежие копии, перезапуск копий не прибавляет.
Длинная сессия устаёт: агент начинает повторять старые ответы. Если ответ подозрительно похож на прошлый, проверь сервер и начни новую сессию с коротким заданием: что готово, что отстаёт, что проверить.
Проверка сервера запросами
Это твоя часть работы, агенту её не отдавай. Зайди на сервер и посмотри сам. Флаг -readonly значит, что база только читается и ничего не поменяется.
ssh root@<адрес сервера>
systemctl is-active crm-kodium
sqlite3 -readonly /opt/crm-kodium/crm.db "PRAGMA user_version;"
sqlite3 -readonly /opt/crm-kodium/crm.db ".tables"
sqlite3 -readonly /opt/crm-kodium/crm.db ".schema users"
ls /opt/crm-kodium/backups | wc -l
cut -d= -f1 /opt/crm-kodium/.env
По схеме таблиц попроси агента написать три запроса и выполни их сам той же командой с -readonly: роли и школа каждого пользователя; сроки пробного и оплаченного периода у каждой школы; число заявок первой школы. Что должно быть:
- служба active, метка версии 1;
- у admin роль admin и пустая школа, у остальных своя школа;
- у «Кодиума» срок пробного периода в будущем, кабинет открывается;
- заявок «Кодиума» столько же, сколько до выкладки (в прогоне 83);
- в списке переменных .env на месте ключи ЮKassa и всё, что было раньше.
Сломай и почини
- Посчитай копии в backups, перезапусти службу (
systemctl restart crm-kodium) и посчитай снова. Число не выросло: миграция на старте больше не запускается зря. - Отправь поддельное уведомление об оплате с телом
{"object":{"id":"fake"}}наhttps://<твой поддомен>/pay/notify. Команду curl попроси написать агента. Ответ не 500, сроки школ в базе не изменились.
Комплект не отменяет проверку
Комплект навыков и проверок разберём в уроке Фундамента про обвязку (готовится); здесь — что он поймал и чего нет. Перед правкой кода агент сам вызвал навык серверной разработки. Но обе дыры урока, отговорка и повтор ответа случились уже с комплектом. Закончить проверкой сервера должен ты.
Если не получилось
- Агент пишет «Выполнено», а роли или сроки на сервере не те → покажи ему строку из базы и попроси миграцию с тестом на старой базе, а не на свежей.
- Кабинет «Кодиума» после выкладки просит оплатить → у школы пустые сроки; попроси миграцию, которая даёт существующей школе 14 дней пробного периода от даты миграции.
- Тесты зависают или агент говорит «слишком долго» → запусти
pytest -vсам и посмотри, на каком тесте встало. - После каждого перезапуска в backups новая копия → миграция запускается на каждом старте; нужна метка версии и копия только перед настоящей миграцией.
- Агент повторил прошлый ответ, на сервере старая версия → новая сессия с коротким заданием.
- Нужно вернуть код как было →
git log, потом откат к коммиту «перед выкладкой П6».
Контрольный вопрос. Локально все тесты зелёные, а на сервере admin записался с ролью owner. Почему тесты этого не поймали?
Подсказка: Чем база на сервере отличается от той, что создают тесты?
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Контрольный вопрос. Агент предлагает: если база занята, отвечать ЮKassa «уже обработано» с кодом 200. Что произойдёт с настоящим платежом в такую секунду?
Подсказка: Что ЮKassa делает, когда получила ответ 200?
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Контрольный вопрос. Ты перезапустил службу. До перезапуска в backups было 3 файла, после стало 4. О чём это говорит?
Подсказка: Вспомни, откуда на сервере прогона взялись 100 копий.
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Задание. МИССИЯ «Выкладка, которой веришь». 1. Перед выкладкой: коммит в git проекта, последняя строка pytest -q. 2. Дай агенту задание 1 из урока со своими путём, адресом и поддоменом. Ключи ЮKassa в .env сервера кладёшь сам. 3. Проверь сервер своими командами: служба active, метка версии, роли пользователей со школами, сроки школ, число заявок первой школы до и после, список переменных .env. 4. Нашёл расхождение — дай задание на исправление по образцу урока и проверь снова. 5. Живая оплата: зарегистрируй на поддомене тестовую школу, на «Тарифе» нажми «Оплатить» и оплати тестовой картой (в прогоне 5555 5555 5555 4477, срок и код — на странице тестирования ЮKassa). Срок на «Тарифе» продлился; проверь запросом к базе сервера с -readonly, что в payments одна оплаченная запись (запрос попроси написать агента по .schema payments). 6. Сломай и почини: число копий в backups до и после перезапуска; поддельное уведомление на /pay/notify без продления и без 500. Принято, если: приложены последняя строка pytest -q до и после, вывод твоих запросов к базе сервера (роли, сроки, число заявок до и после), вывод cut -d= -f1 .env, число файлов в backups до и после перезапуска, ответ сервера на поддельное уведомление, вывод запроса к payments после живой оплаты и строка git log с коммитом перед выкладкой. Паролей, ключей и телефонов в приложенном нет.
Подсказка: Начни с числа заявок до выкладки: без него «после» не с чем сравнить.
✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.
На курсе задания проверяются автоматически. Решить первое задание бесплатно → · Подобрать курс
Что дальше
Сервис для нескольких школ работает на сервере, и ты проверил это сам. Следующий урок про первых пользователей и обратную связь.
Итог:
• перед выкладкой есть коммит в git и записанное число тестов;
• старая база на сервере проверяется миграцией с тестом на старой схеме;
• роли, сроки и число заявок ты сверил своими запросами с -readonly;
• перезапуск службы не плодит копии, поддельное уведомление ничего не продлевает.
