📌 Guia Técnico para Arquitetura e Desenvolvimento de Micro-Frontend (MFE)
🔹 O que é um Micro-Frontend?
Um Micro-Frontend (MFE) é uma abordagem arquitetural que aplica ao front-end os mesmos princípios usados em microservices no back-end.
Em vez de manter uma única aplicação monolítica de interface, a aplicação é dividida em módulos menores, independentes e autônomos, que podem ser desenvolvidos, testados e implantados separadamente.
Cada MFE é responsável por uma parte específica do domínio de negócio e pode ser integrado a uma aplicação maior (geralmente chamada de Shell ou Container) através de técnicas como Webpack Module Federation, iframes ou Web Components.
🔹 Quais as principais vantagens?
| Vantagem | Descrição |
|---|---|
| Autonomia das equipes | Cada squad pode trabalhar em um MFE específico sem bloquear outras equipes. |
| Deploy independente | Atualizações podem ser entregues sem precisar publicar toda a aplicação. |
| Escalabilidade organizacional | Facilita o crescimento da aplicação e do time de desenvolvimento. |
| Isolamento de falhas | Erros em um MFE não necessariamente comprometem toda a aplicação. |
| Evolução tecnológica | Diferentes MFEs podem adotar versões distintas de libs ou frameworks, permitindo evolução gradual. |
| Time-to-market mais rápido | Novas funcionalidades chegam ao usuário sem depender de uma release centralizada. |
🔹 Quais são os benefícios?
| Benefício | Descrição |
|---|---|
| Melhoria na manutenção | Código mais enxuto e focado em um domínio específico reduz complexidade. |
| Reuso de componentes e padrões | MFEs podem compartilhar bibliotecas (como o Design System) para manter consistência visual e de usabilidade. |
| Escalabilidade técnica | Permite dividir a aplicação em múltiplos pipelines de build, testes e deploy. |
| Aumento da qualidade | Com menor escopo de código em cada MFE, testes e revisões tornam-se mais eficazes. |
| Flexibilidade arquitetural | Facilita a introdução de novas tecnologias sem reescrever toda a aplicação. |
| Alinhamento com microservices | Cria simetria entre front-end e back-end, adotando práticas modernas de arquitetura distribuída. |
🔹 Desenvolvimento:
Inicialização do Repositório
- O projeto deverá ser inicializado a partir do Alquimia, sendo escolhida a categoria Static Front-End, com o template Micro-Frontend with Module Federation. Os seguintes parâmetros devem ser selecionados/informados:

| Parâmetro | Valor |
|---|---|
| System | finopping (platform-engineering) |
| GitHub Team | 903 - Finopping |
| Component Name | À escolher, desde que contenha um prefixo final nomeado como mfe |
| Repository GitHub Name | Será inicializado com o prefixo plat-eng-finop e, composto pelo nome do componente inserido anteriormente. |
| Component Description | Breve descrição do que se refere o componente (a ser criado) |
-
Após, confirmar se todos os ambientes necessários serão apresentados. Caso não sejam, entrar em contato a partir do canal
#fale-com-devops-cross. -
Na sequência, deverão ser informados o sub-domínio e domínio - inclusive, será apresentado no Alqumia como o endereço de acesso ao MFE será consolidado.
-
Caso deseje associar algum canal do Slack específico, a próxima etapa será para isso.
-
E por fim, basta revisar e executar a criação do projeto.
Com o repositório criado, basta dar continuidade com as configurações básicas:
Husky,Semantic Release, Template para Pull Requests, outros.
❗️ Dica importante para criar os commits...
Os commits semânticos são uma abordagens para rotular commits de uma forma mais significativa e estruturada, tornando o histórico de desenvolvimento de software mais fácil de entender e de se trabalhar. O objetivo principal dos commits semânticos é fornecer informações úteis sobre a natureza da mudança, o escopo das mudanças e o impacto que a mudança pode ter no sistema.
| Tipo | Emoji | Quando Usar | Versão |
|---|---|---|---|
| feat | ✨ | Quando adicionamos uma nova funcionalidade ao código ou ao projeto, sem mudanças significativas em funcionalidades existentes. Pode alterar completamente uma única funcionalidade. Não deve quebrar a compatibilidade com versões anteriores. | Minor |
| fix | 🐛 | Quando corrigimos um bug ou um problema no código ou no projeto. Deve ser usado quando a correção não altera o comportamento de funcionalidades existentes. Não deve quebrar a compatibilidade com versões anteriores. | Patch |
| perf | ⚡ | Quando fazemos alterações que melhoram o desempenho do código ou do projeto ou adicionam melhorias a sistemas de monitoramento, logs, etc, de funcionalidades já existentes sem alterar o comportamento delas. | Patch |
| style | 💄 | Quando fazemos alterações que não afetam o comportamento do código como alteração de textos estáticos ou alterações de estilos de componentes, etc. | Patch |
| refactor | 🔨 | Quando fazemos alterações no código que não adicionam novas funcionalidades nem corrigem bugs, mas melhoram a estrutura, a legibilidade ou a manutenibilidade do código. | Minor |
| chore | 🚧 | Quando fazemos alterações no código que não afetam o comportamento do projeto, como ajustes de configuração, atualizações de dependências, alteração de recursos de infraestrutura, etc. | Patch |
| test | 🧪 | Quando adicionamos ou modificamos testes no código ou no projeto. | n/a |
| docs | 📚 | Quando fazemos alterações na documentação do código ou do projeto, como README, guias, comentários, etc. | n/a |
| ci | 🔧 | Quando fazemos alterações em configurações de integração contínua, como GitHub Actions. | n/a |
Estrutura de pastas e arquivos

Uma das etapas mais importantes no desenvolvimento de um Micro-Frontend (MFE) é a definição de uma estrutura de pastas sólida, organizada e padronizada.
Essa estrutura serve como guia para o time, facilita o onboarding de novos desenvolvedores, aumenta a produtividade e reduz a chance de erros de manutenção ao longo do ciclo de vida do projeto.
No contexto da Plataforma Finopping, a padronização de diretórios também promove consistência entre todos os MFEs, facilitando integrações, automações de CI/CD e garantindo que práticas como testes, documentação e versionamento sejam seguidas de forma uniforme.
Quick Wins:
- 🚀 Velocidade no desenvolvimento: menos tempo perdido procurando onde colocar ou encontrar código.
- ✅ Qualidade de código: separação clara de responsabilidades reduz erros.
- 📦 Reuso de lógica e componentes: hooks e serviços bem definidos podem ser aplicados em múltiplas partes do projeto.
- 🔄 Testabilidade: com escopos menores (services, hooks, components), os testes ficam mais objetivos.
- 🧩 Integração facilitada: quando todos os MFEs seguem a mesma estrutura, o Shell e outros times conseguem consumir e integrar módulos de forma previsível.
- 📈 Escalabilidade futura: a base sólida permite crescimento do projeto sem gerar um novo “monólito disfarçado”.
Uma boa organização de pastas é essencial para manter a aplicação escalável, legível e fácil de dar manutenção. Cada seção descreve a finalidade da pasta/arquivo, o que deve conter e um espaço reservado para blocos de código de exemplo.
🧩 components/
Pasta dedicada a componentes visuais reutilizáveis dentro do escopo do MFE.
- Sempre baseados no Design System Flora.
- Não devem conter regras de negócio, apenas UI e interações.
- Componentes devem ser coesos e autocontidos, podendo ter subpastas próprias.
➡️ Exemplo de código:
import { FloraButton } from "@grupoboticario/flora-react"
type ButtonExampleProps = {
name: string;
action: () => void;
}
export const ButtonExample = ({ name, action }: ButtonExampleProps) => {
return(
<FloraButton
aria-label={name}
onClick={action}
>
{name}
</FloraButton>
)
}
🌐 contexts/
Armazena React Context Providers responsáveis por compartilhar estado em diferentes áreas do MFE. - Usado para dados de sessão, preferências ou estados que devem ser acessados por múltiplos componentes/páginas. - Evitar uso excessivo para não transformar tudo em estado global.
➡️ Exemplo de código:
import { UsersService } from '../data/services/users.service';
import { createContext, useMemo } from 'react';
interface UsersProviderProps {
children: React.ReactNode;
}
const UsersContext = createContext<UsersService | null>(null);
function UsersProvider({ children }: Readonly<UsersProviderProps>) {
const usersService = useMemo(() => new UsersService(), []);
return (
<UsersContext.Provider value={usersService}>
{children}
</UsersContext.Provider>
);
}
export {
UsersService,
UsersProvider,
UsersProviderProps,
};
export default UsersContext;
🗂️ data/models/
Contém tipos, interfaces e contratos de dados. - Representam entidades que vêm do back-end (API/BFF). - Servem como “contrato único de verdade” para a aplicação.
➡️ Exemplo de código:
export interface IUser {
id: string;
name: string;
email: string;
}
📡 data/services/
Centraliza toda a lógica de integração com APIs/BFFs.
- Nunca fazer chamadas HTTP direto em hooks ou componentes.
- Utilizar um API Client configurado com interceptors (auth, tracing, error handling).
- Cada arquivo deve corresponder a um domínio (ex.: users.service.ts).
➡️ Exemplo de código:
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { IUser } from '../models/user.model';
export interface IUsersService {
get(): Promise<IUser[]>;
}
export class UsersService implements IUsersService {
private readonly api: AxiosInstance;
constructor() {
this.api = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com',
});
}
private async createConfig(): Promise<AxiosRequestConfig> {
return {
headers: {
'Content-Type': 'application/json',
},
};
}
public async get(): Promise<IUser[]> {
const config = await this.createConfig();
const { data } = await this.api.get<IUser[]>('/users', config);
return data;
}
public async getById(id: number): Promise<IUser> {
const config = await this.createConfig();
const { data } = await this.api.get<IUser>(`/users/${id}`, config);
return data;
}
}
🔄 hooks/
Armazena React Hooks customizados para reuso de lógica.
- Hooks de domínio: encapsulam regras específicas (ex.: useUsers).
- Hooks técnicos: facilitam reuso de lógica (ex.: useDebounce).
- Nomeação padrão: use-*.hook.ts.
➡️ Exemplo de código:
import { useContext } from 'react';
import { useQuery } from '@tanstack/react-query';
import UsersContext from '../contexts/users.context';
export function useUsers() {
const users = useContext(UsersContext);
return useQuery({
queryKey: ['useUsers'],
queryFn: () => users?.get() || null,
});
}
📄 pages/
Contém as páginas principais e rotas do MFE.
- Cada página deve estar preparada para rodar standalone e também ser exposta via Module Federation.
- Arquivo index.tsx dentro de pages/ deve exportar o Routes do domínio.
➡️ Exemplo de código:
import { Flex, Spinner } from "@grupoboticario/flora-react";
import { CardExample } from "../components/card-example"
import { useUsers } from "../hooks/use-users.hook"
export const PageExample = () => {
const { isPending, isError, data, error } = useUsers();
if (isPending) {
return <Spinner />
}
if (isError) {
return <div>Ocorreu um erro: {String(error)}</div>
}
return (
<>
<Flex direction='column' gap='$2'>
{data?.map(user => (
<CardExample key={user.id} id={user.id} name={user.name} email={user.email} />
))}
</Flex>
</>
)
}
🔹 Testes Unitários, Cobertura e Reports
Objetivo
Garantir que cada MFE mantenha qualidade de código, previsibilidade de comportamento e segurança contra regressões através de testes unitários consistentes.
Ferramentas
- Jest: framework principal de testes unitários.
- React Testing Library (RTL): testes de componentes React, priorizando comportamento sobre implementação.
- Coverage Reports: relatórios de cobertura para medir eficácia dos testes.
Cobertura Mínima
O projeto deve manter ≥ 80% de cobertura global em:
-
Statements (Declarações) Mede quantas instruções do código foram executadas pelos testes.
Exemplo: umconsole.log()ou uma atribuição de variável. Se você tem 10 declarações e os testes passam por 8, sua cobertura de statements será 80%. -
Branches (Ramificações) Mede se todos os caminhos de decisão foram testados.
Exemplo: condicionaisif/else, operadores ternários,switch/case. Se você testa apenas oifmas nunca oelse, a cobertura de branches estará incompleta. -
Functions (Funções) Mede quantas funções ou métodos foram chamadas pelos testes.
Exemplo: se um módulo possui 5 funções exportadas mas só 3 foram chamadas nos testes, a cobertura de functions será 60%. -
Lines (Linhas) Mede a quantidade de linhas de código executadas durante os testes.
É parecido com statements, mas contado de forma mais granular.
Exemplo: se um arquivo tem 100 linhas e 90 são executadas nos testes, a cobertura de lines será 90%.
Localização dos Testes
- Os testes devem ser mantidos próximos aos arquivos que validam ou dentro de uma pasta
__tests__. - Extensão recomendada:
*.test.ts*.test.tsx
Relatórios
- HTML (lcov-report): usado localmente para consulta rápida.
- Cobertura XML (cobertura/junit): usado em pipelines de CI/CD para integração com ferramentas como SonarQube ou Codecov.
Exemplo de script em package.json
```json { "scripts": { "test": "jest --passWithNoTests", "test:cov": "jest --coverage", "test:ci": "jest --ci --reporters=default --reporters=jest-junit --coverage" } }