
OK3D
LiveПолноценная платформа для выбора 3D-моделей и заказа изделий с изготовлением и доставкой.
Full-Stack · Автоматизация · AI-системы · Инфраструктура
Сайты. Автоматизация. Боты. AI. Инфраструктура.
Если процесс можно запрограммировать, соединить с другими системами, автоматизировать или усилить AI — я спроектирую и построю систему вокруг него: от интерфейса и бэкенда до сервера, на котором она работает.
Что можно автоматизироватьОдна система, каждый слой — и она работает сама.
Проекты
Сайты, сервисы и системы, которые я проектирую, разрабатываю и запускаю.

Полноценная платформа для выбора 3D-моделей и заказа изделий с изготовлением и доставкой.
Что я строю
Не одна страница и не один скрипт — рабочий продукт: интерфейс, бэкенд, данные, автоматизация и сервер, на котором это живёт.
Фронтенд и бэкенд как единое целое — от лендинга до маркетплейса с админкой.
Всё, что сотрудник делает руками по расписанию, может делать скрипт — быстрее и без ошибок.
Боты, которые принимают заказы, сообщают о событиях и дают команде админку прямо в мессенджере.
Собрать, очистить, сопоставить и держать в синхроне — тысячи страниц, сотни тысяч строк.
Локальные и облачные модели внутри продуктов: ассистенты, агенты, генерация, поиск по своим данным.
Сервер, на котором живёт продукт: Linux, Docker, reverse proxy, бэкапы и мониторинг.
Процесс
Один и тот же путь и для лендинга, и для системы с AI внутри. Разница лишь в глубине каждого шага.
Часть шагов выполняют AI-агенты под моим контролем. Результат проверяется в реальном браузере — скриншотом, а не на веру.
Автоматизация
Почти всё, что повторяется. Вот как рутина, съедающая день сотрудника, превращается в систему, которая работает сама.
~2–4 часа в день · ошибки · задержки
по расписанию · 0 ручных шагов · всё в логах
Есть повторяющаяся задача? Давайте автоматизируем.
Описать задачуКак это устроено
Пять типовых контуров, из которых состоит большинство моих проектов. Каждый можно заказать отдельно или как часть целой системы.
«Парсер» — это не скрипт на одну страницу. Это конвейер: много источников, нормализация, валидация, база — и потребители, которым нужны чистые данные.
Когда у сервиса нет API, с ним можно работать через браузер — как человек, но по расписанию и с проверкой результата.
Только там, где это технически и юридически уместно. Обход защитных механизмов — не про это.
Не «просто бот», а вход в систему: заказы, уведомления, админка и отчёты — там, где команда уже сидит.
Соединяю системы, которые не были созданы для работы вместе: CRM, магазин, оплата, доставка, аналитика, Telegram, внутренние базы.
Продукт живёт на сервере, который я настраиваю и сопровождаю сам: от reverse proxy до бэкапов и GPU-нагрузок.
Лаборатория
Небольшие интерактивные демо. Каждое — упрощённая версия того, что я строю по-настоящему. Всё симулируется в вашем браузере и не подключено к живым системам.
URL → HTML → структурированные данные → JSON
// JSONБезопасное демо: парсится подготовленная страница, а не произвольный сайт.
Один клик — отрабатывает вся цепочка.
$ Чистый REST API — так я их строю.
// responseКак выглядит AI-слой внутри продукта: вопрос → поиск по своим данным → ответ.
Макет интерфейса — ответы заскриптованы, данные не покидают страницу.
Сборка → браузер → скриншот → анализ → исправление. Так результат проверяется, а не принимается на веру.
$ Живая аналитика — та, что владелец открывает каждое утро.
Типичный деплой — симуляция, безопасно.
Система
Наведите или коснитесь узла, чтобы увидеть, что я могу сделать на этом уровне.
Стек
Сгруппировано по слоям. Нажмите на группу, чтобы развернуть.
Фронтенд
Бэкенд
Данные
Автоматизация
AI
Инфраструктура
Инструменты
AI Lab
Локальные модели на своём GPU-сервере — без оплаты за токены и без утечки данных наружу. Такую же схему можно развернуть для вашего продукта.
Модели
Не «подключил чат-бота», а отдельный слой: модель, поиск по вашим данным и инструменты, которые действуют в вашей системе.
Генерация и обработка изображений и видео на собственном GPU — воркфлоу ComfyUI, которые можно встроить в конвейер.
Статусы честные: «рабочий» — использую в задачах, «эксперимент» — работает, но ещё не для продакшена, «исследование» — изучаю.
Не логотипы ради логотипов — что именно каждый инструмент делает в моих системах.
Собственная AI-платформа разработки
Я собираю локальную AI-ассистированную среду разработки: модели, база знаний, агенты с ролями, браузерная автоматизация и визуальная проверка — на собственной инфраструктуре.
Вместо «сгенерировал код и поверил, что интерфейс правильный» — среда открывает результат в браузере, смотрит на него и итерирует.
Отдельный слой знаний об интерфейсах, чтобы агент компоновал страницы не «как получится», а по проверенным паттернам.
База — кураторские референсы, документация, открытые ресурсы и метаданные паттернов. Не копии коммерческих UI-библиотек.
Код
Реалистичные фрагменты — интеграция API, автоматизация, обработка данных. Без секретов и без hello-world.
<?php
declare(strict_types=1);
// Webhook нового заказа: подпись → валидация → БД → уведомление.
// Секреты берутся из окружения, в коде их нет.
$secret = getenv('ORDER_WEBHOOK_SECRET') ?: '';
$payload = file_get_contents('php://input');
$given = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
if (!hash_equals(hash_hmac('sha256', $payload, $secret), $given)) {
http_response_code(401);
exit;
}
$order = json_decode($payload, true, 8, JSON_THROW_ON_ERROR);
$rules = [
'id' => fn($v) => is_int($v) && $v > 0,
'phone' => fn($v) => preg_match('/^\+?\d{10,15}$/', (string) $v),
'items' => fn($v) => is_array($v) && count($v) > 0,
'total' => fn($v) => is_numeric($v) && $v >= 0,
];
foreach ($rules as $field => $ok) {
if (!isset($order[$field]) || !$ok($order[$field])) {
http_response_code(422);
echo json_encode(['error' => "invalid {$field}"]);
exit;
}
}
$db = Db::connection();
$db->beginTransaction();
try {
$db->prepare(
'INSERT INTO orders (id, phone, total, status, created_at)
VALUES (:id, :phone, :total, "new", NOW())
ON DUPLICATE KEY UPDATE total = VALUES(total)'
)->execute([
'id' => $order['id'], 'phone' => $order['phone'], 'total' => $order['total'],
]);
$stmt = $db->prepare('INSERT INTO order_items (order_id, sku, qty) VALUES (?, ?, ?)');
foreach ($order['items'] as $item) {
$stmt->execute([$order['id'], $item['sku'], (int) $item['qty']]);
}
$db->commit();
} catch (Throwable $e) {
$db->rollBack();
error_log('order webhook: ' . $e->getMessage());
http_response_code(500);
exit;
}
// Уведомление — асинхронно, чтобы не держать вебхук открытым.
Queue::push('telegram.notify', [
'chat' => 'orders',
'text' => sprintf("🛒 Заказ #%d — %s ₴\n%d позиций",
$order['id'], number_format($order['total'], 0, '.', ' '), count($order['items'])),
]);
http_response_code(202);
echo json_encode(['ok' => true]);"""Мониторинг цен: обход по расписанию, история, AI-оценка изменений."""
from __future__ import annotations
import asyncio
import logging
from dataclasses import dataclass
from decimal import Decimal
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential
from monitor.db import PriceRepo
from monitor.llm import classify_change
from monitor.notify import telegram
log = logging.getLogger(__name__)
@dataclass(frozen=True)
class Target:
sku: str
url: str
selector: str
@retry(stop=stop_after_attempt(4), wait=wait_exponential(min=2, max=30))
async def fetch_price(client: httpx.AsyncClient, target: Target) -> Decimal:
resp = await client.get(target.url, timeout=20)
resp.raise_for_status()
node = parse_html(resp.text).select_one(target.selector)
if node is None:
raise LookupError(f"selector miss: {target.sku}")
return normalize_price(node.get_text())
async def check(target: Target, repo: PriceRepo, client: httpx.AsyncClient) -> None:
price = await fetch_price(client, target)
previous = await repo.last(target.sku)
await repo.append(target.sku, price)
if previous is None or previous == price:
return
delta = (price - previous) / previous * 100
verdict = await classify_change(target.sku, previous, price, delta)
if verdict.significant:
await telegram.send(
"pricing",
f"📉 {target.sku}: {previous} → {price} ({delta:+.1f}%)\n{verdict.reason}",
)
async def main() -> None:
repo = PriceRepo.from_env()
targets = await repo.targets()
sem = asyncio.Semaphore(6) # не долбим один сайт параллельно
async with httpx.AsyncClient(headers={"User-Agent": "price-monitor/2.1"}) as client:
async def guarded(t: Target) -> None:
async with sem:
try:
await check(t, repo, client)
except Exception: # одна ошибка не должна ронять весь прогон
log.exception("target failed: %s", t.sku)
await asyncio.gather(*(guarded(t) for t in targets))
if __name__ == "__main__":
asyncio.run(main())// Тонкий API-клиент: дедупликация одинаковых запросов,
// отмена устаревших, оптимистичное обновление кэша.
const inflight = new Map();
export function createClient({ baseUrl, onError }) {
const cache = new Map();
async function request(method, path, { body, signal } = {}) {
const key = method === 'GET' ? `GET ${path}` : null;
if (key && inflight.has(key)) return inflight.get(key);
const run = fetch(baseUrl + path, {
method,
headers: { 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
signal,
})
.then(async (res) => {
if (!res.ok) throw new ApiError(res.status, await res.text());
return res.status === 204 ? null : res.json();
})
.catch((err) => {
if (err.name !== 'AbortError') onError?.(err);
throw err;
})
.finally(() => key && inflight.delete(key));
if (key) inflight.set(key, run);
return run;
}
return {
get: (path, opts) => request('GET', path, opts),
// Оптимистично: UI видит изменение сразу, откат — только при ошибке.
async patch(path, body, { optimistic } = {}) {
const prev = cache.get(path);
if (optimistic) cache.set(path, { ...prev, ...body });
try {
const data = await request('PATCH', path, { body });
cache.set(path, data);
return data;
} catch (err) {
cache.set(path, prev);
throw err;
}
},
// Поиск с отменой предыдущего запроса при новом вводе.
search: (() => {
let controller;
return (q) => {
controller?.abort();
controller = new AbortController();
return request('GET', `/search?q=${encodeURIComponent(q)}`, {
signal: controller.signal,
});
};
})(),
};
}
export class ApiError extends Error {
constructor(status, body) {
super(`API ${status}`);
this.status = status;
this.body = body;
}
}Опыт
10+ лет
Каждый слой добавлялся потому, что предыдущего не хватало, чтобы выпустить целый продукт.
Сайты, вёрстка, CMS, первые бэкенды на PHP.
API, базы данных, оплаты, авторизация — логика за интерфейсом.
Парсеры, боты, планировщики — убираю ручную работу из процессов.
Собственные серверы: Linux, Docker, Nginx, бэкапы, мониторинг.
Локальные модели, агенты, RAG — AI как слой внутри продуктов.
Обо мне
Я программирую больше 10 лет. Работаю со всем стеком продукта — интерфейс, бэкенд, базы данных, автоматизация, серверы и AI.
Мне нравятся задачи, где софт может убрать повторяющуюся работу или превратить сложный процесс в простую систему.
Не автоматизируйте, потому что это модно. Автоматизируйте, потому что люди не должны тратить время на то, что софт делает надёжнее.
Задачи, которые я решаю
Контакт
Расскажите, что вы хотите автоматизировать, построить или улучшить. Не обязательно знать, какой стек нужен — просто опишите задачу.