diff --git a/PLANO_BI_SUPERSET.md b/PLANO_BI_SUPERSET.md new file mode 100644 index 0000000..5a74ae6 --- /dev/null +++ b/PLANO_BI_SUPERSET.md @@ -0,0 +1,787 @@ +# PLANO BI — Substituição Metabase → Apache Superset +## Análise Real + Plano de Migração +### Versão 1.0 — Março 2026 + +--- + +## 1. DIAGNÓSTICO — ESTADO ATUAL + +### 1.1 O que foi descoberto no código + +O documento do Replit referenciava **Metabase** (Java, :8088) como o pilar visual do BI. Ao analisar o código real, a situação é diferente: + +| Componente | Nome no doc | Nome real no código | Status | +|---|---|---|---| +| Plataforma BI Visual | "Metabase" | **"MetaSet"** (alias) | Metabase por baixo | +| Proxy | `/metabase/*` | `server/metabase/proxy.ts` | Funcional | +| Auth | Metabase session | `server/metaset/routes.ts` (autologin) | Funcional | +| Client | MetabaseClient | `server/metaset/client.ts` | Funcional | +| UI | Advanced tab iframe | `/api/bi/metaset/autologin` → `/metabase/` | Funcional | +| **Superset** | Não mencionado | **`docker-compose.yml` linha 165** | **JÁ CONFIGURADO** | + +**Descoberta crítica:** O Apache Superset **já está no docker-compose.yml**: +```yaml +superset: + image: apache/superset:4.1.0 + restart: unless-stopped + environment: + SUPERSET_SECRET_KEY: ${SUPERSET_SECRET_KEY:-superset-secret-change-in-prod} + DATABASE_URL: postgresql://arcadia:arcadia123@db:5432/arcadia_superset + ports: + - "8088:8088" + depends_on: + db: + condition: service_healthy + profiles: [bi] +``` + +O Superset está configurado, mas **não integrado ao gateway Node.js**. O que falta é a ponte. + +### 1.2 Arquivos que precisam mudar vs o que fica igual + +**Mudam:** +``` +server/metabase/proxy.ts → substituir por server/superset/proxy.ts +server/metaset/routes.ts → substituir por server/superset/routes.ts +server/metaset/client.ts → substituir por server/superset/client.ts +client/src/pages/BiWorkspace.tsx (Advanced tab apenas) +docker-compose.yml (Superset config + init) +docker-compose.prod.yml (adicionar Superset) +.env.example (novas variáveis) +``` + +**NÃO mudam (ficam exatamente iguais):** +``` +server/python/bi_engine.py ← Motor Python :8004 continua intacto +server/bi/routes.ts ← CRUD de datasets/charts/dashboards +server/bi/upload.ts ← ETL pipeline +server/bi/staging.ts ← Staging +server/bi/engine-proxy.ts ← Proxy para BI Engine Python +client/src/pages/BiWorkspace.tsx (7 de 8 tabs ficam iguais) +Todas as tabelas do banco (bi_datasets, bi_charts, etc.) +``` + +--- + +## 2. POR QUE SUPERSET É MELHOR PARA O CASO + +### 2.1 Metabase vs Superset + +| Critério | Metabase | Apache Superset | +|---|---|---| +| Runtime | Java (JVM, 500MB+ RAM) | Python/Flask (mais leve) | +| Embedding | Iframe com cookie de sessão | **Guest Token JWT** (seguro, sem credenciais) | +| "Qualquer tela" | Iframe estático, limitado | **`@superset-ui/embedded-sdk`** — componente React nativo | +| REST API | Limitada e não documentada | **REST API v1 completa e documentada** | +| Consistência de stack | Java (fora do padrão) | Python (mesmo stack dos motores existentes) | +| Docker image | `metabase/metabase` ~700MB | `apache/superset` ~400MB | +| SQL Lab | Básico | **Poderoso** (autocomplete, histórico, salvar queries) | +| Alertas | Básico | **Avançado** (webhooks, Slack, email) | +| Tipos de chart | ~20 | **50+** (incluindo mapas, sunburst, funnel) | +| Banco de metadados | H2/Postgres separado | **Mesmo PostgreSQL** da Arcádia | + +### 2.2 A feature que o usuário pediu: "funcionar em qualquer tela" + +O Superset resolve isso com **Guest Token + Embedded SDK**: + +``` +Fluxo atual (Metabase): + BiWorkspace → iframe → /metabase/ → autologin com cookie + ❌ Só funciona na tab Advanced do BiWorkspace + ❌ Cookie expira, precisa re-autenticar + ❌ Não embeda em outras páginas facilmente + +Fluxo novo (Superset): + QUALQUER página React → + ✅ Funciona no Dashboard principal (/) + ✅ Funciona no SOE (/soe tab Financeiro) + ✅ Funciona no /contabil + ✅ Funciona no /financeiro + ✅ Funciona em qualquer tela do Arcádia + ✅ Guest Token renovado automaticamente (sem re-login) +``` + +--- + +## 3. ARQUITETURA COM SUPERSET + +### 3.1 Diagrama atualizado + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ USUÁRIO / FRONTEND │ +│ │ +│ BiWorkspace.tsx (8 tabs — 7 iguais, Advanced → Superset) │ +│ + QUALQUER outra página pode embedar um dashboard Superset │ +│ │ +│ ┌────────────────────────────────────────────────────────────┐ │ +│ │ │ │ +│ │ Componente React reutilizável em QUALQUER rota │ │ +│ └────────────────────────────────────────────────────────────┘ │ +└─────────────────────────┬────────────────────────────────────────────┘ + │ + ┌───────────────┼──────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌──────────────┐ ┌────────────────┐ ┌──────────────────────┐ +│ API BI Node │ │ BI Engine Py │ │ Superset (Python) │ +│ /api/bi/* │ │ /api/bi-engine │ │ /superset/* │ +│ (sem mudança)│ │ :8004 (igual) │ │ :8088 │ +│ │ │ │ │ │ +│ + novo: │ │ │ │ REST API v1 │ +│ /api/superset│ │ │ │ Guest Token JWT │ +│ /guest-token │ │ │ │ SQL Lab │ +│ │ │ │ │ 50+ chart types │ +└──────────────┘ └────────────────┘ └──────────┬───────────┘ + │ + ▼ + ┌──────────────────────┐ + │ PostgreSQL │ + │ arcadia (dados SOE) │ + │ arcadia_superset │ + │ (metadados Superset) │ + └──────────────────────┘ +``` + +### 3.2 Dois bancos PostgreSQL + +``` +Banco: arcadia → Dados do SOE (persons, products, sales_orders, etc.) + Superset conecta aqui em READ-ONLY para criar charts +Banco: arcadia_superset → Metadados do Superset (dashboards, queries, users) + Superset usa internamente +``` + +Ambos no mesmo servidor PostgreSQL, bancos separados. O docker-compose.yml já referencia `arcadia_superset`. + +--- + +## 4. O QUE CONSTRUIR — Passo a Passo + +### 4.1 Configuração do Superset (docker-compose.yml) + +O container já existe. Faltam: init script, volumes, configuração de embedding. + +```yaml +# docker-compose.yml — seção superset (expandida) + +superset: + image: apache/superset:4.1.0 + restart: unless-stopped + environment: + SUPERSET_SECRET_KEY: ${SUPERSET_SECRET_KEY:-superset-secret-change-in-prod} + DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD:-arcadia123}@db:5432/arcadia_superset + SUPERSET_WEBSERVER_PORT: 8088 + PYTHONPATH: /app/pythonpath + # Para embedding funcionar: + FEATURE_FLAGS: '{"EMBEDDED_SUPERSET": true, "ENABLE_TEMPLATE_PROCESSING": true}' + ports: + - "8088:8088" + volumes: + - ./docker/superset/superset_config.py:/app/pythonpath/superset_config.py + - ./docker/superset/init.sh:/app/docker/init.sh + - superset_home:/app/superset_home + depends_on: + db: + condition: service_healthy + command: ["/bin/bash", "/app/docker/init.sh"] + profiles: [bi] + networks: + - arcadia +``` + +### 4.2 Arquivo de Configuração Superset + +```python +# docker/superset/superset_config.py + +import os + +# Chave secreta (mesma do .env) +SECRET_KEY = os.environ.get("SUPERSET_SECRET_KEY", "change-in-production") + +# Banco de metadados do Superset +SQLALCHEMY_DATABASE_URI = os.environ.get( + "DATABASE_URL", + "postgresql://arcadia:arcadia123@db:5432/arcadia_superset" +) + +# CORS — permite o gateway Arcádia (:5000) chamar a API +ENABLE_CORS = True +CORS_OPTIONS = { + "supports_credentials": True, + "allow_headers": ["*"], + "resources": {r"/api/*": {"origins": "*"}}, +} + +# Embedding habilitado +FEATURE_FLAGS = { + "EMBEDDED_SUPERSET": True, + "ENABLE_TEMPLATE_PROCESSING": True, + "ALERT_REPORTS": True, # Alertas automáticos + "DRILL_TO_DETAIL": True, # Drill-down em charts +} + +# Timeout de queries (30s por default, aumentar para análises pesadas) +SUPERSET_WEBSERVER_TIMEOUT = 300 + +# Cache (Redis se disponível, senão in-memory) +CACHE_CONFIG = { + "CACHE_TYPE": "SimpleCache", + "CACHE_DEFAULT_TIMEOUT": 300, # 5 min +} + +# Tema/branding Arcádia (logo, cores) +APP_NAME = "Arcádia Insights" +APP_ICON = "/static/arcadia-logo.png" +``` + +### 4.3 Init Script do Superset + +```bash +#!/bin/bash +# docker/superset/init.sh — roda ao iniciar o container + +set -e + +echo "[Superset Init] Iniciando configuração..." + +# Aguarda PostgreSQL +until psql "${DATABASE_URL}" -c "SELECT 1" > /dev/null 2>&1; do + echo "[Superset Init] Aguardando PostgreSQL..." + sleep 2 +done + +# Cria banco arcadia_superset se não existir +psql "postgresql://${PGUSER:-arcadia}:${PGPASSWORD:-arcadia123}@db:5432/postgres" \ + -c "CREATE DATABASE arcadia_superset OWNER arcadia;" 2>/dev/null || true + +# Inicializa banco do Superset +superset db upgrade + +# Cria usuário admin (só se não existir) +superset fab create-admin \ + --username "${SUPERSET_ADMIN_USER:-admin}" \ + --firstname "Arcádia" \ + --lastname "Admin" \ + --email "${SUPERSET_ADMIN_EMAIL:-admin@arcadia.app}" \ + --password "${SUPERSET_ADMIN_PASSWORD:-arcadia2026}" 2>/dev/null || true + +# Carrega exemplos (opcional, comentar em prod) +# superset load_examples + +# Inicializa roles e permissões +superset init + +# Registra conexão com o banco Arcádia (dados do SOE) +python - <<'PYEOF' +from superset import create_app +from superset.extensions import db +from superset.models.core import Database +import os + +app = create_app() +with app.app_context(): + existing = db.session.query(Database).filter_by( + database_name="Arcádia Suite" + ).first() + if not existing: + arcadia_db = Database( + database_name="Arcádia Suite", + sqlalchemy_uri=os.environ.get( + "ARCADIA_DATABASE_URL", + "postgresql://arcadia:arcadia123@db:5432/arcadia" + ), + expose_in_sqllab=True, + allow_run_async=True, + allow_csv_upload=False, + ) + db.session.add(arcadia_db) + db.session.commit() + print("[Superset Init] Banco 'Arcádia Suite' registrado!") + else: + print("[Superset Init] Banco 'Arcádia Suite' já existe.") +PYEOF + +echo "[Superset Init] Iniciando servidor..." +gunicorn \ + --bind "0.0.0.0:${SUPERSET_WEBSERVER_PORT:-8088}" \ + --access-logfile "-" \ + --error-logfile "-" \ + --workers 4 \ + --timeout 120 \ + --limit-request-line 0 \ + --limit-request-field_size 0 \ + "superset.app:create_app()" +``` + +### 4.4 Proxy Superset (substitui server/metabase/proxy.ts) + +```typescript +// server/superset/proxy.ts + +import { Express, Response } from "express"; +import { createProxyMiddleware } from "http-proxy-middleware"; + +const SUPERSET_HOST = process.env.SUPERSET_HOST || "localhost"; +const SUPERSET_PORT = parseInt(process.env.SUPERSET_PORT || "8088", 10); +const SUPERSET_TIMEOUT = 60000; + +export function setupSupersetProxy(app: Express): void { + const target = `http://${SUPERSET_HOST}:${SUPERSET_PORT}`; + + const supersetProxy = createProxyMiddleware({ + target, + changeOrigin: true, + timeout: SUPERSET_TIMEOUT, + proxyTimeout: SUPERSET_TIMEOUT, + pathRewrite: { "^/superset": "" }, + on: { + error: (err, _req, res) => { + console.error("[Superset Proxy] Error:", err.message); + if (res && typeof (res as Response).status === "function") { + (res as Response).status(502).json({ + error: "Superset indisponível", + message: "O Superset está iniciando. Tente novamente em alguns segundos.", + target, + }); + } + }, + proxyRes: (proxyRes) => { + const location = proxyRes.headers["location"]; + if (location && typeof location === "string" && location.startsWith("/")) { + proxyRes.headers["location"] = `/superset${location}`; + } + }, + }, + }); + + app.use("/superset", supersetProxy); + console.log(`[Superset Proxy] Configurado -> /superset/* => ${target}`); +} +``` + +### 4.5 Rotas Superset — Guest Token para Embedding + +Esta é a peça-chave para "funcionar em qualquer tela": + +```typescript +// server/superset/routes.ts + +import type { Express, Request, Response } from "express"; + +const SUPERSET_HOST = process.env.SUPERSET_HOST || "localhost"; +const SUPERSET_PORT = parseInt(process.env.SUPERSET_PORT || "8088", 10); +const SUPERSET_URL = `http://${SUPERSET_HOST}:${SUPERSET_PORT}`; +const SUPERSET_ADMIN_USER = process.env.SUPERSET_ADMIN_USER || "admin"; +const SUPERSET_ADMIN_PASS = process.env.SUPERSET_ADMIN_PASSWORD || "arcadia2026"; + +// Cache do token de serviço (expira em 50 min) +let serviceToken: string | null = null; +let serviceTokenExpiry = 0; + +async function getServiceToken(): Promise { + if (serviceToken && Date.now() < serviceTokenExpiry) return serviceToken; + + const resp = await fetch(`${SUPERSET_URL}/api/v1/security/login`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + username: SUPERSET_ADMIN_USER, + password: SUPERSET_ADMIN_PASS, + provider: "db", + refresh: true, + }), + }); + + if (!resp.ok) throw new Error("Falha ao autenticar no Superset"); + const data = await resp.json(); + serviceToken = data.access_token; + serviceTokenExpiry = Date.now() + 50 * 60 * 1000; // 50 min + return serviceToken!; +} + +export function registerSupersetRoutes(app: Express): void { + + // Guest Token — para embedding em qualquer tela + // O frontend chama este endpoint para obter um token temporário + // e renderiza o dashboard via @superset-ui/embedded-sdk + app.post("/api/superset/guest-token", async (req: Request, res: Response) => { + try { + if (!req.isAuthenticated()) return res.status(401).json({ error: "Not authenticated" }); + + const { dashboardId } = req.body; + if (!dashboardId) return res.status(400).json({ error: "dashboardId obrigatório" }); + + const token = await getServiceToken(); + + // Solicita guest token ao Superset + const guestResp = await fetch(`${SUPERSET_URL}/api/v1/security/guest_token/`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${token}`, + }, + body: JSON.stringify({ + user: { + username: `arcadia_${req.user?.id}`, + first_name: req.user?.name?.split(" ")[0] || "User", + last_name: req.user?.name?.split(" ")[1] || "", + }, + resources: [{ type: "dashboard", id: dashboardId }], + rls: [], // Row Level Security (futuro: por tenantId) + }), + }); + + if (!guestResp.ok) { + const err = await guestResp.text(); + return res.status(502).json({ error: "Falha ao gerar guest token", detail: err }); + } + + const { token: guestToken } = await guestResp.json(); + res.json({ token: guestToken, supersetUrl: "/superset" }); + } catch (err: any) { + res.status(502).json({ error: err.message }); + } + }); + + // Lista dashboards disponíveis (para o seletor na UI) + app.get("/api/superset/dashboards", async (req: Request, res: Response) => { + try { + if (!req.isAuthenticated()) return res.status(401).json({ error: "Not authenticated" }); + + const token = await getServiceToken(); + const resp = await fetch(`${SUPERSET_URL}/api/v1/dashboard/?q=(order_column:changed_on_delta_humanized,order_direction:desc)`, { + headers: { "Authorization": `Bearer ${token}` }, + }); + + if (!resp.ok) return res.status(502).json({ error: "Superset indisponível" }); + const data = await resp.json(); + res.json(data.result || []); + } catch (err: any) { + res.status(502).json({ error: err.message }); + } + }); + + // Health check + app.get("/api/superset/health", async (_req: Request, res: Response) => { + try { + const resp = await fetch(`${SUPERSET_URL}/health`); + res.json({ online: resp.ok, url: SUPERSET_URL }); + } catch { + res.json({ online: false, url: SUPERSET_URL }); + } + }); +} +``` + +### 4.6 Componente React — SupersetDashboard (reutilizável em QUALQUER tela) + +```typescript +// client/src/components/SupersetDashboard.tsx + +import { useEffect, useRef, useState } from "react"; +import { embedDashboard } from "@superset-ui/embedded-sdk"; + +interface SupersetDashboardProps { + dashboardId: string; + height?: string | number; + className?: string; +} + +export function SupersetDashboard({ + dashboardId, + height = "calc(100vh - 300px)", + className = "", +}: SupersetDashboardProps) { + const containerRef = useRef(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + if (!containerRef.current) return; + + let mounted = true; + setLoading(true); + setError(null); + + embedDashboard({ + id: dashboardId, + supersetDomain: window.location.origin + "/superset", + mountPoint: containerRef.current, + + // Busca guest token do gateway Arcádia + fetchGuestToken: async () => { + const resp = await fetch("/api/superset/guest-token", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ dashboardId }), + credentials: "include", + }); + if (!resp.ok) throw new Error("Falha ao obter token"); + const { token } = await resp.json(); + return token; + }, + + dashboardUiConfig: { + hideTitle: true, // Título próprio no Arcádia + hideChartControls: false, // Manter controles de chart + filters: { + visible: true, // Mostrar filtros + expanded: false, + }, + }, + }).then(() => { + if (mounted) setLoading(false); + }).catch((err) => { + if (mounted) { + setError(err.message); + setLoading(false); + } + }); + + return () => { mounted = false; }; + }, [dashboardId]); + + if (error) { + return ( + + Superset indisponível: {error} + + ); + } + + return ( + + {loading && ( + + + + Carregando Arcádia Insights... + + + )} + + + ); +} +``` + +**Uso em QUALQUER página:** +```tsx +// Exemplo: na página /financeiro +import { SupersetDashboard } from "@/components/SupersetDashboard"; + +// Dashboard financeiro embeddado diretamente no módulo Financeiro + + +// Exemplo: na página /contabil + + +// Exemplo: no Dashboard principal (/) + +``` + +### 4.7 BiWorkspace.tsx — Advanced tab (única mudança na UI) + +```tsx +// Substituir a tab Advanced (linhas 2918-2945) + + + + + + Arcádia Insights — Apache Superset + + SQL Lab avançado, 50+ tipos de gráfico, dashboards interativos + + + + Abrir em Nova Aba + + + + {/* Dashboard selecionável */} + + + +``` + +--- + +## 5. TABELAS E VARIÁVEIS + +### 5.1 Nenhuma tabela nova no schema Arcádia + +O Superset usa seu próprio banco (`arcadia_superset`) para metadados internos. As tabelas do Arcádia não mudam. + +### 5.2 Novas variáveis de ambiente + +```bash +# .env — adicionar/substituir: + +# Superset (substitui METABASE_*) +SUPERSET_HOST=superset # nome do container Docker +SUPERSET_PORT=8088 +SUPERSET_SECRET_KEY= # gerar: openssl rand -hex 32 +SUPERSET_ADMIN_USER=admin +SUPERSET_ADMIN_EMAIL=admin@arcadia.app +SUPERSET_ADMIN_PASSWORD= # senha forte em prod + +# URL do banco Arcádia para o Superset acessar (read-only ideal) +ARCADIA_DATABASE_URL=postgresql://arcadia_ro:pass@db:5432/arcadia + +# Remover (não são mais necessários): +# METABASE_HOST +# METABASE_PORT +# METASET_ADMIN_EMAIL +# METASET_ADMIN_PASSWORD +``` + +--- + +## 6. ROADMAP — Fases de Implementação + +### Fase 1 — Infraestrutura (2-3 dias) +``` +[ ] Criar docker/superset/superset_config.py +[ ] Criar docker/superset/init.sh +[ ] Atualizar docker-compose.yml (expandir seção superset existente) +[ ] Adicionar volumes: superset_home no docker-compose +[ ] Testar: docker compose --profile bi up superset +[ ] Verificar: banco arcadia_superset criado, admin funciona, :8088 acessível +``` + +### Fase 2 — Gateway (1-2 dias) +``` +[ ] Criar server/superset/proxy.ts (substitui server/metabase/proxy.ts) +[ ] Criar server/superset/routes.ts (guest token, lista dashboards, health) +[ ] Registrar no server/routes.ts: setupSupersetProxy() + registerSupersetRoutes() +[ ] Remover/comentar setupMetabaseProxy() e registerMetaSetRoutes() +[ ] Testar: GET /api/superset/health → { online: true } +[ ] Testar: POST /api/superset/guest-token → token JWT +``` + +### Fase 3 — Frontend (2-3 dias) +``` +[ ] npm install @superset-ui/embedded-sdk +[ ] Criar client/src/components/SupersetDashboard.tsx +[ ] Atualizar BiWorkspace.tsx Advanced tab (substituir iframe MetaSet) +[ ] Testar: dashboard embeddado na Advanced tab +[ ] Criar 3 dashboards base no Superset: + - executive-summary (KPIs gerais) + - financial-overview (Financeiro) + - dre-mensal (DRE) +``` + +### Fase 4 — Embedding em outras telas (1 semana) +``` +[ ] Embedar SupersetDashboard no /financeiro (tab Análise) +[ ] Embedar SupersetDashboard no /contabil (tab DRE/Balanço) +[ ] Embedar SupersetDashboard no SOE (tab Dashboard) +[ ] Embedar SupersetDashboard no Home / Dashboard principal +[ ] RLS por tenantId (Row Level Security nos dashboards) +``` + +### Fase 5 — Migração de dashboards (conforme necessário) +``` +[ ] Recriar no Superset os dashboards que existiam no MetaSet (se houver) +[ ] Configurar alertas automáticos (Superset Alerts & Reports) +[ ] Criar dashboards para cada domínio do SOE: + - Vendas, Compras, Fiscal, Pessoas, Estoque +``` + +--- + +## 7. DIAGRAMA BI ATUALIZADO (completo) + +``` +┌────────────────────────────────────────────────────────────────────┐ +│ ARCÁDIA BI STACK v2 │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ FRONTEND REACT — Pode usar em QUALQUER rota │ │ +│ │ │ │ +│ │ BiWorkspace.tsx → 8 tabs (7 iguais + Advanced=Superset) │ │ +│ │ → componente reutilizável │ │ +│ │ Guest Token API → /api/superset/guest-token │ │ +│ └────────────────────────────┬─────────────────────────────────┘ │ +│ │ │ +│ ┌─────────────────────┼──────────────────────┐ │ +│ │ │ │ │ +│ ┌──────▼──────┐ ┌────────▼───────┐ ┌─────────▼──────────┐ │ +│ │ API BI │ │ BI Engine │ │ Apache Superset │ │ +│ │ (Node.js) │ │ Python:8004 │ │ Python:8088 │ │ +│ │ sem mudança│ │ sem mudança │ │ │ │ +│ │ │ │ │ │ SQL Lab │ │ +│ │ CRUD │ │ SQL+Charts │ │ 50+ chart types │ │ +│ │ Upload/ETL │ │ Micro-BI │ │ Guest Token (embed) │ │ +│ │ Staging │ │ Análise Pandas │ │ Alerts & Reports │ │ +│ │ Backups │ │ Cache 5min │ │ REST API v1 │ │ +│ └─────┬───────┘ └────────┬───────┘ └─────────┬───────────┘ │ +│ │ │ │ │ +│ └──────────────────────┼─────────────────────┘ │ +│ │ │ +│ ┌──────────▼──────────┐ │ +│ │ PostgreSQL │ │ +│ │ │ │ +│ │ arcadia │ ← Dados SOE (read-only) │ +│ │ arcadia_superset │ ← Metadados Superset │ +│ └────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ CIENTISTA (Python) — IA/ML: análise, padrões, insights │ │ +│ │ ASSISTENTE BI (GPT) — chat sobre dados │ │ +│ │ (ambos sem mudança) │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +└────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 8. RESUMO — O que muda, o que fica + +| Componente | Ação | Esforço | +|---|---|---| +| `server/metabase/proxy.ts` | Substituir por `server/superset/proxy.ts` | 30 min | +| `server/metaset/routes.ts` | Substituir por `server/superset/routes.ts` | 2h | +| `server/metaset/client.ts` | Remover (lógica vai para routes.ts) | 5 min | +| `docker-compose.yml` Superset | Expandir configuração existente | 1h | +| `docker/superset/superset_config.py` | Criar (novo arquivo) | 30 min | +| `docker/superset/init.sh` | Criar (novo arquivo) | 1h | +| `BiWorkspace.tsx` Advanced tab | Substituir iframe MetaSet | 1h | +| `SupersetDashboard.tsx` | Criar componente (novo) | 2h | +| `npm install @superset-ui/embedded-sdk` | Instalar dependência | 5 min | +| BI Engine Python (:8004) | **Não muda nada** | — | +| API BI Node /api/bi/* | **Não muda nada** | — | +| Upload/ETL/Staging | **Não muda nada** | — | +| 7 tabs do BiWorkspace | **Não muda nada** | — | +| Tabelas do banco | **Não muda nada** | — | + +**Total estimado: 1-2 dias de implementação real** (a infra já está 80% pronta). + +--- + +## 9. VANTAGEM ESTRATÉGICA + +> O Apache Superset não é apenas "trocar Metabase". +> +> É a virada de chave que permite que o BI deixe de ser uma página separada +> e vire um **componente vivo** que aparece **dentro de cada módulo do Arcádia**: +> +> - O usuário está no módulo Financeiro → vê o dashboard financeiro ali mesmo +> - O usuário está no módulo Contábil → vê o DRE ali mesmo +> - O usuário está no SOE → vê os KPIs do negócio ali mesmo +> +> Sem abrir nova aba. Sem sair do contexto. Sem re-autenticar. +> O Superset renderiza no lugar exato onde o usuário está. + +--- + +*PLANO_BI_SUPERSET.md — Arcádia Suite v3.0* +*Gerado em: 2026-03-16 — Baseado na análise do MAPA_BI_ARCADIA.md (Replit) + código real*
Carregando Arcádia Insights...
+ SQL Lab avançado, 50+ tipos de gráfico, dashboards interativos +