← На главную

Тестовое задание

Polza Agency — Технический специалист / вайбкодер

1

Выгрузка → PostgreSQL

Из data_pack.zip (page_001.json … page_020.json, ~1000 компаний) все записи загружены в PostgreSQL. Реализована дедупликация, проставлены индексы.

  • Скрипт загрузки: `scripts/load_data.ts` — читает JSON, дедуплицирует по названию, загружает в БД
  • Схема: таблица `companies` с полями: id, name, category, city, address, rating, reviews_count, site, phone, created_at
  • Индексы: на name (для поиска), city (для фильтрации), category (для группировок)
  • Docker Compose: `docker-compose.yml` — PostgreSQL + приложение одной командой
  • SQL-запросы в блоке ниже
2

Страница /companies

Next.js App Router страница с серверным рендерингом. Таблица компаний из PostgreSQL с поиском по названию и фильтром по городу.

  • Server Component: `src/app/companies/page.tsx` — фетчит данные и города напрямую из БД
  • Client Component: `CompaniesClient.tsx` — интерактивная таблица с поиском и фильтрацией
  • Поиск через URL-параметры (?q=&city=) — работают навигация, рефреши и расшаривание результатов
  • Адаптивный дизайн: колонки скрываются на мобильных устройствах
3

Данные с сюрпризом (review.csv)

Анализ review.csv на аномалии. Все несоответствия задокументированы в ANOMALIES.md — 31 инцидент.

  • Найдены: невалидные рейтинги, битая кодировка (mojibake), дубликаты ID, сдвиг колонок, опечатки
  • Полный отчёт с таблицами и цветовой кодировкой по severity
4

Вайбкод / LLM-стек

Процесс разработки, инструменты, методология и архитектурные решения.

  • IDE: Claude Code + Cursor, агентские сценарии на живом репозитории
  • Модели: Claude Sonnet 4.5 / DeepSeek V4 Flash — под задачу
  • Подход: AI генерирует код, я проверяю каждый шаг, тестирую и коммичу
  • Все изменения в git с осмысленными сообщениями, каждая фича в своей ветке
5

SEO-оптимизация

Полный набор SEO-базовых мета-тегов, структурированных данных и файлов для индексации.

  • Open Graph / Twitter Cards на всех страницах с og:image 1200×630
  • JSON-LD структурированные данные (Organization + BreadcrumbList)
  • robots.txt + sitemap.xml + уникальные canonical URL
  • Уникальные title/description для каждой страницы (главная, /companies, /privacy, /docs, /anomalies)
  • favicon.svg + lang="ru"

Архитектурные решения

Почему Next.js + TypeScript, а не Python?

В ТЗ не было жёсткого требования по языку для ETL-скрипта, но вся платформа Polza Agency построена на Next.js + TypeScript + PostgreSQL. Выбор TypeScript для скрипта загрузки данных и всего приложения — это осознанное архитектурное решение:

  • Единый стек — скрипты загрузки, сайт и API пишутся на одном языке. Не нужно переключать контекст между Python и TypeScript.
  • Типизация — TypeScript даёт статическую проверку типов на всём протяжении: от парсинга JSON до UI-компонентов.
  • Server Components — данные фетчатся напрямую в серверном компоненте, без отдельного API-слоя. Меньше кода, быстрее работа.
  • Docker Compose — и БД, и приложение поднимаются одной командой. Не нужно ставить Python, Node.js или настраивать окружение вручную.
  • Единый CI/CD — один набор зависимостей для всего проекта: npm install, npm run build, npm start.

Прочие важные моменты

  • Безопасность — .env в .gitignore, секреты не попадают в репозиторий. Промпт-инъекции и SQL-инъекции проверены (не найдены).
  • Воспроизводимость — docker-compose.yml поднимает PostgreSQL, скрипт load_data.ts загружает данные. README с командой запуска.
  • Дедупликация — компании сопоставляются по названию, дубликаты исключаются на этапе загрузки.
  • ETL-обработка аномалий — автоматическое выявление и исправление битой кодировки, нормализация городов, приведение типов.

SQL-запросы

1. Топ-5 категорий по числу компаний

SELECT category, COUNT(*) AS company_count
FROM companies
WHERE category IS NOT NULL
GROUP BY category
ORDER BY company_count DESC
LIMIT 5;

2. Средний рейтинг по городам (компании с 10+ отзывами)

SELECT city,
       ROUND(AVG(rating)::numeric, 2) AS avg_rating,
       COUNT(*)                       AS company_count
FROM companies
WHERE rating IS NOT NULL
  AND reviews_count >= 10
GROUP BY city
ORDER BY avg_rating DESC;

3. Доля компаний с сайтом по категориям

SELECT category,
       COUNT(*)                                                              AS total,
       COUNT(*) FILTER (WHERE site IS NOT NULL)                              AS with_site,
       ROUND(100.0 * COUNT(*) FILTER (WHERE site IS NOT NULL) / COUNT(*), 1) AS pct_with_site
FROM companies
WHERE category IS NOT NULL
GROUP BY category
ORDER BY pct_with_site DESC;

Вопрос-ответ

IDE и LLM модели — выбор и эволюция

Q: Твой выбор IDE и LLM моделей сейчас и как он менялся последние полгода.

A: Сейчас основная IDE это VS Code. Для работы с кодом использую двух агентов: Claude Code (Sonnet 5) и OpenCode с бесплатными моделями DeepSeek V4 Flash и OpenCode Zen. Полгода назад в основном работал с бесплатными китайскими моделями DeepSeek, MiniMax, MiMo. Причина была не только в экономии. Бесплатные модели чаще требуют самостоятельно разбираться в архитектуре проекта, проверять предлагаемые решения и принимать инженерные решения самому. Для меня это было полезно, потому что позволяло лучше понимать код и технологии, а не просто принимать готовые ответы модели. Задачи стали серьезнее и я пришел к подписке Claude, но все ещё совмещаю.

Подписки на LLM сервисы

Q: Сколько и каких подписок в месяц тебе хватает для полноценной работы.

A: Подписка Claude pro покрывает все задачи + иногда использую бесплатные модели в OpenCode на несущественных задачах (рутина, документация), где не стоит вопрос безопасности или критичного искажения данных.

Методология сравнения моделей

Q: Как сравниваешь две новые модели или инструмента — по ощущениям или на одинаковом наборе задач?

A: На одинаковом наборе задач, например, багфикс в существующем коде, миграция, рефакторинг. В первую очередь интересует не столько скорость сколько качество. Так же проверяю модели на больших задачах, но тут мы уже переходим в область ощущений часто. На больших задачах мы видим как модель справляется разово. Насколько четко нужно прописывать алгоритм словами либо модель способна сама безошибочно простроить всю цепочку от пункта А к пункту Б, насколько точно модель следует требованиям, понимает ли она существующую архитектуру проекта, не ломает ли код.

Тестирование новых функций

Q: Какие тесты ты потребуешь для новой функции?

A: Unit-тесты, валидность данных, отработка исключений и сообщения об ошибках, ручная проверка чтобы убедиться, что функция действительно работает так, как ожидается. + Безопасность ручного ввода с фронта (инъекции). Если это вход, то авторизация, права доступа, роли.

Разрешения для coding-агента

Q: Какие разрешения ты дашь coding-агенту, имеющему доступ к терминалу и базе?

A: Агент должен быть максимально ограничен в доступе к командам терминала и базы данных. В идеале агент должен работать под отдельной учетной записью с ограниченным набором прав. Если речь идет о базе данных, то по умолчанию ему достаточно доступа на чтение. Любые операции, которые могут изменить или удалить данные — с подтверждением от человека. В начале разработки допускаю большую свободу действий для моделей. Работающий проект — однозначно ограничения прав агента.

Автоматические тесты и CI/CD

Q: Пишешь ли ты автоматические тесты и включаешь ли их в CI/CD? Какие проверки должны обязательно пройти перед слиянием и деплоем.

A: Сборка, линтинги, проверка зависимостей, аудиты безопасности.