Junior IT-специалист · Portfolio 2026
Савинов Никита Сергеевич
Разрабатываю сайты, Telegram-ботов, Telegram Mini Apps, приложения с базами данных и административными панелями.
Выпускник Нижегородского Радиотехнического Колледжа по специальности 09.02.07 «Информационные системы и программирование». Дипломный проект защищён на «отлично». Ищу работу или стажировку в IT-сфере.
Обо мне
Не просто список навыков, а проекты, доведённые до результата
Кто я
Я выпускник НРТК по специальности «Информационные системы и программирование». В учебных и личных проектах работал с веб-сайтами, ботами, Mini Apps, десктопными приложениями, базами данных и 1С.
Что ищу
Ищу работу или стажировку в IT-сфере: junior-разработчик, веб-разработчик, помощник программиста, разработчик ботов, стажёр или специалист по поддержке информационных систем.
Мой подход
Быстро обучаюсь, внимательно отношусь к деталям и стараюсь показывать результат не словами, а рабочими функциями: интерфейс, БД, роли, заказы, тесты, логика и автоматизация.
Стек и практика
Технологии, с которыми я работал в проектах
Проекты
Кейсы с визуальными частями, функциями и кодом
Я встроил в сайт реальные элементы из проектов: изображения/ассеты, структуру функций, архитектурные блоки и короткие фрагменты кода.
Интернет-магазин «Стальной Шов»
Полноценный интернет-магазин тактического снаряжения: каталог, корзина, оформление заказов, личный кабинет, сравнение, избранное, отзывы, конструктор экипировки и админ-панель.
BattleTapper
RPG-кликер с боями, аренами, врагами, инвентарём, рынком, магазином, лутом, рейтингом и серверным расчётом боя.
Tap Empire
Tap-to-earn игра с персонажем, предметами, бизнесами, транспортом, ежедневными заданиями, гонками, рейтингом и игровой экономикой.
Бутурлино Такси
Локальный сервис заказа такси: клиент оформляет поездку, водитель выходит на линию и принимает заказ, администратор управляет тарифами, водителями и комиссиями.
ОсветМир
Интернет-магазин светильников с каталогом, корзиной, оформлением заказа, личным кабинетом и административной панелью.
Магазин комплектующих
Десктопное приложение с товарами, корзиной, заказами, админ-частью, рейтингом товаров и подключением к PostgreSQL.
1С и учебные ИС
Работа с предметными областями, ERD, диаграммами, структурой данных, учебными конфигурациями и логикой информационных систем.
Что внутри
Как проекты раскрываются на сайте
Интерфейс
Визуальные части проектов вынесены в карточки: арены и враги BattleTapper, персонаж Tap Empire, интернет-магазины и UI-макеты для ботов/JavaFX.
Архитектура
Показаны роли, сценарии, базы данных, ключевые модули и результат — чтобы было видно, что проекты не ограничиваются внешним видом.
Код
Ниже размещены короткие фрагменты логики из проектов: оформление заказа, тесты, бой, экономика, заказ такси и CRUD.
Главный кейс
«Стальной Шов» — дипломный проект на отлично


Проект собран как полноценная информационная система: клиентская часть, административная панель, база данных, роли, заказы, отзывы, избранное, сравнение товаров и конструктор экипировки.
- Разделение сценариев для гостя, покупателя, менеджера и администратора.
- Оформление заказа с фиксацией состава покупки и уменьшением остатков.
- Конструктор экипировки как уникальная функция проекта.
- Unit-тесты для ключевой бизнес-логики.
Code Lab
Короткие фрагменты кода из проектов
Фрагменты сокращены для портфолио, чтобы показать смысл реализации и не перегружать страницу.
Оформление заказа и остатки
// tacticalshop/checkout.php — оформление заказа и фиксация состава покупки
$pdo->beginTransaction();
$stmt = $pdo->prepare("INSERT INTO orders (...) VALUES (...)");
$stmt->execute($orderValues);
$orderId = $pdo->lastInsertId();
foreach ($items as $item) {
$updateStock = $pdo->prepare(
"UPDATE products SET stock_quantity = stock_quantity - ? WHERE id = ?"
);
$updateStock->execute([(int)$item['quantity'], (int)$item['product_id']]);
$stmt = $pdo->prepare("
INSERT INTO order_items
(order_id, product_id, product_name_snapshot, price_per_unit, quantity, total_price)
VALUES (?, ?, ?, ?, ?, ?)
");
$stmt->execute([$orderId, $item['product_id'], $item['name'], $item['price'], $item['quantity'], $item['price'] * $item['quantity']]);
}
$pdo->commit();Unit-тесты бизнес-логики
// tacticalshop/tests/tacticalshopFunctionsTest.php — проверка корзины и остатков
public function testCartTotalIsCalculatedCorrectly(): void
{
$items = [
['price' => 26000, 'quantity' => 1],
['price' => 750, 'quantity' => 2],
['price' => 2000, 'quantity' => 3],
];
$this->assertSame(33500.0, steel_seam_calculate_cart_total($items));
}
public function testRequestedQuantityCannotExceedStockQuantity(): void
{
$this->assertSame(3, steel_seam_limit_quantity_by_stock(5, 3));
$this->assertSame(1, steel_seam_limit_quantity_by_stock(0, 10));
}Серверный расчёт боя
// BattleTapper/backend/core/game.js — серверный удар и ответ врага
function hitBattle(db, player, quality = 'normal') {
let battle = player.activeBattle;
if (!battle || battle.status !== 'active') battle = createBattle(db, player, 'normal');
const stats = calcStats(db, player);
const enemy = battle.enemy;
const qualityMap = {
normal: { multiplier: 1, perfect: false },
good: { multiplier: 1.55, perfect: false },
perfect: { multiplier: 2.35, perfect: true }
};
const hit = qualityMap[quality] || qualityMap.normal;
const randomCrit = randomInt(1, 100) <= stats.critChance;
const multiplier = randomCrit && quality === 'normal' ? stats.critDamage / 100 : hit.multiplier;
enemy.hp = Math.max(0, enemy.hp - dealDamage(stats.attack, enemy.defense, multiplier));
if (enemy.hp <= 0) return finishVictory(db, player, battle);
battle.playerHp = Math.max(0, battle.playerHp - dealDamage(enemy.attack, stats.defense));
if (battle.playerHp <= 0) finishDefeat(db, player, battle);
return { battle, player };
}Сила тапа и пассивный доход
// Tap Empire/src/server.js — расчёт силы тапа и пассивного дохода
async function getEffectiveTapPower(userId, db = pool) {
const user = await findUserById(userId, db);
const activeVehicle = await getActiveVehicle(userId, db);
const vehicleBonus = activeVehicle
? Math.floor(activeVehicle.prestige / 35) + activeVehicle.upgrade_level
: 0;
const itemBonuses = await getEquippedItemBonuses(userId, db);
const baseTapPower = Number(user?.tap_power || 1) + vehicleBonus;
return Math.max(1, Math.floor(baseTapPower * (1 + itemBonuses.tapBonusPercent / 100)));
}
async function calculatePassiveIncomePerHour(userId, db = pool) {
const businesses = await getUserBusinesses(userId, db);
const baseIncome = businesses.reduce((sum, row) => sum + getBusinessIncome(row.base_income_per_hour, row.level), 0);
const itemBonuses = await getEquippedItemBonuses(userId, db);
return Math.floor(baseIncome * (1 + itemBonuses.incomeBonusPercent / 100));
}Заказ, водитель и комиссия
# buturlino_taxi_bot/database/db.py — заказ, водитель и комиссия
async def create_order(user_id, tariff_id, from_address, to_address, phone, comment):
tariff = await get_tariff(tariff_id)
price, is_night = price_for_tariff(tariff)
commission = round(price * config.commission_percent / 100)
return await execute("""
INSERT INTO orders
(client_id, tariff_id, from_address, to_address, phone, price, commission_amount, status)
VALUES (?, ?, ?, ?, ?, ?, ?, 'new')
""", (user_id, tariff_id, from_address, to_address, phone, price, commission))
async def accept_order(order_id, driver_telegram_id):
driver = await get_driver_by_telegram(driver_telegram_id)
await execute(
"UPDATE orders SET driver_id = ?, status = 'accepted' WHERE id = ? AND status = 'new'",
(driver['id'], order_id)
)CRUD и рейтинг в JavaFX-приложении
// CourseNIKITA/DatabaseManager.java — CRUD через PreparedStatement
public void addPart(String name, String description, double price, String category, int quantity) throws SQLException {
String query = "INSERT INTO computer_parts (name, description, price, category, quantity) VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement pstmt = connection.prepareStatement(query)) {
pstmt.setString(1, name);
pstmt.setString(2, description);
pstmt.setDouble(3, price);
pstmt.setString(4, category);
pstmt.setInt(5, quantity);
pstmt.executeUpdate();
}
}
public void ratePart(int partId, int rating) throws SQLException {
// Получение текущего рейтинга → пересчёт среднего значения → обновление записи
}Структура игрока в MySQL
-- Tap Empire/database/schema.sql — часть структуры игрока
CREATE TABLE IF NOT EXISTS users (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
telegram_id BIGINT UNSIGNED NOT NULL,
username VARCHAR(255) NULL,
balance BIGINT UNSIGNED NOT NULL DEFAULT 0,
tap_power INT UNSIGNED NOT NULL DEFAULT 1,
energy INT UNSIGNED NOT NULL DEFAULT 100,
passive_income_per_hour BIGINT UNSIGNED NOT NULL DEFAULT 0,
level INT UNSIGNED NOT NULL DEFAULT 1,
xp BIGINT UNSIGNED NOT NULL DEFAULT 0,
character_created TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME(3) NOT NULL,
updated_at DATETIME(3) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY uq_users_telegram_id (telegram_id)
);Образование и цель
Готов развиваться в реальной команде
Выпускник Нижегородского Радиотехнического Колледжа по специальности «Информационные системы и программирование».
Дипломный проект — интернет-магазин тактического снаряжения «Стальной Шов».
Интересуют junior-позиции, стажировки, веб-разработка, боты, информационные системы и поддержка IT-проектов.
Контакты
Готов обсудить работу, стажировку или тестовое задание
Ниже оставлены места под реальные контакты. Их лучше заполнить перед публикацией сайта.