Merge 132a734832 into e38cbb24d3
This commit is contained in:
commit
0fbbe42449
|
|
@ -0,0 +1,20 @@
|
|||
PGPASSWORD=afefb610090de1646944b537f3054715ad5755665c90036c2bcd258c9ab52dd8
|
||||
SESSION_SECRET=092a26dcbebd6f7f5e7b9e020bdc4d4e966286c9780ef72e3426f437eb8d608b
|
||||
SSO_SECRET=fbb87d1c5a14a6623d4e3dcc2b679bd68c46e59afb48dd6abd42b95cac945856
|
||||
LITELLM_API_KEY=e396b827cbeb5e77d85cce4eb9da0521114f57a8e799f7aa8febad08d776c07e
|
||||
WEBUI_SECRET_KEY=76c7fc044f9e8d6e5eb60b67c82832b67e84739da4827ce1fa7c101ae1a055df
|
||||
DOMAIN=suite.onboardbi.com.br
|
||||
OLLAMA_BASE_URL=http://ollama-ia1upsekrad96at5hq97e4qa:11434
|
||||
|
||||
LLMFIT_BASE_URL=http://llmfit:8000
|
||||
LLMFIT_API_KEY=key-arcadia
|
||||
|
||||
# ── Superset BI ───────────────────────────────────────────────
|
||||
SUPERSET_SECRET_KEY=421274b5ba360778a5398d528116a45ea962d1197e3dfc99f36a372ff1025a63
|
||||
SUPERSET_ADMIN_USERNAME=admin
|
||||
SUPERSET_ADMIN_PASSWORD=arcadia1337
|
||||
SUPERSET_ADMIN_EMAIL=engenharia@ometas.com.br
|
||||
COMPOSE_PROFILES=bi
|
||||
|
||||
SUPERSET_HOST=superset
|
||||
SUPERSET_PORT=8088
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
node_modules/
|
||||
dist/
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
.env.production
|
||||
|
||||
# Replit specific
|
||||
.cache/
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ FROM node:20-alpine AS builder
|
|||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --ignore-scripts
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
|
@ -18,16 +18,19 @@ ENV NODE_ENV=production
|
|||
|
||||
# Deps de produção apenas
|
||||
COPY package*.json ./
|
||||
RUN npm ci --omit=dev --ignore-scripts
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
# Artefatos do build
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/shared ./shared
|
||||
COPY --from=builder /app/migrations ./migrations
|
||||
|
||||
# Arquivos de runtime necessários (caminhos quebrados pelo bundler)
|
||||
RUN cp /app/node_modules/connect-pg-simple/table.sql /app/dist/table.sql
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
CMD wget -qO- http://localhost:5000/api/health || exit 1
|
||||
CMD wget -qO- http://127.0.0.1:5000/ || exit 1
|
||||
|
||||
CMD ["node", "dist/index.cjs"]
|
||||
|
|
|
|||
|
|
@ -2985,6 +2985,7 @@ export default function BiWorkspace() {
|
|||
</TabsContent>
|
||||
<TabsContent value="advanced" className="mt-0">
|
||||
<SupersetAdvancedTab />
|
||||
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// SOE — Sistema de Operações Empresariais (alias para o módulo Plus/ERP)
|
||||
export { default } from "./Plus";
|
||||
// SOE — Sistema de Operações Empresariais
|
||||
export { default } from "./ERP";
|
||||
|
|
|
|||
|
|
@ -86,12 +86,145 @@ services:
|
|||
condition: service_started
|
||||
networks:
|
||||
- arcadia-internal
|
||||
- arcadia-public
|
||||
- coolify
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=coolify"
|
||||
- "traefik.http.routers.arcadia.entrypoints=https"
|
||||
- "traefik.http.routers.arcadia.rule=Host(`${DOMAIN}`)"
|
||||
- "traefik.http.routers.arcadia.tls=true"
|
||||
- "traefik.http.routers.arcadia.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.arcadia.loadbalancer.server.port=5000"
|
||||
|
||||
# ── Arcádia Plus (Laravel + MySQL) ──────────────────────────────────────────
|
||||
# Perfil `plus` — suba com: docker compose --profile plus up
|
||||
plus-db:
|
||||
image: mysql:8.0
|
||||
restart: always
|
||||
profiles: [plus]
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${PLUS_DB_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: ${PLUS_DB_DATABASE:-arcadia_plus}
|
||||
MYSQL_USER: ${PLUS_DB_USER:-plus}
|
||||
MYSQL_PASSWORD: ${PLUS_DB_PASSWORD}
|
||||
volumes:
|
||||
- plus_db:/var/lib/mysql
|
||||
command: --default-authentication-plugin=mysql_native_password
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "--password=${PLUS_DB_ROOT_PASSWORD}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
plus:
|
||||
image: ${PLUS_IMAGE:-php:8.3-apache}
|
||||
restart: always
|
||||
profiles: [plus]
|
||||
environment:
|
||||
APP_ENV: production
|
||||
APP_KEY: ${PLUS_APP_KEY}
|
||||
APP_URL: https://${DOMAIN}/plus
|
||||
DB_HOST: plus-db
|
||||
DB_DATABASE: ${PLUS_DB_DATABASE:-arcadia_plus}
|
||||
DB_USERNAME: ${PLUS_DB_USER:-plus}
|
||||
DB_PASSWORD: ${PLUS_DB_PASSWORD}
|
||||
SESSION_DRIVER: redis
|
||||
REDIS_HOST: redis
|
||||
ARCADIA_URL: https://${DOMAIN}
|
||||
ARCADIA_SSO_SECRET: ${SSO_SECRET}
|
||||
volumes:
|
||||
- plus_storage:/var/www/html/storage
|
||||
depends_on:
|
||||
plus-db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
# ── Apache Superset (BI) ─────────────────────────────────────────────────────
|
||||
# Perfil `bi` — suba com: docker compose --profile bi up
|
||||
superset:
|
||||
image: apache/superset:4.1.0
|
||||
restart: always
|
||||
profiles: [bi]
|
||||
environment:
|
||||
SUPERSET_SECRET_KEY: ${SUPERSET_SECRET_KEY}
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/arcadia_superset
|
||||
ARCADIA_DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
SUPERSET_ADMIN_USER: ${SUPERSET_ADMIN_USER:-admin}
|
||||
SUPERSET_ADMIN_EMAIL: ${SUPERSET_ADMIN_EMAIL:-admin@arcadia.app}
|
||||
SUPERSET_ADMIN_PASSWORD: ${SUPERSET_ADMIN_PASSWORD}
|
||||
SUPERSET_WEBSERVER_PORT: "8088"
|
||||
PYTHONPATH: /app/pythonpath
|
||||
volumes:
|
||||
- ./docker/superset/superset_config.py:/app/pythonpath/superset_config.py:ro
|
||||
- ./docker/superset/init.sh:/app/docker/init.sh:ro
|
||||
- superset_home:/app/superset_home
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
command: ["/bin/bash", "/app/docker/init.sh"]
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8088/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
# ── ERPNext (Frappe Framework) ───────────────────────────────────────────────
|
||||
# Perfil `erpnext` — suba com: docker compose --profile erpnext up
|
||||
erpnext-db:
|
||||
image: mariadb:10.6
|
||||
restart: always
|
||||
profiles: [erpnext]
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${ERPNEXT_DB_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: _frappe
|
||||
MYSQL_USER: frappe
|
||||
MYSQL_PASSWORD: ${ERPNEXT_DB_PASSWORD}
|
||||
volumes:
|
||||
- erpnext_db:/var/lib/mysql
|
||||
command: >
|
||||
--character-set-server=utf8mb4
|
||||
--collation-server=utf8mb4_unicode_ci
|
||||
--skip-character-set-client-handshake
|
||||
--skip-innodb-read-only-compressed
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "--password=${ERPNEXT_DB_ROOT_PASSWORD}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
erpnext:
|
||||
image: frappe/erpnext:version-15
|
||||
restart: always
|
||||
profiles: [erpnext]
|
||||
environment:
|
||||
FRAPPE_SITE_NAME_HEADER: erpnext.local
|
||||
ERPNEXT_DB_ROOT_PASSWORD: ${ERPNEXT_DB_ROOT_PASSWORD}
|
||||
ERPNEXT_ADMIN_PASSWORD: ${ERPNEXT_ADMIN_PASSWORD}
|
||||
volumes:
|
||||
- erpnext_sites:/home/frappe/frappe-bench/sites
|
||||
- erpnext_logs:/home/frappe/frappe-bench/logs
|
||||
- ./docker/erpnext/init.sh:/usr/local/bin/init-erpnext.sh:ro
|
||||
depends_on:
|
||||
erpnext-db:
|
||||
condition: service_healthy
|
||||
command: ["/bin/bash", "/usr/local/bin/init-erpnext.sh"]
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:8080/api/method/frappe.ping || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
start_period: 120s
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
# ── Arcádia Plus (Laravel + MySQL) ──────────────────────────────────────────
|
||||
# Perfil `plus` — suba com: docker compose --profile plus up
|
||||
|
|
@ -297,6 +430,9 @@ services:
|
|||
SERVICE_NAME: embeddings
|
||||
SERVICE_PORT: 8001
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
LITELLM_BASE_URL: http://litellm:4000
|
||||
LITELLM_API_KEY: ${LITELLM_API_KEY}
|
||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
|
@ -314,12 +450,13 @@ services:
|
|||
environment:
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||
LITELLM_MASTER_KEY: ${LITELLM_API_KEY}
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/litellm
|
||||
# Ollama: se instalado no host use http://host-gateway:11434
|
||||
# Se usar container Docker, mantém http://ollama:11434
|
||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||
# LLMFit: URL do serviço de modelos fine-tuned
|
||||
LLMFIT_BASE_URL: ${LLMFIT_BASE_URL:-}
|
||||
LLMFIT_API_KEY: ${LLMFIT_API_KEY:-}
|
||||
# Providers externos opcionais (soberania: só habilitados se configurados)
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||
GROQ_API_KEY: ${GROQ_API_KEY:-}
|
||||
|
|
@ -328,6 +465,7 @@ services:
|
|||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
- coolify
|
||||
|
||||
# ── Ollama (LLMs locais — soberania total) ────────────────────────────────────
|
||||
# OPÇÃO A (padrão): Ollama como container Docker
|
||||
|
|
@ -359,7 +497,7 @@ services:
|
|||
- litellm
|
||||
networks:
|
||||
- arcadia-internal
|
||||
- arcadia-public
|
||||
- coolify
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.webui.rule=Host(`ai.${DOMAIN}`)"
|
||||
|
|
@ -368,17 +506,55 @@ services:
|
|||
- "traefik.http.services.webui.loadbalancer.server.port=8080"
|
||||
profiles: [ai]
|
||||
|
||||
# ── Superset BI ───────────────────────────────────────────────────────────────
|
||||
superset:
|
||||
build:
|
||||
context: ./docker/superset
|
||||
dockerfile: Dockerfile
|
||||
restart: always
|
||||
environment:
|
||||
SUPERSET_SECRET_KEY: ${SUPERSET_SECRET_KEY}
|
||||
SQLALCHEMY_DATABASE_URI: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/superset
|
||||
PYTHONPATH: /app/pythonpath
|
||||
SUPERSET_ADMIN_USERNAME: ${SUPERSET_ADMIN_USERNAME:-admin}
|
||||
SUPERSET_ADMIN_PASSWORD: ${SUPERSET_ADMIN_PASSWORD}
|
||||
SUPERSET_ADMIN_EMAIL: ${SUPERSET_ADMIN_EMAIL:-admin@onboardbi.com.br}
|
||||
ARCADIA_DATABASE_URL: postgresql+psycopg2://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
command: ["/bin/bash", "/app/docker/init.sh"]
|
||||
volumes:
|
||||
- ./docker/superset/superset_config.py:/app/pythonpath/superset_config.py:ro
|
||||
- ./docker/superset/init.sh:/app/docker/init.sh:ro
|
||||
- superset_home:/app/superset_home
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
- coolify
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=coolify"
|
||||
- "traefik.http.routers.superset.entrypoints=https"
|
||||
- "traefik.http.routers.superset.rule=Host(`${SUPERSET_DOMAIN:-bi.onboardbi.com.br}`)"
|
||||
- "traefik.http.routers.superset.tls=true"
|
||||
- "traefik.http.routers.superset.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.superset.loadbalancer.server.port=8088"
|
||||
profiles: [bi]
|
||||
|
||||
networks:
|
||||
arcadia-internal:
|
||||
driver: bridge
|
||||
arcadia-public:
|
||||
driver: bridge
|
||||
coolify:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
redis_data:
|
||||
ollama_models:
|
||||
open_webui_data:
|
||||
|
||||
|
||||
|
||||
plus_db:
|
||||
plus_storage:
|
||||
superset_home:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,237 @@
|
|||
# ─── Arcádia Suite — Produção (Coolify) ───────────────────────────────────────
|
||||
# Este arquivo é usado pelo Coolify para deploy automático.
|
||||
# NÃO inclui volumes de código-fonte — só artefatos de build.
|
||||
# Configurar no Coolify: Environment Variables para todas as vars ${...}
|
||||
|
||||
name: arcadia-prod
|
||||
|
||||
services:
|
||||
|
||||
# ── Banco de dados com pgvector ─────────────────────────────────────────────
|
||||
db:
|
||||
image: pgvector/pgvector:pg16
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_DB: ${PGDATABASE:-arcadia}
|
||||
POSTGRES_USER: ${PGUSER:-arcadia}
|
||||
POSTGRES_PASSWORD: ${PGPASSWORD}
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
- ./docker/init-pgvector.sql:/docker-entrypoint-initdb.d/01-pgvector.sql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${PGUSER:-arcadia}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
# ── Redis ────────────────────────────────────────────────────────────────────
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: always
|
||||
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
# ── App principal ─────────────────────────────────────────────────────────
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: always
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: 5000
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
REDIS_URL: redis://redis:6379
|
||||
DOCKER_MODE: "true"
|
||||
CONTABIL_PYTHON_URL: http://contabil:8003
|
||||
BI_PYTHON_URL: http://bi:8004
|
||||
AUTOMATION_PYTHON_URL: http://automation:8005
|
||||
FISCO_PYTHON_URL: http://fisco:8002
|
||||
PYTHON_SERVICE_URL: http://embeddings:8001
|
||||
SESSION_SECRET: ${SESSION_SECRET}
|
||||
SSO_SECRET: ${SSO_SECRET}
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||
LITELLM_BASE_URL: http://litellm:4000
|
||||
LITELLM_API_KEY: ${LITELLM_API_KEY}
|
||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||
# ── Manus Agent — aponta para LiteLLM como gateway unificado ──────────
|
||||
# LiteLLM roteia para Ollama (local), LLMFit (fine-tuned) ou externo
|
||||
AI_INTEGRATIONS_OPENAI_BASE_URL: http://litellm:4000/v1
|
||||
AI_INTEGRATIONS_OPENAI_API_KEY: ${LITELLM_API_KEY}
|
||||
ports:
|
||||
- "5000:5000"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_started
|
||||
networks:
|
||||
- arcadia-internal
|
||||
- arcadia-public
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.arcadia.rule=Host(`${DOMAIN}`)"
|
||||
- "traefik.http.routers.arcadia.tls=true"
|
||||
- "traefik.http.routers.arcadia.tls.certresolver=letsencrypt"
|
||||
|
||||
# ── Microserviços Python ─────────────────────────────────────────────────────
|
||||
contabil:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.python
|
||||
restart: always
|
||||
environment:
|
||||
SERVICE_NAME: contabil
|
||||
SERVICE_PORT: 8003
|
||||
CONTABIL_PORT: 8003
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
bi:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.python
|
||||
restart: always
|
||||
environment:
|
||||
SERVICE_NAME: bi
|
||||
SERVICE_PORT: 8004
|
||||
BI_PORT: 8004
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
automation:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.python
|
||||
restart: always
|
||||
environment:
|
||||
SERVICE_NAME: automation
|
||||
SERVICE_PORT: 8005
|
||||
AUTOMATION_PORT: 8005
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
fisco:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.python
|
||||
restart: always
|
||||
environment:
|
||||
SERVICE_NAME: fisco
|
||||
SERVICE_PORT: 8002
|
||||
FISCO_PORT: 8002
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
embeddings:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.python
|
||||
restart: always
|
||||
environment:
|
||||
SERVICE_NAME: embeddings
|
||||
SERVICE_PORT: 8001
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
# ── LiteLLM (gateway unificado de LLM — soberania dos dados) ─────────────────
|
||||
# Roteia: LLMFit (fine-tuned) → Ollama (local) → externo (opt-in)
|
||||
litellm:
|
||||
image: ghcr.io/berriai/litellm:main-latest
|
||||
restart: always
|
||||
volumes:
|
||||
- ./docker/litellm-config.yaml:/app/config.yaml
|
||||
command: ["--config", "/app/config.yaml", "--port", "4000"]
|
||||
environment:
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||
LITELLM_MASTER_KEY: ${LITELLM_API_KEY}
|
||||
DATABASE_URL: postgresql://${PGUSER:-arcadia}:${PGPASSWORD}@db:5432/${PGDATABASE:-arcadia}
|
||||
# Ollama: se instalado no host use http://host-gateway:11434
|
||||
# Se usar container Docker, mantém http://ollama:11434
|
||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||
# LLMFit: URL do serviço de modelos fine-tuned
|
||||
LLMFIT_BASE_URL: ${LLMFIT_BASE_URL:-}
|
||||
# Providers externos opcionais (soberania: só habilitados se configurados)
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||
GROQ_API_KEY: ${GROQ_API_KEY:-}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- arcadia-internal
|
||||
|
||||
# ── Ollama (LLMs locais — soberania total) ────────────────────────────────────
|
||||
# OPÇÃO A (padrão): Ollama como container Docker
|
||||
# OPÇÃO B: Ollama no host → comente este serviço e defina
|
||||
# OLLAMA_BASE_URL=http://host-gateway:11434 nas env vars
|
||||
ollama:
|
||||
image: ollama/ollama:latest
|
||||
restart: always
|
||||
volumes:
|
||||
- ollama_models:/root/.ollama
|
||||
networks:
|
||||
- arcadia-internal
|
||||
# Remova 'profiles: [ai]' para ativar por padrão no deploy
|
||||
profiles: [ai]
|
||||
|
||||
# ── Open WebUI (interface para Ollama + LLMFit) ───────────────────────────────
|
||||
open-webui:
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
restart: always
|
||||
environment:
|
||||
# Pode apontar para LiteLLM para ter acesso a todos os modelos via WebUI
|
||||
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
|
||||
OPENAI_API_BASE_URL: http://litellm:4000/v1
|
||||
OPENAI_API_KEY: ${LITELLM_API_KEY}
|
||||
WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY}
|
||||
volumes:
|
||||
- open_webui_data:/app/backend/data
|
||||
depends_on:
|
||||
- litellm
|
||||
networks:
|
||||
- arcadia-internal
|
||||
- arcadia-public
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.webui.rule=Host(`ai.${DOMAIN}`)"
|
||||
- "traefik.http.routers.webui.tls=true"
|
||||
- "traefik.http.routers.webui.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.webui.loadbalancer.server.port=8080"
|
||||
profiles: [ai]
|
||||
|
||||
networks:
|
||||
arcadia-internal:
|
||||
driver: bridge
|
||||
arcadia-public:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
redis_data:
|
||||
ollama_models:
|
||||
open_webui_data:
|
||||
|
|
@ -13,35 +13,22 @@
|
|||
model_list:
|
||||
|
||||
# ── TIER 1: LLMFit (modelos fine-tuned locais — máxima soberania) ────────────
|
||||
# Descomente quando o LLMFit estiver rodando no servidor
|
||||
# O LLMFit expõe API compatível com OpenAI — basta apontar a URL
|
||||
#
|
||||
# - model_name: arcadia-finetuned
|
||||
# litellm_params:
|
||||
# model: openai/arcadia-v1 # nome do modelo no LLMFit
|
||||
# api_base: os.environ/LLMFIT_BASE_URL
|
||||
# api_key: llmfit-internal
|
||||
#
|
||||
# - model_name: arcadia-embed
|
||||
# litellm_params:
|
||||
# model: openai/arcadia-embed-v1 # modelo de embeddings fine-tuned
|
||||
# api_base: os.environ/LLMFIT_BASE_URL
|
||||
# api_key: llmfit-internal
|
||||
- model_name: arcadia-finetuned
|
||||
litellm_params:
|
||||
model: openai/llama3.2:3b
|
||||
api_base: os.environ/LLMFIT_BASE_URL
|
||||
api_key: os.environ/LLMFIT_API_KEY
|
||||
|
||||
- model_name: arcadia-embed
|
||||
litellm_params:
|
||||
model: openai/nomic-embed-text:latest
|
||||
api_base: os.environ/LLMFIT_BASE_URL
|
||||
api_key: os.environ/LLMFIT_API_KEY
|
||||
|
||||
# ── TIER 2: Ollama (LLMs locais — soberania total) ───────────────────────────
|
||||
- model_name: llama3.3
|
||||
- model_name: llama3.2
|
||||
litellm_params:
|
||||
model: ollama/llama3.3
|
||||
api_base: os.environ/OLLAMA_BASE_URL
|
||||
|
||||
- model_name: qwen2.5-coder
|
||||
litellm_params:
|
||||
model: ollama/qwen2.5-coder:7b
|
||||
api_base: os.environ/OLLAMA_BASE_URL
|
||||
|
||||
- model_name: deepseek-r1
|
||||
litellm_params:
|
||||
model: ollama/deepseek-r1:7b
|
||||
model: ollama/llama3.2:3b
|
||||
api_base: os.environ/OLLAMA_BASE_URL
|
||||
|
||||
- model_name: nomic-embed-text
|
||||
|
|
@ -49,6 +36,12 @@ model_list:
|
|||
model: ollama/nomic-embed-text
|
||||
api_base: os.environ/OLLAMA_BASE_URL
|
||||
|
||||
# Alias OpenAI-compatible para embedding (Manus usa este nome por padrão)
|
||||
- model_name: text-embedding-3-small
|
||||
litellm_params:
|
||||
model: ollama/nomic-embed-text
|
||||
api_base: os.environ/OLLAMA_BASE_URL
|
||||
|
||||
# ── TIER 3: OpenAI (opt-in — só ativo se OPENAI_API_KEY configurado) ─────────
|
||||
- model_name: gpt-4o
|
||||
litellm_params:
|
||||
|
|
@ -73,29 +66,26 @@ model_list:
|
|||
# api_key: os.environ/GROQ_API_KEY
|
||||
|
||||
# ── Modelo padrão do Arcádia (Manus usa este) ─────────────────────────────────
|
||||
# Prioridade: LLMFit → OpenAI (se configurado) → Ollama (sempre disponível)
|
||||
# Para soberania total: remova o fallback para gpt-4o-mini
|
||||
# Prioridade: LLMFit (TIER 1) → Ollama (TIER 2 — fallback)
|
||||
- model_name: arcadia-default
|
||||
litellm_params:
|
||||
model: ollama/llama3.3
|
||||
api_base: os.environ/OLLAMA_BASE_URL
|
||||
model_info:
|
||||
# fallbacks: ["gpt-4o-mini"] # descomente para habilitar fallback externo
|
||||
model: openai/llama3.2:3b
|
||||
api_base: os.environ/LLMFIT_BASE_URL
|
||||
api_key: os.environ/LLMFIT_API_KEY
|
||||
|
||||
router_settings:
|
||||
routing_strategy: least-busy
|
||||
fallbacks:
|
||||
- {"gpt-4o": ["llama3.3"]}
|
||||
- {"gpt-4o-mini": ["llama3.3"]}
|
||||
- {"arcadia-default": ["llama3.3"]}
|
||||
- {"gpt-4o": ["llama3.2"]}
|
||||
- {"gpt-4o-mini": ["llama3.2"]}
|
||||
- {"arcadia-default": ["llama3.2"]}
|
||||
- {"arcadia-finetuned": ["llama3.2"]}
|
||||
- {"arcadia-embed": ["nomic-embed-text"]}
|
||||
|
||||
litellm_settings:
|
||||
drop_params: true
|
||||
request_timeout: 120
|
||||
set_verbose: false
|
||||
# Loga todas as chamadas no banco — essencial para auditoria e soberania
|
||||
success_callback: ["langfuse"]
|
||||
failure_callback: ["langfuse"]
|
||||
|
||||
general_settings:
|
||||
master_key: os.environ/LITELLM_MASTER_KEY
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
FROM apache/superset:latest
|
||||
USER root
|
||||
RUN pip install psycopg2-binary && \
|
||||
sed -i 's/include-system-site-packages = false/include-system-site-packages = true/' /app/.venv/pyvenv.cfg
|
||||
USER superset
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Seed das regras padrão do SOE (soe_regras)
|
||||
* Insere FISCAL_RULES_PADRAO + BUSINESS_RULES_PADRAO no banco.
|
||||
* Idempotente: pula regras que já existem (por nome + trigger).
|
||||
*
|
||||
* Uso:
|
||||
* DATABASE_URL=postgres://... npx tsx scripts/seed-soe-rules.ts
|
||||
*/
|
||||
|
||||
import pg from "pg";
|
||||
import { FISCAL_RULES_PADRAO } from "../server/soe/rule-engine/fiscal-rules";
|
||||
import { BUSINESS_RULES_PADRAO } from "../server/soe/rule-engine/business-rules";
|
||||
|
||||
if (!process.env.DATABASE_URL) {
|
||||
throw new Error("DATABASE_URL não definida");
|
||||
}
|
||||
|
||||
const client = new pg.Client({ connectionString: process.env.DATABASE_URL });
|
||||
await client.connect();
|
||||
|
||||
const ALL_RULES = [...FISCAL_RULES_PADRAO, ...BUSINESS_RULES_PADRAO];
|
||||
|
||||
console.log(`Inserindo ${ALL_RULES.length} regras padrão SOE...\n`);
|
||||
|
||||
let inserted = 0;
|
||||
let skipped = 0;
|
||||
|
||||
for (const rule of ALL_RULES) {
|
||||
const existing = await client.query(
|
||||
`SELECT id FROM soe_regras WHERE nome = $1 AND trigger = $2 AND origem_padrao = true`,
|
||||
[rule.nome, rule.trigger]
|
||||
);
|
||||
|
||||
if ((existing.rowCount ?? 0) > 0) {
|
||||
console.log(` [SKIP] ${rule.id}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
await client.query(
|
||||
`INSERT INTO soe_regras (dominio, trigger, nome, condicao, acao, prioridade, ativo, origem_padrao, tenant_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||
[
|
||||
rule.dominio,
|
||||
rule.trigger,
|
||||
rule.nome,
|
||||
JSON.stringify(rule.condicao),
|
||||
JSON.stringify(rule.acao),
|
||||
rule.prioridade,
|
||||
rule.ativo,
|
||||
true,
|
||||
null,
|
||||
]
|
||||
);
|
||||
|
||||
console.log(` [OK] ${rule.id} — ${rule.nome}`);
|
||||
inserted++;
|
||||
}
|
||||
|
||||
await client.end();
|
||||
|
||||
console.log(`\nConcluído: ${inserted} inseridas, ${skipped} ignoradas.`);
|
||||
|
|
@ -2,15 +2,15 @@ import type { Express, Request, Response } from "express";
|
|||
import multer from "multer";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { createRequire } from "module";
|
||||
|
||||
import AdmZip from "adm-zip";
|
||||
import * as BSON from "bson";
|
||||
import { db } from "../../db/index";
|
||||
import { biDatasets, stagedTables } from "@shared/schema";
|
||||
import { sql } from "drizzle-orm";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const XLSX = require("xlsx");
|
||||
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
const uploadDir = path.join(process.cwd(), "uploads");
|
||||
if (!fs.existsSync(uploadDir)) {
|
||||
|
|
|
|||
|
|
@ -1190,3 +1190,6 @@ export function registerErpRoutes(app: Express): void {
|
|||
}
|
||||
});
|
||||
}
|
||||
// SOE routes — placeholder
|
||||
|
||||
export function registerSoeRoutes(_app: Express): void {}
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ export function log(message: string, source = "express") {
|
|||
password: hashedPassword,
|
||||
name: "Administrador Master",
|
||||
email: "admin@arcadia.suite",
|
||||
role: "master",
|
||||
role: "admin",
|
||||
status: "active",
|
||||
});
|
||||
console.log("[Seed] Usuário master 'admin' criado com sucesso");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import type { Express } from "express";
|
||||
|
||||
// Carregador de rotas modulares — placeholder
|
||||
export async function loadModuleRoutes(_app: Express): Promise<void> {
|
||||
// Módulos serão registrados aqui conforme forem criados
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Serviço de sincronização com Plus — placeholder
|
||||
export const retailPlusSyncService = {
|
||||
async getPlusStatus() { return { connected: false }; },
|
||||
async syncAllPersonsToPlus(_tenantId: any, _empresaId: any) { return { synced: 0 }; },
|
||||
async syncSaleToPlus(_saleId: any) { return { synced: false }; },
|
||||
async emitirNFeSale(_saleId: any, _tipo?: string) { return { emitted: false }; },
|
||||
async importClientesFromPlus(_tenantId: any, _empresaId: any) { return { imported: 0 }; },
|
||||
async importProdutosFromPlus(_tenantId: any, _empresaId: any) { return { imported: 0 }; },
|
||||
};
|
||||
|
|
@ -52,7 +52,7 @@ export function registerSupersetRoutes(app: Express): void {
|
|||
last_name: user?.name?.split(" ").slice(1).join(" ") || "User",
|
||||
},
|
||||
resources: [{ type: "dashboard", id: dashboardId }],
|
||||
rls: [],
|
||||
rls: user?.tenantId ? [{ clause: `tenant_id = ${user.tenantId}`, type: "BASE_ROLE" }] : [],
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { sql } from "drizzle-orm";
|
||||
import { pgTable, text, varchar, primaryKey, serial, integer, timestamp, numeric, jsonb, boolean, date } from "drizzle-orm/pg-core";
|
||||
import { pgTable, text, varchar, primaryKey, serial, integer, timestamp, numeric, jsonb, boolean, date, uuid } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
// Schemas modulares — gerados pelo Dev Center
|
||||
// Arquivo placeholder: adicione exports conforme módulos forem criados
|
||||
export {};
|
||||
Loading…
Reference in New Issue