Skip to main content
The Tambo360 dashboard provides comprehensive analytics for dairy farm production, offering real-time insights into production volumes, costs, waste, and trends.

Overview

The dashboard delivers:
  • Monthly production summary - Current month metrics for cheese and milk
  • Month-over-month comparisons - Percentage changes vs. previous month
  • 6-month historical trends - Graphical analysis by product and metric
  • Daily production log - Today’s batches at a glance
  • AI-powered alerts - Proactive notifications about production anomalies

Dashboard Location

The main dashboard is located at /dashboard and is the first screen users see after authentication.

Monthly Summary Metrics

The dashboard displays four key performance indicators:

1. Cheese Production

// Dashboard.tsx:38-52
<StatCard
  title="Queso Producido"
  value={data?.data.actual.quesos}
  unit=" Kg"
  trend={
    data?.data.variaciones.quesos !== null
      ? {
          value: data?.data.variaciones.quesos,
          isPositive: data?.data.variaciones.quesos >= 0,
        }
      : undefined
  }
  description={'vs ' + data?.data.mesPrevio}
/>
Shows: Total kilograms of cheese produced in current month Comparison: Percentage change vs. previous month

2. Milk Sales

// Dashboard.tsx:54-68
<StatCard
  title="Leche Vendida"
  value={data?.data.actual.leches}
  unit="L"
  trend={
    data?.data.variaciones.leches !== null
      ? {
          value: data?.data.variaciones.leches,
          isPositive: data?.data.variaciones.leches >= 0,
        }
      : undefined
  }
/>
Shows: Total liters of milk sold in current month Comparison: Percentage change vs. previous month

3. Total Waste

// Dashboard.tsx:11-20
const totalProduccion =
  (data?.data.actual.quesos || 0) + (data?.data.actual.leches || 0);

const porcentajeMermas =
  totalProduccion > 0
    ? ((data?.data.actual.mermas || 0) / totalProduccion) * 100
    : 0;
Shows: Waste as a percentage of total production Comparison: Percentage point change vs. previous month
Waste percentage is calculated across all products. A lower percentage is better.

4. Total Costs

// Dashboard.tsx:86-100
<StatCard
  title="Costos totales"
  value={data?.data.actual.costos}
  unit="$ "
  trend={
    data?.data.variaciones.costos !== null
      ? {
          value: data?.data.variaciones.costos,
          isPositive: data?.data.variaciones.costos >= 0,
        }
      : undefined
  }
/>
Shows: Total direct costs in ARS for current month Comparison: Percentage change vs. previous month

Data Calculation

The dashboard service aggregates data from production batches:

Current Month Summary

// dashboardService.ts:8-40
export class DashboardService {
  static async listarPorMes(userId: string) {
    // Define current month date range
    const hoy = new Date();
    const anio = hoy.getFullYear();
    const mes = hoy.getMonth() + 1;
    
    const fechaInicio = new Date(anio, mes - 1, 1);
    const fechaFin = new Date(anio, mes, 0, 23, 59, 59, 999);
    
    // Query production batches for current month
    const resultActual = await prisma.loteProduccion.findMany({
      where: {
        establecimiento: { idUsuario: userId },
        fechaProduccion: { gte: fechaInicio, lte: fechaFin }
      },
      include: { mermas: true, costosDirectos: true, producto: true }
    });
  }
}

Aggregation Logic

// dashboardService.ts:44-66
const buildSummary = (result: InfoMes) => {
  const summary = result.reduce<SummaryResult>((acc, lote) => {
    const category = lote.producto.categoria; // "quesos" or "leches"
    
    if (!acc[category]) {
      acc[category] = { cantidad: 0, costos: 0, mermas: 0 };
    }
    
    // Sum production quantity
    acc[category].cantidad += Number(lote.cantidad);
    
    // Sum costs
    acc[category].costos += lote.costosDirectos.reduce(
      (sum: number, costo: CostosDirecto) => sum + Number(costo.monto), 
      0
    );
    
    // Sum waste
    acc[category].mermas += lote.mermas.reduce(
      (sum: number, merma: Merma) => sum + Number(merma.cantidad), 
      0
    );
    
    return acc;
  }, {});
};

Month-over-Month Comparison

// dashboardService.ts:72-82
const variacion = (actual: number, anterior: number): number | null => {
  if (anterior === 0) return null; // No comparison if no previous data
  return ((actual - anterior) / anterior) * 100;
};

const variaciones = {
  leches: variacion(actual.leches, prev.leches),
  quesos: variacion(actual.quesos, prev.quesos),
  mermas: variacion(actual.mermas, prev.mermas),
  costos: variacion(actual.costos, prev.costos)
};
Production: Increase is good (green arrow up)Waste: Decrease is good (green arrow down)Costs: Context-dependent

Historical Comparison Chart

6-Month Trend Analysis

The dashboard includes a historical comparison chart showing trends over 6 months:
// dashboardService.ts:87-112
static async graficoProduccion(userId: string, producto: Categoria, metrica: Metrica) {
  const hoy = new Date();
  const anio = hoy.getFullYear();
  const mes = hoy.getMonth();
  
  // Define 6-month range
  const inicioPeriodo = new Date(anio, mes - 6, 1);
  const finPeriodo = new Date(anio, mes + 1, 0, 23, 59, 59, 999);
  
  // Query batches in range
  const lotes = await prisma.loteProduccion.findMany({
    where: {
      establecimiento: { idUsuario: userId },
      fechaProduccion: {
        gte: inicioPeriodo,
        lte: finPeriodo
      }
    },
    include: {
      producto: true,
      mermas: true,
      costosDirectos: true
    }
  });
}

Available Metrics

// Query parameters for chart
GET /api/dashboard/grafico?producto=quesos&metrica=cantidad

// producto: "quesos" | "leches"
// metrica: "cantidad" | "mermas" | "costos"

cantidad

Total production volume (kg or liters)

mermas

Total waste for the product category

costos

Total direct costs for the product category

Chart Data Processing

// dashboardService.ts:115-153
// Initialize months map
const mesesMap: Record<string, number> = {};

for (let i = 6; i >= 0; i--) {
  const fecha = new Date(anio, mes - i, 1);
  const key = `${fecha.getFullYear()}-${fecha.getMonth()}`;
  mesesMap[key] = 0;
}

// Aggregate data by month
for (const lote of lotes) {
  if (lote.producto.categoria !== producto) continue;
  
  const fecha = new Date(lote.fechaProduccion);
  const key = `${fecha.getFullYear()}-${fecha.getMonth()}`;
  
  let valor = 0;
  
  if (metrica === "cantidad") {
    valor = Number(lote.cantidad);
  }
  if (metrica === "mermas") {
    valor = lote.mermas.reduce((sum, m) => sum + Number(m.cantidad), 0);
  }
  if (metrica === "costos") {
    valor = lote.costosDirectos.reduce((sum, c) => sum + Number(c.monto), 0);
  }
  
  if (mesesMap[key] !== undefined) {
    mesesMap[key] += valor;
  }
}

Daily Production Log

The dashboard includes a real-time view of today’s production:
// Dashboard.tsx:109
<DailyProductionLog />
This component displays:
  • Batches created today
  • Production status (in progress vs. completed)
  • Quick access to batch details
The daily log uses the /api/lotes/produccion-del-dia endpoint to fetch today’s batches.

Alerts Section

The dashboard sidebar shows AI-powered production alerts:
// Dashboard.tsx:114
<AlertsSection />
Alerts are generated by the TamboEngine AI service and displayed in the sidebar for quick visibility. See Alerts for detailed information.

Dashboard Layout

The dashboard uses a responsive grid layout:
// Dashboard.tsx:36-116
<div className="space-y-6 w-full max-w-full overflow-x-hidden">
  {/* Header with breadcrumb */}
  <div className="flex flex-col md:flex-row md:items-center justify-between">
    <div>
      <p className="text-muted-foreground text-xs sm:text-sm">
        Dashboard / {user.establecimientos[0].nombre}
      </p>
      <h1 className="text-2xl sm:text-3xl font-bold">
        Reporte Mensual
      </h1>
    </div>
  </div>

  {/* 4 KPI cards */}
  <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
    {/* StatCard components */}
  </div>

  {/* Main content + sidebar */}
  <div className="flex flex-col lg:flex-row gap-6 w-full">
    <div className="flex-1 flex flex-col gap-6 min-w-0">
      <ComparacionHistorica />  {/* Chart */}
      <DailyProductionLog />     {/* Today's batches */}
    </div>
    <aside className="w-full lg:w-80 shrink-0">
      <AlertsSection />          {/* AI alerts */}
    </aside>
  </div>
</div>
  • 4-column KPI grid
  • Side-by-side chart and alerts
  • Full-width daily log

Data Refresh

The dashboard uses React Query for data management:
// Dashboard.tsx:6-10
const { user } = useAuth();
const { data, isPending } = useCurrentMonth();

// useCurrentMonth hook fetches from:
// GET /api/dashboard/mes-actual
Data is:
  • Fetched on component mount
  • Cached for performance
  • Automatically refetched on window focus
  • Marked as pending during loading

Use Cases

Scenario: End-of-month analysis
  1. View current month totals for cheese and milk
  2. Compare with previous month percentages
  3. Identify trends (increasing/decreasing production)
  4. Check if waste percentage is within targets
  5. Review cost changes and investigate anomalies
Scenario: Daily production oversight
  1. Check Daily Production Log for today’s batches
  2. Verify all batches are progressing
  3. Review any new AI alerts in sidebar
  4. Address any flagged issues immediately
Scenario: Strategic planning
  1. Use Historical Comparison chart
  2. Select product (cheese/milk)
  3. View 6-month trends for quantity, waste, or costs
  4. Identify seasonal patterns
  5. Plan production adjustments
Scenario: Financial review
  1. Check total costs stat card
  2. Compare with previous month
  3. View cost trend in historical chart
  4. Drill down into specific batches if costs spike
  5. Investigate cost optimization opportunities

Performance Optimization

Database Indexing

Queries are optimized with indexes on fechaProduccion and idUsuario

Parallel Queries

Current and previous month data fetched in parallel using Promise.all

Selective Includes

Only necessary relations loaded (mermas, costosDirectos, producto)

Client Caching

React Query caches dashboard data to reduce API calls

Best Practices

Regular Monitoring

Check dashboard daily for real-time production insights

Investigate Trends

When percentages change significantly, drill into batch details

Complete Batches

Mark batches as complete promptly for accurate analytics

Review Alerts

Act on AI alerts to prevent production issues

Common Issues

Cause: No production batches in current monthSolution: Create production batches to populate dashboard metrics
Cause: No data from previous month for comparisonExplanation: This is expected in the first month of use. Trends will appear once there’s historical data.
Cause: Insufficient data for the selected product/metricSolution: Ensure there are completed batches for the selected product in the last 6 months

API Reference

EndpointMethodPurpose
/api/dashboard/mes-actualGETGet current month summary with comparisons
/api/dashboard/graficoGETGet 6-month historical data for chart
/api/lotes/produccion-del-diaGETGet today’s production batches

Build docs developers (and LLMs) love