Arquitetura Desacoplada: Frontend, Backend e Worker Isolados
Este documento descreve uma arquitetura de microsserviços onde cada componente principal (Frontend, Backend, Worker) opera de forma isolada, com seu próprio ciclo de vida, repositório (opcional) e orquestração via Docker Compose. A comunicação entre os serviços ocorre via HTTP (para API) e através de serviços de dados externos (Banco de Dados e Redis).
Visão Geral
Nesta arquitetura, removemos a dependência de uma rede Docker interna compartilhada. Em vez disso, tratamos cada serviço como se estivesse rodando em uma infraestrutura separada.
- Backend (API): Expõe endpoints HTTP públicos. Conecta-se diretamente ao Banco de Dados e Redis (gerenciados externamente).
- Worker: Processa tarefas em background. Conecta-se aos mesmos Banco de Dados e Redis externos que o Backend.
- Frontend: Aplicação estática (SPA) servida por um servidor web. O navegador do usuário consome a API do Backend via internet pública.
- Serviços de Dados (DB/Redis): Hospedados externamente (ex: AWS RDS, MongoDB Atlas, Redis Cloud) ou em um servidor dedicado, acessíveis via URL de conexão.
Fluxo de Comunicação
- Usuário -> Frontend: O navegador carrega a aplicação.
- Frontend (Navegador) -> Backend: O JavaScript no navegador faz requisições HTTP para a API (ex:
https://api.seudominio.com). - Backend -> Dados: A API lê/escreve no PostgreSQL e Redis externos.
- Worker -> Dados: O Worker monitora o Redis (filas) e processa dados no PostgreSQL, sem comunicação direta com a API.
Configuração dos Serviços
Cada serviço possui seu próprio docker-compose.yml e arquivo .env.
1. Backend
Responsável pela regra de negócio e API.
Arquivo: backend/docker-compose.yml
version: '3.8'
services:
api:
image: seu-registry/backend:latest
container_name: backend-api
restart: always
ports:
- "3000:3000" # Porta exposta para receber requisições do Frontend/Internet
env_file: .env
extra_hosts:
- "host.docker.internal:host-gateway" # Para Linux, caso precise acessar algo no host
Configuração (.env):
DATABASE_URL=postgres://user:pass@db-host-externo:5432/pilot_db
REDIS_URL=redis://:pass@redis-host-externo:6379
PORT=3000
2. Worker
Processamento de tarefas assíncronas (envio de emails, relatórios, etc.).
Arquivo: worker/docker-compose.yml
version: '3.8'
services:
worker:
image: seu-registry/worker:latest
container_name: worker-app
restart: always
# Workers geralmente não precisam de portas expostas (inbound)
env_file: .env
extra_hosts:
- "host.docker.internal:host-gateway"
Configuração (.env): Deve apontar para os mesmos serviços de dados do Backend.
DATABASE_URL=postgres://user:pass@db-host-externo:5432/pilot_db
REDIS_URL=redis://:pass@redis-host-externo:6379
3. Frontend
Servidor web (Nginx/Apache) servindo os arquivos estáticos da SPA (React/Vue/Angular).
Arquivo: frontend/docker-compose.yml
version: '3.8'
services:
web:
image: seu-registry/frontend:latest
container_name: frontend-web
restart: always
ports:
- "80:80" # Porta HTTP padrão
environment:
# URL da API que será injetada no build ou runtime do frontend
- VITE_API_URL=https://api.seudominio.com
Vantagens desta Arquitetura
1. Escalabilidade Independente (Horizontal Scaling)
Permite alocar recursos especificamente onde há gargalo.
- Cenário: Se a API estiver lenta devido a muitos acessos, você pode subir 5 réplicas do container
backend-apisem precisar duplicar o Frontend ou o Worker. - Cenário: Se houver muitas tarefas pesadas (ex: processamento de imagens), você pode escalar apenas os
workerspara processar a fila mais rápido, sem impactar a latência da API.
2. Resiliência e Isolamento de Falhas
Falhas em um componente não derrubam o sistema inteiro.
- Se o Worker travar ou consumir 100% da CPU, a API continua respondendo normalmente aos usuários.
- Se a API cair para manutenção, o Frontend continua sendo servido (podendo exibir uma mensagem amigável de erro/manutenção).
3. Deploy Sem Downtime (Zero Downtime)
Atualizações seguras e granulares.
- Você pode atualizar o Frontend (ex: mudar texto ou cor) sem reiniciar o Backend.
- Você pode corrigir um bug no Worker sem interromper a navegação dos usuários no site.
4. Bancos de Dados Gerenciados (Externalizados)
Ao tirar o estado (DB/Redis) de dentro do Docker Compose:
- Segurança: Backups, updates e patches de segurança são gerenciados pelo provedor (AWS, Azure, etc.).
- Persistência: Elimina o risco de perder dados se um container ou volume for deletado acidentalmente.
- Performance: Bancos de dados dedicados geralmente têm performance de I/O muito superior a bancos rodando em containers compartilhados.
5. Flexibilidade Tecnológica
Liberdade para evoluir a stack.
- O Frontend não precisa saber em que linguagem o Backend foi escrito, apenas consome JSON.
- O Worker pode ser reescrito em outra linguagem (ex: Go/Rust para performance) sem afetar o Backend, desde que ambos concordem no formato das mensagens no Redis/DB.
Gerenciamento de Código Compartilhado
Como Backend e Worker frequentemente utilizam as mesmas entidades (ex: definições de Banco de Dados, Tipos, Utilitários), é necessário uma estratégia para evitar duplicação e inconsistências.
1. Pacote Interno Compartilhado (Recomendado)
A abordagem mais moderna e segura é extrair o código comum para um pacote interno (packages/core ou shared).
- Funcionamento: Cria-se uma biblioteca interna que exporta DTOs, Schemas do Banco (Prisma/TypeORM) e Helpers.
- Integração: Backend e Worker declaram esse pacote como dependência no
package.json("dependencies": { "@app/core": "file:../packages/core" }). - Build: No momento do build da imagem Docker, o gerenciador de pacotes (npm/yarn/pnpm) ou ferramentas de monorepo (Turborepo/Nx) cuidam de copiar e linkar esse código.
- Vantagem: Fonte única de verdade (Single Source of Truth). Se uma tabela muda, você atualiza o pacote
coree reconstrói os serviços.
2. Git Submodules / Subtree
Manter o código comum em um repositório Git separado e importá-lo dentro das pastas dos projetos.
- Funcionamento: O código compartilhado é "clonado" dentro de
backend/src/sharedeworker/src/shared. - Vantagem: Desacoplamento total de gerenciadores de pacote.
- Desvantagem: Complexidade operacional (necessidade de dar pull manual nos submodules para atualizar).
3. Duplicação de Código (Não Recomendado)
Copiar e colar arquivos entre os projetos.
- Risco: Altíssima probabilidade de divergência (ex: Backend espera um campo
userIde Worker esperauser_id), causando erros difíceis de rastrear em produção.