arcadiasuite/docs/PLANO_METASET.md

618 lines
26 KiB
Markdown

Plano de Implementação: MetaSet no ArcadiaSuite (Atualizado - 07/04/2026)
📊 Visão Geral da Arquitetura Atual
┌─────────────────────────────────────────────────────────────────────────┐
│ ARCADIA KERNEL (5001) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Dashboard │ │ Process │ │ Health │ │ LogAggregator │ │
│ │ (Web UI) │ │ Manager │ │ Monitor │ │ │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └─────────────────┘ │
│ │ │ │ │
│ └────────────────┴────────────────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ │ Service Registry │ │
│ │ (services.json) │ │
│ └───────────┬───────────┘ │
│ │ │
│ ┌─────────────────────┼─────────────────────┐ │
│ │ │ │ │
│ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ │
│ │9001 │ │9002 │ │9003 │ + NOVO: 8004 │
│ │Comm │ │Core │ │Worker│ + NOVO: 8100 │
│ │Whats│ │ API │ │Queue │ (MetaSet) │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ 🆕 SERVIÇOS BI: │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 8004 │ │ 8100 │ │ 8200 │ │
│ │ BI-API │──│ MetaSet │ │ FDB-Bridge │ │
│ │ (Node.js) │ │ (Python) │ │ (Python) │ │
│ │ Gateway │ │ Superset │ │ Firebird │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
┌──────────┴──────────┐
│ PostgreSQL 16 │
│ ┌───────────────┐ │
│ │ arcadia_db │ │
│ │ metaset_db │ │ ✅ Schema criado e migrado
│ └───────────────┘ │
└─────────────────────┘
🔧 Configuração dos Serviços (services.json)
{
"services": [
{
"id": "communication",
"name": "Communication Service",
"type": "node",
"command": "node",
"args": ["server/communication/index.js"],
"cwd": ".",
"port": 9001,
"autoStart": true,
"healthCheck": {
"path": "/health",
"interval": 30000,
"timeout": 5000,
"retries": 3
},
"maxRestarts": 5
},
{
"id": "core-api",
"name": "Core API",
"type": "node",
"command": "node",
"args": ["server/core/index.js"],
"cwd": ".",
"port": 9002,
"autoStart": true,
"healthCheck": {
"path": "/health",
"interval": 30000,
"timeout": 5000,
"retries": 3
},
"maxRestarts": 5
},
{
"id": "bi-api",
"name": "BI API Gateway",
"type": "node",
"command": "node",
"args": ["server/bi/index.js"],
"cwd": ".",
"port": 8004,
"autoStart": true,
"env": {
"METASET_PORT": "8100",
"METASET_HOST": "127.0.0.1",
"FDB_BRIDGE_PORT": "8200"
},
"healthCheck": {
"path": "/bi/health",
"interval": 30000,
"timeout": 5000,
"retries": 3
},
"maxRestarts": 5,
"description": "Gateway de BI com proxy para MetaSet e FDB-Bridge"
},
{
"id": "metaset",
"name": "MetaSet BI",
"type": "python",
"command": "python",
"args": ["server/bi/metaset/run.py", "--port=8100", "--host=127.0.0.1"],
"cwd": ".",
"port": 8100,
"autoStart": false,
"env": {
"PYTHONPATH": "server/bi/metaset",
"FLASK_ENV": "production",
"SUPERSET_CONFIG_PATH": "server/bi/metaset/superset_config.py",
"SUPERSET_SECRET_KEY": "${SUPERSET_SECRET_KEY}"
},
"healthCheck": {
"path": "/health",
"interval": 30000,
"timeout": 10000,
"retries": 3
},
"maxRestarts": 3,
"description": "Apache Superset rebrandado como MetaSet (Docker-managed)"
},
{
"id": "fdb-bridge",
"name": "FDB Bridge",
"type": "python",
"command": "python",
"args": ["server/bi/fdb-bridge/main.py", "--port=8200"],
"cwd": ".",
"port": 8200,
"autoStart": false,
"env": {
"PYTHONPATH": "server/bi/fdb-bridge",
"FDB_HOST": "${FDB_HOST}",
"FDB_PORT": "${FDB_PORT:-3050}"
},
"healthCheck": {
"path": "/health",
"interval": 60000,
"timeout": 5000,
"retries": 3
},
"maxRestarts": 3,
"description": "Conector Firebird para sincronização de dados (Docker-managed)"
}
]
}
🏗️ Estrutura de Diretórios Final
arcadiasuite/
├── server/
│ ├── kernel/ # ✅ Kernel finalizado
│ │ ├── core/
│ │ │ ├── ProcessManager.ts # ✅ Suporta 'python' e 'node'
│ │ │ ├── HealthMonitor.ts
│ │ │ └── LogAggregator.ts
│ │ ├── dashboard/ # Dashboard Web UI (porta 5001)
│ │ ├── config/
│ │ │ └── services.json # ✅ Configuração dos serviços
│ │ └── index.ts
│ │
│ ├── bi/ # 🆕 MÓDULO BI COMPLETO
│ │ ├── index.ts # BI-API Gateway (porta 8004)
│ │ ├── routes/
│ │ │ ├── query.ts # Queries nativas Drizzle
│ │ │ ├── export.ts # Exportação PDF/Word
│ │ │ └── sync.ts # Sincronização FDB
│ │ │
│ │ ├── metaset/ # 🆕 METASET (Superset)
│ │ │ ├── run.py # Entry point Python
│ │ │ ├── superset_config.py # Configuração Arcadia
│ │ │ ├── security_manager.py # ArcadiaSecurityManager
│ │ │ ├── requirements.txt # Dependências Python
│ │ │ ├── Dockerfile # Multi-stage build
│ │ │ ├── init.sh # Container init script
│ │ │ ├── branding/ # 🎨 Assets MetaSet
│ │ │ │ ├── metaset-logo-horiz.png
│ │ │ │ ├── metaset-icon.png
│ │ │ │ ├── favicon-16x16.png
│ │ │ │ └── favicon-32x32.png
│ │ │ │
│ │ │ └── superset-src/ # Fork Apache Superset 4.1.0
│ │ │ ├── superset-frontend/ # ✅ Rebuild com branding MetaSet
│ │ │ │ └── src/
│ │ │ │ ├── features/home/RightMenu.tsx # ✅ Textos atualizados
│ │ │ │ ├── components/ErrorMessage/OAuth2RedirectMessage.tsx
│ │ │ │ └── pages/... # ✅ Traduções atualizadas
│ │ │ │
│ │ │ ├── superset/
│ │ │ │ ├── config.py # ✅ APP_NAME = "MetaSet"
│ │ │ │ ├── constants.py # ✅ USER_AGENT = "MetaSet"
│ │ │ │ ├── cli/
│ │ │ │ ├── templates/ # ✅ HTML templates atualizados
│ │ │ │ └── translations/ # ✅ Traduções en/pt_BR
│ │ │ └── ...
│ │ │
│ │ └── fdb-bridge/ # 🆕 FIREBIRD CONNECTOR (skeleton)
│ │ ├── main.py # Serviço Python porta 8200
│ │ ├── sync.py # Lógica de sincronização
│ │ ├── models.py # Modelos SQLAlchemy
│ │ └── requirements.txt
│ │
│ └── ... (outros serviços)
├── client/
│ └── src/
│ └── pages/
│ └── bi/ # 🆕 FRONTEND BI
│ ├── index.tsx # Dashboard BI Arcadia
│ ├── metaset/ # Embed MetaSet
│ │ ├── Dashboard.tsx
│ │ ├── SQLLab.tsx
│ │ └── Explore.tsx
│ └── components/
│ ├── QueryBuilder.tsx
│ ├── ExportButton.tsx
│ └── FDBSyncStatus.tsx
└── branding/ # 🆕 ASSETS COMPARTILHADOS
├── logos/
│ ├── arcadia-suite-logo.svg
│ ├── arcadia-suite-logo-horiz.svg
│ ├── metaset-logo.svg
│ └── metaset-icon.svg
├── colors/
│ └── arcadia-palette.json
└── fonts/
└── Inter-Variable.ttf
🔐 Arquitetura de Segurança & Multi-tenancy
Fluxo de Autenticação
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Cliente │────▶│ Arcadia │────▶│ BI-API │────▶│ MetaSet │
│ (React) │ │ Login │ │ (8004) │ │ (8100) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │
│ Headers: │ SET LOCAL
│ X-Tenant-ID: 123 │ app.current_tenant
│ X-User-Role: admin │ = 123;
│ Authorization: JWT │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ RLS Check │ │ PostgreSQL │
│ Middleware │ │ (RLS) │
└─────────────┘ └─────────────┘
ArcadiaSecurityManager (server/bi/metaset/security_manager.py) ✅ CORRIGIDO
"""
Security Manager integrado ao Arcadia Kernel
- Extrai tenant e usuário do token JWT
- Aplica RLS automaticamente
- Sincroniza roles com ArcadiaSuite
- Preserva comportamento padrão do Superset (chama super().before_request())
"""
from superset.security import SupersetSecurityManager
from flask import g, request, current_app
from sqlalchemy import text
import jwt
import logging
logger = logging.getLogger(__name__)
class ArcadiaSecurityManager(SupersetSecurityManager):
ROLE_MAPPING = {
'superadmin': 'Admin',
'admin': 'Alpha',
'analyst': 'Gamma',
'viewer': 'Public',
}
def before_request(self):
"""Executado antes de cada requisição - preserva comportamento padrão"""
super().before_request() # ← CRÍTICO: preserva autenticação padrão
auth_header = request.headers.get('Authorization', '')
if not auth_header.startswith('Bearer '):
return
token = auth_header.replace('Bearer ', '')
try:
payload = jwt.decode(
token,
current_app.config.get('SECRET_KEY', 'default-key'),
algorithms=['HS256']
)
g.tenant_id = payload.get('tenant_id')
g.user_id = payload.get('sub')
g.user_role = payload.get('role', 'viewer')
g.user_email = payload.get('email')
if g.tenant_id:
try:
from superset import db
db.session.execute(
text(f"SET LOCAL app.current_tenant = {g.tenant_id}")
)
except Exception as e:
logger.warning(f"Erro ao aplicar RLS: {e}")
except jwt.ExpiredSignatureError:
logger.warning("JWT token expirado")
except jwt.InvalidTokenError:
logger.warning("JWT token inválido")
except Exception as e:
logger.warning(f"Erro ao processar JWT: {e}")
🐍 Código dos Serviços Python
1. MetaSet Entry Point (server/bi/metaset/run.py)
"""
MetaSet - Serviço Apache Superset integrado ao Arcadia Kernel
Porta: 8100 (Docker container)
Gunicorn: 2 workers, gthread, 120s timeout
"""
import os
import sys
import logging
from pathlib import Path
logging.basicConfig(
level=logging.INFO,
format='[MetaSet] %(levelname)s: %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger(__name__)
def create_app():
"""Criar aplicação Flask do Superset com endpoints customizados"""
from superset import create_app as create_superset_app
from datetime import datetime
app = create_superset_app()
@app.route('/health')
def health_check():
return {'status': 'healthy', 'service': 'metaset'}, 200
@app.route('/info')
def service_info():
return {
'name': 'MetaSet',
'description': 'Business Intelligence by ArcadiaSuite',
'version': app.config.get('VERSION_STRING', '4.1.0'),
'features': ['sql_lab', 'dashboards', 'charts', 'rls', 'embedding']
}
return app
# MetaSetApplication: custom Gunicorn app
# Config: 2 workers, gthread, 120s timeout, stdout/stderr logging
2. BI-API Gateway (server/bi/index.ts)
"""
* BI-API Gateway
* Porta: 8004
* Integra MetaSet (8100) e FDB-Bridge (8200) ao ArcadiaSuite
* Proxy manual usando módulo http nativo (bypass http-proxy-middleware ECONNRESET)
"""
import express from 'express';
import http from 'http';
const METASET_URL = `http://${process.env.METASET_HOST || 'metaset'}:${process.env.METASET_PORT || '8100'}`;
// Manual proxy: http.request() com pathRewrite
// Solução para ECONNRESET com Gunicorn keepalive
// Health check agrega MetaSet + FDB-Bridge status
🎨 Configuração de Branding (superset_config.py)
"""
Configuração do MetaSet (Superset) para ArcadiaSuite
"""
import os
from pathlib import Path
BASE_DIR = Path(__file__).parent.absolute()
SUPERSET_HOME = BASE_DIR / 'superset_home'
# ==========================================
# BRANDING - ARCADIASUITE ✅ IMPLEMENTADO
# ==========================================
APP_NAME = "MetaSet by Arcádia"
APP_ICON = "/static/assets/images/branding/metaset-logo-horiz.png"
LOGO_TARGET_PATH = "/"
LOGO_TOOLTIP = "MetaSet - Business Intelligence by ArcadiaSuite"
# Favicons
FAVICONS = [
{"href": "/static/assets/images/branding/favicon-16x16.png", "sizes": "16x16"},
{"href": "/static/assets/images/branding/favicon-32x32.png", "sizes": "32x32"},
{"href": "/static/assets/images/branding/apple-touch-icon.png", "sizes": "180x180"},
]
# Cores ArcadiaSuite
ARCADIA_PRIMARY = "#0ea5e9" # Azul celeste
ARCADIA_SECONDARY = "#10b981" # Verde
ARCADIA_ACCENT = "#f59e0b" # Laranja
ARCADIA_BG = "#f8fafc" # Background claro
ARCADIA_TEXT = "#1e293b" # Texto escuro
# Desabilitar cache de arquivos estáticos
SEND_FILE_MAX_AGE_DEFAULT = 0
THEME_DEFAULT = {
"token": {
"brandAppName": "MetaSet",
"brandLogoAlt": "MetaSet by ArcadiaSuite",
"brandLogoUrl": "/static/assets/images/branding/metaset-logo-horiz.png",
"brandLogoMargin": "16px 0",
"brandLogoHeight": "28px",
"colorPrimary": ARCADIA_PRIMARY,
"colorLink": ARCADIA_PRIMARY,
"colorSuccess": ARCADIA_SECONDARY,
"colorWarning": ARCADIA_ACCENT,
"colorError": "#ef4444",
"colorInfo": "#3b82f6",
"colorBgLayout": ARCADIA_BG,
"colorBgContainer": "#ffffff",
"colorText": ARCADIA_TEXT,
"colorTextSecondary": "#64748b",
"fontFamily": "Inter, -apple-system, BlinkMacSystemFont, sans-serif",
"fontSize": 14,
"borderRadius": 8,
"borderRadiusLG": 12,
"boxShadow": "0 1px 3px 0 rgba(0, 0, 0, 0.1)",
"boxShadowSecondary": "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
},
"algorithm": "default",
}
THEME_DARK = { ... } # Tema escuro
# ==========================================
# SEGURANÇA & MULTI-TENANCY
# ==========================================
from security_manager import ArcadiaSecurityManager
CUSTOM_SECURITY_MANAGER = ArcadiaSecurityManager # ✅ Funcionando
AUTH_TYPE = 1
WTF_CSRF_ENABLED = True
WTF_CSRF_TIME_LIMIT = 3600
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = False # True em produção com HTTPS
SESSION_COOKIE_SAMESITE = "Lax"
# ==========================================
# BANCO DE DADOS
# ==========================================
SQLALCHEMY_DATABASE_URI = os.getenv(
'DATABASE_URL',
'postgresql://arcadia:arcadia123@db:5432/metaset_db'
)
SQLALCHEMY_ENGINE_OPTIONS = {
"connect_args": {"options": "-c row_security=on"},
"pool_pre_ping": True,
"pool_recycle": 300,
}
# ==========================================
# FEATURE FLAGS
# ==========================================
FEATURE_FLAGS = {
"EMBEDDED_SUPERSET": True,
"EMBEDDABLE_CHARTS": True,
"DASHBOARD_RBAC": True,
"SQLLAB_BACKEND_PERSISTENCE": True,
"DASHBOARD_VIRTUALIZATION": True,
"DRILL_BY": True,
"CSS_TEMPLATES": True,
"ENABLE_JAVASCRIPT_CONTROLS": False,
"ALERT_REPORTS": False,
}
📋 Roadmap de Implementação (8 Semanas)
Semana Foco Entregáveis
1 Setup MetaSet Fork Superset, branding básico (logo, cores), superset_config.py
2 Integração Kernel services.json atualizado, BI-API gateway, proxy funcionando
3 Segurança ArcadiaSecurityManager, JWT validation, injeção de headers
4 Multi-tenancy RLS PostgreSQL, isolamento de datasources, testes de segurança
5 FDB Bridge Serviço Python porta 8200, conexão Firebird, testes de sync
6 Sync Engine Sincronização incremental, agendamento, resolução de conflitos
7 Frontend Páginas BI no React, embed de dashboards, SQL Lab integrado
8 Go-Live Testes E2E, documentação, otimização de performance
✅ Checklist de Implementação - STATUS ATUAL
Semana 1-2: Setup e Integração ✅ CONCLUÍDO
✅ Clonar superset (4.1.0rc4) para server/bi/metaset/superset-src
✅ Criar superset_config.py com branding ArcadiaSuite (APP_NAME, cores, tema)
✅ Rebuild do frontend React com logos MetaSet (COMPLETO - 07/04/2026)
- Substituição de textos: "Superset" → "MetaSet" em todo codebase
- Traduções atualizadas: en/LC_MESSAGES/messages.po, pt_BR/LC_MESSAGES/messages.po
- Arquivos fonte atualizados: RightMenu.tsx, OAuth2RedirectMessage.tsx,
SliceHeaderControls, HeaderActionsDropdown, AnchorLink, EmbeddedModal,
useExploreAdditionalActionsMenu
- Templates HTML: basic.html, public_welcome.html, 404.html, 500.html
- Config Python: config.py (APP_NAME), constants.py (USER_AGENT), cli/*.py
- Build webpack concluído com sucesso (429 warnings, 0 errors)
- Assets compilados com branding MetaSet incorporado
✅ Criar server/bi/metaset/run.py entry point (Gunicorn)
✅ Criar server/bi/metaset/init.sh container initialization
✅ Criar server/bi/index.ts BI-API gateway (proxy manual Node.js)
✅ Atualizar server/kernel/config/services.json (autoStart: false, Docker Discovery)
✅ Docker Compose: metaset + bi-api + redes configuradas
✅ Dockerfile multi-stage build com assets locais (não mais copiando de apache/superset:latest)
✅ Deploy: https://bi.onboardbi.com.br (MetaSet rodando com branding completo)
✅ Container antigo arcadia-prod-superset-1 removido
✅ Container metaset conectado à rede coolify para Traefik
✅ Banco de dados metaset_db migrado e inicializado
✅ Usuário admin criado (login: admin / senha: admin)
✅ BI-API Gateway proxy /bi/metaset funcionando (porta 8004)
✅ Health checks integrados (metaset + bi-api)
✅ requirements.txt corrigido (compatível apache-superset 4.1.0)
✅ extra_hosts configurado para resolver db → 10.0.10.2 (IPv4)
Semana 3-4: Segurança 🔄 EM ANDAMENTO
✅ Implementar ArcadiaSecurityManager (CORRIGIDO - chama super().before_request())
✅ Configurar JWT validation
🔄 Criar schema metaset no PostgreSQL (banco criado, migrações aplicadas)
☐ Configurar RLS em tabelas do arcadia_db
☐ Testar isolamento entre tenants
Semana 5-6: FDB Bridge ⏳ PENDENTE
☐ Criar server/bi/fdb-bridge/main.py
☐ Implementar conexão Firebird (fdb library)
☐ Criar lógica de sincronização incremental
☐ Configurar agendador APScheduler
☐ Testar sync Matriz + 5 Filiais
Semana 7-8: Frontend e Go-Live ⏳ PENDENTE
☐ Criar páginas BI no frontend React
☐ Implementar embed de dashboards MetaSet
☐ Criar componente de status de sincronização
☐ Testes E2E completos
☐ Documentação do módulo BI
📝 Lições Aprendidas (07/04/2026)
1. Frontend rebuild obrigatório: Substituir arquivos estáticos PNG no Docker
não funciona porque os assets são compilados em bundles JS pelo webpack.
É necessário rebuildar o superset-frontend com npm run build.
2. Dependências faltantes: O build pode falhar por pacotes não instalados:
@react-spring/web, global-box, currencyformatter.js. Instalar com
npm install --legacy-peer-deps.
3. Security Manager: O ArcadiaSecurityManager DEVE chamar super().before_request()
no início do método para preservar o comportamento de autenticação padrão
do Flask-AppBuilder. Sem isso, o login falha com AttributeError: user.
4. IPv6 vs IPv4: O hostname "db" resolve para IPv6 (fd20:a15a:c2d4::c) mas
o psycopg2 falha na autenticação via IPv6. Solução: mapear db → IP IPv4
via extra_hosts no docker-compose.yml.
5. Container antigo: Sempre verificar se há containers antigos com labels
do Traefik apontando para o mesmo domínio. Eles podem conflitar com
o novo container.
6. Traefik discovery: O container DEVE estar na mesma rede Docker que o
Traefik (coolify) para ser descoberto automaticamente.
💰 Custos Adicionais
Componente Especificação Custo Estimado
Memória extra +2GB para Python (MetaSet + FDB-Bridge) ~$20/mês
Storage PostgreSQL +10GB para metadata MetaSet ~$5/mês
CPU Processamento de sync FDB ~$15/mês
Total ~$40/mês
🚀 Comandos de Deploy
# 1. Build da imagem Docker
cd /opt/arcadia_merged
docker compose build --no-cache metaset
# 2. Recriar container com nova imagem
docker compose up -d --force-recreate metaset
# 3. Verificar status
curl http://localhost:8100/health
curl https://bi.onboardbi.com.br/login/ | grep "<title>"
# 4. Logs
docker logs -f arcadia-dev-metaset-1
# 5. Migrar banco (se necessário)
docker exec -e FLASK_APP=superset \
-e DATABASE_URL="postgresql://arcadia:arcadia123@10.0.10.2:5432/metaset_db" \
arcadia-dev-metaset-1 superset db upgrade
# 6. Inicializar
docker exec -e FLASK_APP=superset \
-e DATABASE_URL="postgresql://arcadia:arcadia123@10.0.10.2:5432/metaset_db" \
arcadia-dev-metaset-1 superset init
📌 URLs de Acesso
Serviço URL Status
MetaSet UI https://bi.onboardbi.com.br ✅ Online com branding MetaSet
MetaSet Health http://localhost:8100/health ✅ OK
BI-API Gateway http://localhost:8004 ⚠️ Unhealthy (esperado - requer JWT)
Traefik Dashboard http://localhost:8080 ✅ Online
🔧 Próximos Passos Prioritários
1. Configurar RLS (Row Level Security) no PostgreSQL para isolamento de tenants
2. Testar fluxo completo de autenticação com token JWT do Arcadia
3. Criar datasource de exemplo conectado ao arcadia_db
4. Implementar FDB Bridge (conector Firebird)
5. Criar páginas BI no frontend React
6. Configurar cache Redis para MetaSet