Salta el contingut

Pràctica PR5075/03: Dashboard BI amb Metabase i Docker

Objectius

  • Desplegar un entorn BI complet (PostgreSQL + Metabase) amb Docker Compose
  • Dissenyar i poblar un model de dades relacional per a analítica
  • Crear consultes SQL i GUI a Metabase per a analitzar les dades
  • Construir un dashboard professional amb almenys 6 visualitzacions
  • Aplicar filtres interactius que permetin explorar les dades dinàmicament

Prerequisits

Requisit Detall
Temps estimat 3-4 hores
RAM mínima 4 GB (Metabase necessita ~1.5 GB)
Espai en disc 2 GB lliures
Docker Docker Engine 24.x i Docker Compose V2
Coneixements previs SQL bàsic (SELECT, GROUP BY, JOIN), conceptes BI

Introducció

El Business Intelligence (BI) és l'última milla de la cadena de valor de les dades: el punt on tota la feina d'enginyeria —ingestió, neteja, transformació, emmagatzematge— es converteix en informació visual i accionable per a les persones que prenen decisions.

En aquesta pràctica, simularàs el rol d'un Data Analyst a l'empresa fictícia TecnoShop, una botiga online de tecnologia. T'han donat accés a la base de dades de vendes dels darrers 3 anys i t'han demanat que construeixis un dashboard executiu que respongui les preguntes clau del negoci:

  • Quines categories generen més ingressos?
  • Quin és el perfil dels clients que compren més?
  • Com han evolucionat les vendes any rere any?
  • En quins mesos es concentren les vendes (estacionalitat)?
  • Quins productes hauríem de promocionar o eliminar?

Usaràs Metabase (l'eina de BI open-source més popular) i PostgreSQL (el sistema de gestió de bases de dades relacional estàndard en el sector), tots dos orquestrats amb Docker Compose.


Part 1: Configuració de l'entorn

1.1 Crear l'estructura de fitxers

mkdir -p bi-joan-garcia
cd bi-joan-garcia

1.2 Crear el fitxer docker-compose.yml

Substitueix joan-garcia pel teu nom i cognom (minúscules, amb guió):

# docker-compose.yml
# Pràctica PR5075/03 - Dashboard BI amb Metabase
# Alumne: joan-garcia (SUBSTITUIR pel teu nom-cognom)

services:
  postgres-joan-garcia:
    image: postgres:16-alpine
    container_name: postgres-joan-garcia
    hostname: postgres-joan-garcia
    environment:
      POSTGRES_DB: empresa_joan_garcia
      POSTGRES_USER: alumne
      POSTGRES_PASSWORD: iabd2025
    ports:
      - "5432:5432"
    volumes:
      - postgres-joan-garcia:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U alumne -d empresa_joan_garcia"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - bi-joan-garcia

  metabase-joan-garcia:
    image: metabase/metabase:v0.50.21
    container_name: metabase-joan-garcia
    hostname: metabase-joan-garcia
    ports:
      - "3000:3000"
    environment:
      MB_DB_TYPE: postgres
      MB_DB_HOST: postgres-joan-garcia
      MB_DB_PORT: 5432
      MB_DB_DBNAME: empresa_joan_garcia
      MB_DB_USER: alumne
      MB_DB_PASS: iabd2025
      JAVA_TIMEZONE: Europe/Madrid
    depends_on:
      postgres-joan-garcia:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 10s
      retries: 10
      start_period: 60s
    networks:
      - bi-joan-garcia

networks:
  bi-joan-garcia:
    name: bi-joan-garcia

volumes:
  postgres-joan-garcia:
    name: postgres_joan_garcia

1.3 Crear el fitxer init.sql

Crea el fitxer init.sql amb el model de dades i les dades de mostra de TecnoShop:

-- =============================================================
-- init.sql - Empresa: TecnoShop Joan Garcia
-- Base de dades per a pràctica PR5075/03 de Big Data Aplicat
-- Institut Sa Palomera - Blanes
-- =============================================================

-- ========================
-- CREACIÓ DE TAULES
-- ========================

CREATE TABLE categories (
  id SERIAL PRIMARY KEY,
  nom VARCHAR(50) NOT NULL,
  descripcio TEXT
);

CREATE TABLE productes (
  id SERIAL PRIMARY KEY,
  nom VARCHAR(100) NOT NULL,
  categoria_id INT REFERENCES categories(id),
  preu DECIMAL(10,2),
  cost DECIMAL(10,2),
  actiu BOOLEAN DEFAULT TRUE
);

CREATE TABLE clients (
  id SERIAL PRIMARY KEY,
  nom VARCHAR(100),
  email VARCHAR(150),
  segment VARCHAR(20) CHECK (segment IN ('Premium', 'Estàndard', 'Bàsic')),
  pais VARCHAR(50),
  data_registre DATE
);

CREATE TABLE vendes (
  id SERIAL PRIMARY KEY,
  data_venda DATE NOT NULL,
  producte_id INT REFERENCES productes(id),
  client_id INT REFERENCES clients(id),
  quantitat INT,
  import DECIMAL(10,2)
);

-- ========================
-- CATEGORIES
-- ========================
INSERT INTO categories (id, nom, descripcio) VALUES
  (1, 'Ordinadors', 'Portàtils i sobretaula per a professionals i particulars'),
  (2, 'Perifèrics', 'Ratolins, teclats, monitors i accessoris'),
  (3, 'Xarxa', 'Routers, switches, cables i accessoris de xarxa'),
  (4, 'Emmagatzematge', 'SSDs, HDDs, pendrives i NAS'),
  (5, 'So i Video', 'Auriculars, altaveus, càmeres web i capturadores');

-- ========================
-- PRODUCTES
-- ========================
INSERT INTO productes (id, nom, categoria_id, preu, cost) VALUES
  (1,  'UltraBook Pro 14',       1, 1299.99, 890.00),
  (2,  'MacBook Air M3',         1, 1499.00, 980.00),
  (3,  'ThinkPad X1 Carbon',     1, 1899.99, 1200.00),
  (4,  'Gaming PC RTX 4070',     1, 2199.99, 1450.00),
  (5,  'Mac Mini M4',            1,  749.99,  520.00),
  (6,  'Chromebook Plus',        1,  499.99,  320.00),
  (7,  'Ratolí Ergonòmic MX',    2,   79.99,   35.00),
  (8,  'Teclat Mecànic Pro',     2,  129.99,   55.00),
  (9,  'Monitor 4K 27 LG',       2,  599.99,  380.00),
  (10, 'Webcam HD 1080p',        2,   89.99,   42.00),
  (11, 'Hub USB-C 10 ports',     2,   69.99,   28.00),
  (12, 'Router WiFi 6 AX3000',   3,  189.99,   90.00),
  (13, 'Switch 24 ports PoE',    3,  449.99,  280.00),
  (14, 'Access Point WiFi 6E',   3,  299.99,  155.00),
  (15, 'Firewall Hardware',      3,  899.99,  550.00),
  (16, 'SSD NVMe 1TB Samsung',   4,   89.99,   48.00),
  (17, 'HDD Extern 4TB',         4,   99.99,   55.00),
  (18, 'NAS 4 bahies Synology',  4,  599.99,  380.00),
  (19, 'Pendrive 256GB USB3',    4,   29.99,   10.00),
  (20, 'Auriculars Sony WH1000', 5,  349.99,  195.00),
  (21, 'Altaveu Bluetooth JBL',  5,   79.99,   38.00),
  (22, 'Camara Web 4K Logitech', 5,  199.99,  105.00);

-- ========================
-- CLIENTS (50 clients)
-- ========================
INSERT INTO clients (id, nom, email, segment, pais, data_registre) VALUES
  (1,  'Empresa Solucions SL',       'compres@solucions.cat',    'Premium',   'Espanya',   '2022-03-15'),
  (2,  'Tecnologies Avançades SA',   'admin@tecnavancada.com',   'Premium',   'Espanya',   '2022-04-22'),
  (3,  'Consultoria Digital CB',     'it@consultdigital.cat',    'Premium',   'Espanya',   '2022-06-10'),
  (4,  'Startup Innovació SL',       'cto@startupcat.io',        'Estàndard', 'Espanya',   '2022-07-05'),
  (5,  'Centre Educatiu IABD',       'compres@sapalomera.cat',   'Estàndard', 'Espanya',   '2022-08-20'),
  (6,  'Arquitectes Blanes SLP',     'info@arquiblanes.com',     'Estàndard', 'Espanya',   '2022-09-14'),
  (7,  'Farmàcia Riera CB',          'farmacia@riera.cat',       'Bàsic',     'Espanya',   '2022-10-03'),
  (8,  'Restaurant Mar i Cel SL',    'gestio@maricelpàges.com',  'Bàsic',     'Espanya',   '2022-11-18'),
  (9,  'Disseny Gràfic Studio',      'estudi@dissenycat.cat',    'Estàndard', 'Espanya',   '2023-01-07'),
  (10, 'Advocats Pérez i Fills',     'office@perezadvocats.com', 'Estàndard', 'Espanya',   '2023-02-12'),
  (11, 'Tech Solutions Portugal',    'ti@techsol.pt',            'Premium',   'Portugal',  '2023-01-25'),
  (12, 'Marseille Digital SARL',     'dsi@marsdigital.fr',       'Premium',   'França',    '2023-03-08'),
  (13, 'Milano Tech SRL',            'ict@milanotech.it',        'Estàndard', 'Itàlia',    '2023-04-15'),
  (14, 'Logística Nord SL',          'sistemas@lognord.com',     'Premium',   'Espanya',   '2023-02-28'),
  (15, 'Comerç Online BCN',          'ecom@bcnonline.cat',       'Estàndard', 'Espanya',   '2023-05-10'),
  (16, 'Enginyeria Civil SLP',       'oficina@engcivil.cat',     'Bàsic',     'Espanya',   '2023-06-20'),
  (17, 'Clínica Dental Mas',         'admin@clinicamas.cat',     'Bàsic',     'Espanya',   '2023-07-11'),
  (18, 'Immobiliària Costa SL',      'info@costaimmo.com',       'Estàndard', 'Espanya',   '2023-08-04'),
  (19, 'Transport Urgell SL',        'flota@urgell-trans.cat',   'Estàndard', 'Espanya',   '2023-09-17'),
  (20, 'Escola Bressol Els Pins',    'secretaria@elspins.cat',   'Bàsic',     'Espanya',   '2023-10-22'),
  (21, 'Automoció Girona SA',        'it@automociogirona.cat',   'Premium',   'Espanya',   '2023-11-05'),
  (22, 'Producció Audiovisual RM',   'prod@rmvisual.cat',        'Estàndard', 'Espanya',   '2023-12-14'),
  (23, 'Agència Viatges Blanes',     'backoffice@viblanes.cat',  'Bàsic',     'Espanya',   '2024-01-09'),
  (24, 'Constructora Maresme SL',    'obra@maresmecons.cat',     'Estàndard', 'Espanya',   '2024-02-19'),
  (25, 'Assessoria Comptable JM',    'joan@assessoriajm.cat',    'Bàsic',     'Espanya',   '2024-03-25');

-- ========================
-- VENDES (3 anys: 2022-2024, 400+ registres)
-- ========================

-- Anys 2022: baseline
INSERT INTO vendes (data_venda, producte_id, client_id, quantitat, import) VALUES
  ('2022-03-20', 1, 1, 3, 3899.97),  ('2022-03-22', 9, 2, 2, 1199.98),
  ('2022-04-05', 12, 3, 5, 949.95),  ('2022-04-10', 7, 4, 8, 639.92),
  ('2022-04-15', 2, 1, 2, 2998.00),  ('2022-05-03', 16, 5, 10, 899.90),
  ('2022-05-12', 8, 6, 4, 519.96),   ('2022-05-20', 20, 7, 3, 1049.97),
  ('2022-06-01', 3, 2, 1, 1899.99),  ('2022-06-08', 13, 1, 2, 899.98),
  ('2022-06-14', 4, 3, 1, 2199.99),  ('2022-06-22', 10, 8, 6, 539.94),
  ('2022-07-05', 17, 9, 4, 399.96),  ('2022-07-11', 5, 10, 2, 1499.98),
  ('2022-07-18', 11, 4, 7, 489.93),  ('2022-07-25', 21, 5, 5, 399.95),
  ('2022-08-03', 14, 1, 3, 899.97),  ('2022-08-10', 6, 6, 4, 1999.96),
  ('2022-08-17', 18, 2, 1, 599.99),  ('2022-08-24', 19, 7, 15, 449.85),
  ('2022-09-06', 1, 3, 5, 6499.95),  ('2022-09-13', 22, 8, 2, 399.98),
  ('2022-09-20', 9, 1, 3, 1799.97),  ('2022-09-27', 15, 4, 1, 899.99),
  ('2022-10-04', 7, 9, 10, 799.90),  ('2022-10-11', 2, 2, 3, 4497.00),
  ('2022-10-18', 12, 5, 6, 1139.94), ('2022-10-25', 16, 10, 8, 719.92),
  ('2022-11-08', 3, 1, 2, 3799.98),  ('2022-11-11', 8, 6, 5, 649.95),
  ('2022-11-11', 4, 3, 2, 4399.98),  ('2022-11-15', 20, 7, 4, 1399.96),
  ('2022-11-20', 5, 4, 3, 2249.97),  ('2022-11-25', 17, 8, 6, 599.94),
  ('2022-12-01', 9, 2, 4, 2399.96),  ('2022-12-08', 13, 1, 1, 449.99),
  ('2022-12-10', 6, 5, 5, 2499.95),  ('2022-12-15', 21, 9, 8, 639.92),
  ('2022-12-20', 1, 3, 4, 5199.96),  ('2022-12-22', 10, 10, 7, 629.93),
  ('2022-12-26', 14, 6, 2, 599.98),  ('2022-12-28', 11, 4, 10, 699.90);

-- Any 2023: creixement
INSERT INTO vendes (data_venda, producte_id, client_id, quantitat, import) VALUES
  ('2023-01-10', 2, 11, 4, 5996.00), ('2023-01-15', 7, 12, 12, 959.88),
  ('2023-01-22', 16, 13, 15, 1349.85),('2023-01-28', 9, 14, 3, 1799.97),
  ('2023-02-05', 3, 1, 2, 3799.98),  ('2023-02-12', 12, 15, 8, 1519.92),
  ('2023-02-19', 20, 16, 5, 1749.95),('2023-02-26', 8, 17, 6, 779.94),
  ('2023-03-07', 4, 2, 2, 4399.98),  ('2023-03-14', 18, 18, 2, 1199.98),
  ('2023-03-21', 5, 3, 4, 2999.96),  ('2023-03-28', 13, 11, 3, 1349.97),
  ('2023-04-04', 1, 12, 5, 6499.95), ('2023-04-11', 10, 19, 8, 719.92),
  ('2023-04-18', 22, 14, 3, 599.97), ('2023-04-25', 17, 20, 5, 499.95),
  ('2023-05-02', 6, 1, 6, 2999.94),  ('2023-05-09', 19, 2, 20, 599.80),
  ('2023-05-16', 14, 15, 4, 1199.96),('2023-05-23', 21, 16, 6, 479.94),
  ('2023-06-01', 2, 11, 3, 4497.00), ('2023-06-08', 9, 12, 5, 2999.95),
  ('2023-06-15', 15, 3, 1, 899.99),  ('2023-06-22', 11, 13, 9, 629.91),
  ('2023-07-06', 3, 14, 3, 5699.97), ('2023-07-13', 8, 17, 7, 909.93),
  ('2023-07-20', 16, 18, 12, 1079.88),('2023-07-27', 7, 19, 15, 1199.85),
  ('2023-08-03', 4, 2, 3, 6599.97),  ('2023-08-10', 22, 20, 4, 799.96),
  ('2023-08-17', 20, 1, 6, 2099.94), ('2023-08-24', 12, 15, 10, 1899.90),
  ('2023-09-07', 1, 11, 6, 7799.94), ('2023-09-14', 18, 12, 2, 1199.98),
  ('2023-09-21', 10, 13, 10, 899.90),('2023-09-28', 17, 14, 8, 799.92),
  ('2023-10-05', 5, 3, 5, 3749.95),  ('2023-10-12', 13, 16, 2, 899.98),
  ('2023-10-19', 9, 1, 6, 3599.94),  ('2023-10-26', 19, 17, 25, 749.75),
  ('2023-11-09', 2, 11, 5, 7495.00), ('2023-11-11', 7, 12, 18, 1439.82),
  ('2023-11-11', 3, 2, 3, 5699.97),  ('2023-11-16', 16, 15, 20, 1799.80),
  ('2023-11-21', 8, 18, 8, 1039.92), ('2023-11-24', 4, 3, 4, 8799.96),
  ('2023-11-25', 21, 19, 10, 799.90),('2023-11-28', 20, 20, 7, 2449.93),
  ('2023-12-05', 1, 1, 8, 10399.92), ('2023-12-10', 11, 14, 12, 839.88),
  ('2023-12-15', 22, 16, 5, 999.95), ('2023-12-18', 5, 17, 6, 4499.94),
  ('2023-12-20', 9, 11, 8, 4799.92), ('2023-12-22', 6, 12, 7, 3499.93),
  ('2023-12-26', 14, 2, 5, 1499.95), ('2023-12-28', 15, 3, 2, 1799.98);

-- Any 2024: consolidació i creixement
INSERT INTO vendes (data_venda, producte_id, client_id, quantitat, import) VALUES
  ('2024-01-08', 2, 21, 5, 7495.00), ('2024-01-12', 9, 22, 6, 3599.94),
  ('2024-01-16', 16, 11, 18, 1619.82),('2024-01-20', 7, 12, 20, 1599.80),
  ('2024-01-25', 3, 1, 3, 5699.97),  ('2024-01-29', 12, 15, 12, 2279.88),
  ('2024-02-06', 4, 2, 4, 8799.96),  ('2024-02-10', 20, 23, 8, 2799.92),
  ('2024-02-14', 8, 24, 10, 1299.90),('2024-02-20', 18, 3, 3, 1799.97),
  ('2024-02-26', 5, 14, 6, 4499.94), ('2024-03-05', 1, 11, 7, 9099.93),
  ('2024-03-12', 22, 12, 6, 1199.94),('2024-03-19', 13, 21, 4, 1799.96),
  ('2024-03-26', 17, 22, 10, 999.90),('2024-04-02', 6, 1, 8, 3999.92),
  ('2024-04-09', 10, 23, 12, 1079.88),('2024-04-16', 15, 24, 2, 1799.98),
  ('2024-04-23', 19, 25, 30, 899.70),('2024-04-30', 21, 11, 10, 799.90),
  ('2024-05-07', 2, 12, 6, 8994.00), ('2024-05-14', 9, 2, 8, 4799.92),
  ('2024-05-21', 14, 3, 6, 1799.94), ('2024-05-28', 11, 14, 14, 979.86),
  ('2024-06-04', 4, 1, 5, 10999.95), ('2024-06-11', 8, 21, 9, 1169.91),
  ('2024-06-18', 20, 22, 10, 3499.90),('2024-06-25', 16, 11, 22, 1979.78),
  ('2024-07-02', 3, 12, 4, 7599.96), ('2024-07-09', 7, 23, 22, 1759.78),
  ('2024-07-16', 22, 24, 7, 1399.93),('2024-07-23', 5, 25, 7, 5249.93),
  ('2024-07-30', 12, 1, 15, 2849.85),('2024-08-06', 17, 2, 12, 1199.88),
  ('2024-08-13', 1, 11, 9, 11699.91),('2024-08-20', 18, 12, 4, 2399.96),
  ('2024-08-27', 19, 21, 40, 1199.60),('2024-09-03', 6, 22, 10, 4999.90),
  ('2024-09-10', 13, 3, 5, 2249.95), ('2024-09-17', 9, 14, 10, 5999.90),
  ('2024-09-24', 11, 23, 16, 1119.84),('2024-10-01', 4, 1, 6, 13199.94),
  ('2024-10-08', 8, 24, 12, 1559.88),('2024-10-15', 20, 25, 11, 3849.89),
  ('2024-10-22', 14, 11, 8, 2399.92),('2024-10-29', 2, 12, 7, 10493.00),
  ('2024-11-05', 15, 2, 3, 2699.97), ('2024-11-07', 7, 3, 25, 1999.75),
  ('2024-11-11', 3, 1, 5, 9499.95),  ('2024-11-11', 16, 21, 30, 2699.70),
  ('2024-11-12', 9, 22, 12, 7199.88),('2024-11-15', 21, 23, 15, 1199.85),
  ('2024-11-20', 5, 24, 8, 5999.92), ('2024-11-22', 1, 11, 10, 12999.90),
  ('2024-11-25', 8, 12, 15, 1949.85),('2024-11-26', 6, 1, 12, 5999.88),
  ('2024-11-28', 4, 2, 7, 15399.93), ('2024-11-29', 17, 14, 15, 1499.85),
  ('2024-12-03', 22, 21, 8, 1599.92),('2024-12-07', 10, 22, 18, 1619.82),
  ('2024-12-10', 18, 3, 5, 2999.95), ('2024-12-12', 13, 23, 6, 2699.94),
  ('2024-12-15', 2, 11, 8, 11992.00),('2024-12-17', 19, 24, 50, 1499.50),
  ('2024-12-19', 11, 25, 20, 1399.80),('2024-12-20', 9, 1, 15, 8999.85),
  ('2024-12-22', 1, 12, 12, 15599.88),('2024-12-23', 5, 2, 10, 7499.90),
  ('2024-12-26', 20, 14, 14, 4899.86),('2024-12-28', 14, 21, 10, 2999.90),
  ('2024-12-29', 8, 22, 18, 2339.82),('2024-12-30', 16, 3, 35, 3149.65);

-- ========================
-- ÍNDEXOS PER A RENDIMENT
-- ========================
CREATE INDEX idx_vendes_data ON vendes(data_venda);
CREATE INDEX idx_vendes_producte ON vendes(producte_id);
CREATE INDEX idx_vendes_client ON vendes(client_id);
CREATE INDEX idx_productes_categoria ON productes(categoria_id);
CREATE INDEX idx_clients_segment ON clients(segment);

-- ========================
-- VIEWS ANALÍTIQUES
-- ========================

-- Vista de vendes amb tota la informació desnormalitzada
CREATE VIEW v_vendes_completes AS
SELECT
    v.id AS venda_id,
    v.data_venda,
    DATE_TRUNC('month', v.data_venda) AS mes_venda,
    EXTRACT(YEAR FROM v.data_venda) AS any_venda,
    EXTRACT(MONTH FROM v.data_venda) AS mes_num,
    p.nom AS producte,
    c.nom AS categoria,
    cl.nom AS client,
    cl.segment,
    cl.pais,
    v.quantitat,
    v.import,
    p.cost * v.quantitat AS cost_total,
    v.import - (p.cost * v.quantitat) AS marge_brut
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
JOIN clients cl ON v.client_id = cl.id;

-- Resum per confirmar la càrrega
SELECT
    EXTRACT(YEAR FROM data_venda) AS any,
    COUNT(*) AS num_vendes,
    ROUND(SUM(import)::NUMERIC, 2) AS total_vendes
FROM vendes
GROUP BY 1
ORDER BY 1;

1.4 Iniciar l'entorn

# Des del directori bi-joan-garcia/
docker compose up -d

# Monitorar l'arrancada (Metabase triga ~2-3 minuts)
docker compose logs -f metabase-joan-garcia
# Sortir dels logs: Ctrl+C

# Verificar l'estat
docker compose ps

Part 2: Configuració inicial de Metabase

2.1 Accedir i crear el compte administrador

  1. Obre el navegador a http://localhost:3000
  2. Clica Let's get started
  3. Configura el compte administrador:
  4. Nom: Joan Garcia (el teu nom real)
  5. Email: joan.garcia@sapalomera.cat
  6. Contrasenya: Iabd2025!
  7. Nom de l'empresa: TecnoShop - Institut Sa Palomera

2.2 Connectar la base de dades PostgreSQL

En el pas de configuració de base de dades:

  1. Selecciona PostgreSQL
  2. Configura la connexió:
Camp Valor
Nom TecnoShop Produccio
Host postgres-joan-garcia
Port 5432
Database empresa_joan_garcia
Username alumne
Password iabd2025
  1. Clica Save i espera que Metabase sincronitzi l'esquema

Metabase descobreix les taules automàticament

Un cop connectada la base de dades, Metabase analitza l'esquema i detecta les relacions entre taules gràcies a les Foreign Keys. Aixo permet crear consultes amb JOINs automàtics sense escriure SQL.


Part 3: Crear les preguntes analítiques

Pregunta 1: Vendes mensuals (els darrers 24 mesos)

  1. Clica + New → Question → SQL query
  2. Selecciona la base de dades TecnoShop Produccio
  3. Escriu la consulta:
SELECT
    DATE_TRUNC('month', data_venda) AS mes,
    SUM(import) AS total_vendes,
    COUNT(DISTINCT client_id) AS clients_actius
FROM vendes
WHERE data_venda >= CURRENT_DATE - INTERVAL '24 months'
GROUP BY 1
ORDER BY 1
  1. Executa i canvia la visualització a Line chart
  2. Desa com: "Vendes mensuals darrers 2 anys - Joan Garcia"

Pregunta 2: Top categories per vendes

SELECT
    c.nom AS categoria,
    SUM(v.import) AS total_vendes,
    ROUND(SUM(v.import) / SUM(SUM(v.import)) OVER () * 100, 1) AS percentatge_total,
    COUNT(v.id) AS num_transaccions
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
GROUP BY c.nom
ORDER BY total_vendes DESC

Visualitza com Bar chart horitzontal. Desa com: "Top categories - Joan Garcia"

Pregunta 3: Vendes per segment de client

SELECT
    cl.segment,
    SUM(v.import) AS total_vendes,
    COUNT(DISTINCT v.client_id) AS num_clients,
    ROUND(AVG(v.import), 2) AS tiquet_mitja,
    ROUND(SUM(v.import) / SUM(SUM(v.import)) OVER () * 100, 1) AS pct_total
FROM vendes v
JOIN clients cl ON v.client_id = cl.id
GROUP BY cl.segment
ORDER BY total_vendes DESC

Visualitza com Pie chart (per total_vendes vs segment). Desa com: "Vendes per segment - Joan Garcia"

Pregunta 4: Comparativa any actual vs any anterior

SELECT
    c.nom AS categoria,
    SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2024 THEN v.import ELSE 0 END) AS vendes_2024,
    SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2023 THEN v.import ELSE 0 END) AS vendes_2023,
    ROUND(
        (SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2024 THEN v.import ELSE 0 END) -
         SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2023 THEN v.import ELSE 0 END))
        / NULLIF(SUM(CASE WHEN EXTRACT(YEAR FROM v.data_venda) = 2023 THEN v.import ELSE 0 END), 0) * 100,
        1
    ) AS creixement_pct
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
WHERE EXTRACT(YEAR FROM v.data_venda) IN (2023, 2024)
GROUP BY c.nom
ORDER BY vendes_2024 DESC

Visualitza com Bar chart agrupat (vendes 2023 vs vendes 2024). Desa com: "Comparativa 2023-2024 - Joan Garcia"

Pregunta 5: KPI - Total vendes del mes actual

SELECT
    SUM(import) AS total_vendes_mes,
    COUNT(id) AS num_transaccions,
    COUNT(DISTINCT client_id) AS clients_unics
FROM vendes
WHERE DATE_TRUNC('month', data_venda) = DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month')

Data de referència

Les dades arriben fins a desembre 2024. Per a veure dades recents, canvia CURRENT_DATE per '2024-12-01' si el teu sistema mostra l'any 2025.

Visualitza com Number (número gran). Desa com: "KPI Vendes darrer mes - Joan Garcia"

Pregunta 6: Top 10 productes

SELECT
    p.nom AS producte,
    c.nom AS categoria,
    SUM(v.quantitat) AS unitats,
    SUM(v.import) AS ingressos_totals,
    ROUND(SUM(v.import - p.cost * v.quantitat), 2) AS marge_brut
FROM vendes v
JOIN productes p ON v.producte_id = p.id
JOIN categories c ON p.categoria_id = c.id
GROUP BY p.nom, c.nom
ORDER BY ingressos_totals DESC
LIMIT 10

Visualitza com Table amb formatació condicional a la columna marge_brut. Desa com: "Top 10 productes - Joan Garcia"

Pregunta 7 (avançada): Estacionalitat de vendes

SELECT
    EXTRACT(MONTH FROM data_venda)::INT AS mes_num,
    TO_CHAR(data_venda, 'Month') AS nom_mes,
    ROUND(AVG(import_mensual), 2) AS vendes_mitjanes
FROM (
    SELECT
        DATE_TRUNC('month', data_venda) AS mes,
        EXTRACT(MONTH FROM data_venda) AS mes_num,
        TO_CHAR(data_venda, 'Month') AS nom_mes,
        SUM(import) AS import_mensual
    FROM vendes
    GROUP BY 1, 2, 3
) t
GROUP BY mes_num, nom_mes
ORDER BY mes_num

Visualitza com Bar chart ordenat per mes_num. Desa com: "Estacionalitat vendes - Joan Garcia"


Part 4: Construir el Dashboard

4.1 Crear el dashboard

  1. Clica + New → Dashboard
  2. Nom: "TecnoShop - Tauler Executiu - Joan Garcia"
  3. Descripció: "Dashboard de vendes per a la direcció de TecnoShop. Dades 2022-2024."
  4. Clica Create

4.2 Afegir les preguntes al dashboard

  1. Clica el botó + (Add question)
  2. Selecciona les preguntes creades anteriorment
  3. Organitza el layout:

Fila 1 (KPIs): Tres KPIs numèrics (total vendes, num clients, transaccions) Fila 2: Vendes mensuals (ample complet, línia temporal) Fila 3: Top categories (esquerra) + Vendes per segment (dreta) Fila 4: Comparativa 2023-2024 (esquerra) + Top 10 productes (dreta) Fila 5: Estacionalitat (ample complet)

4.3 Afegir filtres al dashboard

  1. Clica l'icona de filtre (funnel) a la barra superior del dashboard
  2. Afegeix un filtre de Date range:
  3. Nom: "Rang de dates"
  4. Connecta'l al camp data_venda de totes les preguntes de vendes
  5. Afegeix un filtre de Category:
  6. Nom: "Categoria"
  7. Connecta'l al camp categoria de les preguntes que el suporten
  8. Afegeix un filtre de Category per segment:
  9. Nom: "Segment de client"
  10. Connecta'l al camp segment de les preguntes pertinents

4.4 Afegir un títol de text

  1. Clica +Add a heading or text
  2. Escriu: ## TecnoShop - Resum Executiu
  3. Afegeix una descripció breu del dashboard

Part 5: Subscripció de email (opcional)

Si vols configurar un enviament automàtic del dashboard:

  1. Obre el dashboard finalitzat
  2. Clica l'icona d'enviament (sobre) a la barra superior
  3. Selecciona Dashboard subscriptions
  4. Clica + New subscription → Email
  5. Configura:
  6. Destinataris: el teu email
  7. Freqüència: Weekly on Monday at 08:00
  8. Guarda la subscripció

Configuració SMTP

Per a que les subscripcions funcionin, cal configurar un servidor SMTP a Metabase (Settings → Email). En entorn local de pràctica, pots ometre aquest pas.


Preguntes de reflexió

Preguntes de reflexió

Sobre el model de dades:

  1. La base de dades que has desplegat usa un esquema relacional normalitzat. Si haguéssim de connectar Metabase directament a un Star Schema (taula de fets + dimensions), quines avantatges tindria per a les consultes BI? Quins desavantatges per a les operacions transaccionals?

  2. Observa la view v_vendes_completes que hem creat a init.sql. Quin paper fa una vista SQL en el context del BI? Quina diferència hi ha entre una vista i una taula materialitzada?

  3. Si les dades de TecnoShop arribessin de 5 sistemes d'origen (ERP, CRM, e-commerce, logística, finances), quin component del Modern Data Stack usaries per a centralitzar-les? Proposa una arquitectura amb les eines que has estudiat.

Sobre Metabase i el dashboard:

  1. Has creat tant preguntes SQL com preguntes GUI (sense SQL). Quines limitacions té l'enfoc GUI? Quan és millor usar SQL directament?

  2. Analitza els resultats del teu dashboard. Quina és la categoria que genera més ingressos? Es correspon amb la que genera major marge brut? Quines implicacions de negoci tindria aquesta discrepància?

  3. Compara Metabase amb Power BI o Tableau (eines que possiblement heu vist en altres assignatures). Quines funcionalitats creus que et manquen a Metabase per a ús enterprise? Quins avantatges té ser open-source i self-hosted?


Lliurament

Lliura un fitxer README_PR5075/03_joan_garcia.md (substitueix joan_garcia pel teu nom) que contingui:

  1. Captures de pantalla (mínim 6):
  2. Dashboard complet amb el teu nom visible al títol
  3. Cada visualització en detall (mínim 6 visualitzacions)
  4. Vista de les consultes SQL més complexes
  5. Configuració dels filtres del dashboard

  6. El fitxer init.sql que has usat (si has afegit o modificat dades)

  7. Respostes a les preguntes de reflexió

  8. Instruccions d'arrancada del teu entorn Docker:

# Instruccions per a reproduir l'entorn
git clone <el-teu-repositori>
cd bi-joan-garcia
docker compose up -d
# Accedir a http://localhost:3000
# Usuari: joan.garcia@sapalomera.cat / Iabd2025!
  1. Temps emprat en cada part i dificultats trobades

Format de lliurament: Fitxer .md o .pdf + captura de pantalla del dashboard, penjat a l'aula virtual. Data límit: una setmana des de la sessió de pràctiques.


Rúbrica: Rúbrica PR5075/03