Coperniq
SaaS для управления проектами в solar-индустрии США. 200+ компаний-подрядчиков, 3000+ одновременных пользователей.
Метрики
Контекст
Coperniq — американский SaaS для управления проектами установки солнечных панелей: от продаж и пермитов до самого монтажа и пост-сервиса. Клиенты — 200+ компаний-подрядчиков среднего размера, у каждой по 5–50 активных проектов параллельно.
Когда я пришёл, платформа была одним Node.js-монолитом. Деплои по 90 минут, p50 MongoDB-запросов на критичных эндпоинтах — 1.2с, а ввод нового разработчика производил больше конфликтов, чем фич. Продукт работал, но каждый новый подрядчик делал следующий деплой ещё больнее.
Что я сделал
- Спроектировал и провёл миграцию монолит → микросервисы. Выделил 5 сервисов: auth, projects, scheduling, billing, notifications. У каждого своя БД, схема, цикл деплоя.
- Сделал real-time синхронизацию полевых работ на WebSocket. Бригады обновляют статус с мобильного, изменения долетают в офисные дашборды за <300мс. Тестировал на 3000 одновременных пользователей без бэклога в очереди.
- Взял на себя всю работу с производительностью MongoDB: профилирование, составные индексы, переписывание pipeline-ов агрегации. p50 на критичных эндпоинтах упал с 1.2с до 180мс — на 85%.
- Внедрил blue-green деплои в GitLab CI с health-чеками, автооткатом и canary-фазой: 5% трафика на новую версию 10 минут перед полной заменой.
- Интегрировал с QuickBooks, Stripe, Google Maps и DocuSign — всё, чем подрядчики реально пользуются в работе.
- Tech-лид команды из 4 fullstack-разработчиков: ревью, архитектура, 1:1, нанял 2 mid-уровня. Время до первого PR у новых сократилось с «3 недели» до «4 дня».
Технические решения
Границы сервисов выбирали по владению данными, не по «фичам» — billing владеет инвойсами и payment intents, scheduling владеет календарём бригад. Избежали антипаттерна «распределённый монолит», где сервисы шарят БД.
Межсервисное взаимодействие: синхронный REST для read-путей, где нужна консистентность; RabbitMQ-события для write-путей с eventual consistency. Saga для cross-service сценариев типа «проект завершён → инвойс → уведомление».
Frontend оставили монолитом на React + Redux Toolkit + React Query. RTK Query для серверного state, Redux — только для настоящего клиентского (модалки, драфты, optimistic UI). Убрали ~40% legacy Redux-boilerplate.
Observability: Prometheus + Grafana, структурированные JSON-логи в централизованный стек. У каждого микросервиса одинаковая тройка /metrics, /health, /ready — единообразие важнее, чем выбор идеального стека.
Из кода
// Before: full collection scan on every dashboard load (~1.2s p50)
db.projects.find({
organizationId: ObjectId("..."),
status: { $in: ["in_progress", "permitting"] },
scheduledStart: { $gte: ISODate("2026-01-01") },
}).sort({ scheduledStart: 1 }).limit(50);
// Compound index covering the filter + sort
db.projects.createIndex(
{ organizationId: 1, status: 1, scheduledStart: 1 },
{ name: "org_status_scheduled_v2", background: true }
);
// After: IXSCAN, ~180ms p50, no in-memory sort.
io.on("connection", (socket) => {
const { orgId, userId } = socket.data.session;
socket.join(`org:${orgId}`);
socket.join(`user:${userId}`);
});
projectsEvents.on("status_changed", async (evt) => {
// Push only to clients in the affected org, not all 3000.
io.to(`org:${evt.orgId}`).emit("project.updated", {
projectId: evt.projectId,
status: evt.status,
updatedBy: evt.actorId,
ts: evt.timestamp,
});
});
Результат
Команда выросла с 5 до 12 разработчиков без пропорционального падения velocity. Деплой: 90 → 12 мин. Production-инцидентов: −60%. API latency: 1.2с → 180мс.
До сих пор веду архитектурное ревью cross-service задач и провожу технические собесы fullstack-кандидатов.