🚀 Oferta especial: 60% OFF no CrazyStack - Últimas vagas!Garantir vaga →
MÓDULO 2 - AULA 7

Dashboard de Métricas

Implementando métricas avançadas com SQL complexo e análises em tempo real

50 minutos
Avançado
Sistema de Métricas do Restaurantix

O dashboard do Restaurantix implementa métricas avançadas para análise de negócio em tempo real.

Métricas Implementadas

  • Receita Mensal: Comparação com mês anterior
  • Pedidos por Dia: Volume diário
  • Produtos Populares: Ranking por vendas
  • Receitas Diárias: Período customizado
  • Crescimento: Percentual de variação

Tecnologias SQL

  • Agregações: SUM, COUNT, AVG
  • Agrupamento: GROUP BY com datas
  • Joins: Múltiplas tabelas
  • Funções: TO_CHAR, EXTRACT
  • Filtros: Períodos dinâmicos
Receita Mensal com Comparação

get-month-revenue.ts

// src/http/routes/get-month-revenue.ts
import { and, eq, gte, sql, sum, lte } from "drizzle-orm";
import { db } from "@/application/infra/db/connection";
import { orders } from "@/application/infra/db/schema";
import { auth } from "../auth";
import { UnauthorizedError } from "../errors/unauthorized-error";
import dayjs from "dayjs";

export const getMonthRevenue = auth.get(
  "/metrics/month-revenue",
  async ({ getCurrentUser }) => {
    const { restaurantId } = await getCurrentUser();
    if (!restaurantId) {
      throw new UnauthorizedError();
    }
    
    // Configurar período de análise
    const today = dayjs();
    const lastMonth = today.subtract(1, "month");
    const startOfLastMonth = lastMonth.startOf("month");

    // Query com agrupamento por mês/ano
    const monthRevenue = await db
      .select({
        monthWithYear: sql<string>`TO_CHAR(${orders.createdAt}, 'YYYY-MM')`,
        total: sum(orders.priceInCents).mapWith(Number),
      })
      .from(orders)
      .where(
        and(
          eq(orders.restaurantId, restaurantId),
          gte(orders.createdAt, startOfLastMonth.toDate()),
          lte(orders.createdAt, today.toDate()),
        ),
      )
      .groupBy(sql`TO_CHAR(${orders.createdAt}, 'YYYY-MM')`);
    
    // Calcular percentual de crescimento
    const diffFromLastMonth =
      currentMonthRevenue && lastMonthRevenue
        ? (currentMonthRevenue.total * 100) / lastMonthRevenue.total
        : null;
    
    return {
      currentMonthRevenue,
      lastMonthRevenue,
      diffFromLastMonth: diffFromLastMonth
        ? Number((diffFromLastMonth - 100).toFixed(2))
        : 0,
    };
  },
);
Produtos Mais Populares

get-popular-products.ts

// src/http/routes/get-popular-products.ts
import { sum, eq, desc, type SQLWrapper } from "drizzle-orm";
import { db } from "@/application/infra/db/connection";
import { orderItems, orders, products } from "@/application/infra/db/schema";
import { auth } from "@/http/auth";
import { UnauthorizedError } from "@/http/errors/unauthorized-error";

export const getPopularProducts = auth.get(
  "/metrics/popular-products",
  async ({ getCurrentUser }) => {
    const { restaurantId } = await getCurrentUser();
    if (!restaurantId) {
      throw new UnauthorizedError();
    }
    
    // Query com múltiplos JOINs
    const popularProducts = await db
      .select({
        productName: products.name,
        amount: sum(orderItems.quantity).mapWith(Number),
      })
      .from(orderItems)
      .leftJoin(orders, eq(orders.id, orderItems.orderId))
      .leftJoin(products, eq(products.id, orderItems.productId))
      .where(eq(orders.restaurantId, restaurantId))
      .groupBy(products.name)
      .orderBy((fields: { amount: SQLWrapper }) => {
        return desc(fields.amount);
      })
      .limit(50);

    return popularProducts;
  },
);
🎯 Exercício Prático

Implemente o sistema completo de métricas do Restaurantix:

Desafio:

  1. Implemente todas as 4 rotas de métricas mostradas
  2. Teste cada rota individualmente
  3. Crie um endpoint que retorna todas as métricas juntas
  4. Adicione cache com TTL de 5 minutos
  5. Implemente filtros por período customizado
  6. Adicione métricas de performance (tempo de resposta)

💡 Dicas avançadas:

  • • Use Promise.all() para carregar métricas em paralelo
  • • Implemente cache Redis para queries pesadas
  • • Adicione índices no banco para campos de data
  • • Use SQL views para queries complexas recorrentes
  • • Monitore performance com logs de tempo de execução