NEVERMORE

От схемы базы до пикселя

Full-stack разработчик. Бэкенд на Python и FastAPI, фронтенд без лишних слоёв.

AniWorld
Голубика Давидика
RecipeVault
Breaking Bad
Ожившая история
DotaCounters
AniWorld
Голубика Давидика
RecipeVault
Breaking Bad
Ожившая история
DotaCounters

AniWorld
Продукт в проде2026

AniWorld

Библиотека аниме и манги с личными коллекциями, оценками и профилями.

Метаданные из Shikimori, видео из Kodik, манга сразу из трёх читалок за общим контрактом провайдера. Серверный рендеринг вместо SPA, потому что трафик такому сайту даёт поиск. 900 тестов, 43 миграции, прод на VPS в ЕС.

  • FastAPI
  • SQLAlchemy 2.0
  • MySQL
  • Alembic
  • Jinja2
  • nginx
Голубика Давидика
Коммерческий заказ2026

Голубика Давидика

Лендинг фермерского хозяйства: заявка уходит владельцу в Telegram за секунду.

Ноль фреймворков на фронте, минифицированные css и js, разметка под поиск: sitemap, robots, манифест. Форма заказа бьёт в Express, тот отдаёт заявку боту. Развёрнуто на Vercel.

  • Express
  • Vanilla JS
  • Telegram Bot API
  • Vercel
RecipeVault
Десктоп с базой2026

RecipeVault

Кулинарная книга на WPF: рецепты, подбор блюд по имеющимся продуктам и планы питания.

Десять таблиц в MySQL за Entity Framework, весь маппинг выписан руками: в базе змеиный регистр, в C# паскалевский, соглашения их сами не свяжут. Поиск идёт от обратного, не что приготовить, а что приготовить из этого. План питания складывает одноимённые ингредиенты всех рецептов и выдаёт список покупок.

  • C#
  • .NET Framework
  • WPF
  • Entity Framework 6
  • MySQL
Breaking Bad
Работа с формой2026

Breaking Bad

Лонгрид по сериалу: персонажи, сезоны, галерея, локации, две языковые версии.

Здесь меня интересовала только подача. Палитра собрана из кадров, заголовки на Bebas Neue, вёрстка держит длинный текст и не разваливается на середине. Переключатель EN и RU работает без перезагрузки.

Ожившая история
Командный проект2025

Ожившая история

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

Пять станций с мини-играми об истории колледжа, сквозной проводник с репликами, переходы и музыка. Станции не знают друг о друге: сценарий создаёт очередную сцену, ждёт её сигнал и освобождает, а проводник и музыка подняты в автозагрузку и живут поверх. Делали вчетвером, я писал три станции из пяти: про историю колледжа в цифрах, про его выпускников и финальную со словесными портретами руководителей.

  • Godot 4.5
  • GDScript
  • WebAssembly
DotaCounters
Десктоп2026

DotaCounters

Портативная утилита для Dota 2: против кого герой играет слабо, а против кого сильно.

Тянет свежую статистику матчапов с Dotabuff и рисует её в одном окне с иконками героев. Патч определяется сам при запуске. Один exe, без установки и без браузера.

  • Python
  • Tkinter
  • PyInstaller

Сначала контракт

Источники прячутся за интерфейсом

У манги в AniWorld три поставщика с разными API и разной пагинацией. Слой синхронизации не знает ни одного из них: он видит только нормализованный ответ. Добавить четвёртый значит написать один класс, а не править половину проекта.

services/manga/base.py
class MangaProvider(ABC):    name: str                      # ключ в конфиге: "mangadex"    can_read: bool = True          # можем ли забрать страницы глав    page_hosts: tuple[str, ...] = ()     @abstractmethod    async def fetch_catalog(self, client, *, limit, offset,                            language) -> list[MangaRaw]: ...

Рендер по задаче

SPA не всегда правильный ответ

AniWorld живёт поиском, поэтому страницы тайтлов отдаёт сервер на Jinja2, а динамика идёт отдельными запросами к тому же FastAPI. Индексируемо из коробки, быстрый первый экран, никакого сборщика.

api/pages.py
@router.get("/", response_class=HTMLResponse)async def home_page(request: Request,                    db: AsyncSession = Depends(get_db)):    featured = await pick_featured(db)    return templates.TemplateResponse(        "home.html", {"request": request, "featured": featured},    )

Версии под контролем

Зависимости закреплены по разбору CVE

В requirements рядом с версиями лежат причины: какой разбор формы читается до проверки входа, какая дыра закрыта в каком релизе. Обновление пакета это решение, а не автоматика.

requirements.txt
# Разбор формы идёт до проверки входа: так устроен FastAPI,# тело читается раньше зависимостей маршрута.python-multipart==0.0.32Pillow==12.3.0 argon2-cffi==25.1.0PyJWT==2.13.0

Залеский Кирилл

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

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

Сейчас учусь и хочу практики: одинаково рад заказу, стажировке и работе в команде.

NEVERMORE это старое имя Shadow Fiend из Dota 2, одного из моих любимых персонажей.

900
тестов в AniWorld
43
миграции базы
6
проектов доведено до конца
3
источника за одним контрактом

Чем работаю

Открыт к работе и к заказам. Отвечаю в течение дня.

Или оставьте заявку прямо здесь: она придёт мне в Telegram.