Backend de marketplace multi-vendedor, escrito em Java/Spring, com escopo deliberadamente estreito e profundidade concentrada no núcleo: pedido, pagamento e estoque. Não é uma loja completa — é uma demonstração de modelagem de domínio, concorrência, consistência e operação sob falha. O nicho (tecnologia e cultura geek) é só o pano de fundo; a arquitetura é o ponto.
Critério de sucesso do projeto: um revisor técnico abre o repositório e, em poucos minutos, vê rigor no fluxo de pedido (máquina de estados, idempotência de pagamento, estoque correto sob concorrência) — não 30 endpoints CRUD genéricos. Ver design/escopo para os cortes deliberados de escopo.
Para quem tem pouco tempo, nessa ordem:
- architecture/overview.md — diagramas C4 (Context, Container, Component) e como os 6 módulos se comunicam entre si.
- adr/ — decisões arquiteturais significativas, uma por arquivo, imutáveis. Comece por ADR-0001 (monólito modular em vez de microsserviços).
- design/nucleo-pedido-pagamento-estoque.md — como o núcleo (pedido, pagamento, estoque) é desenhado antes de ser construído: máquina de estados, idempotência, outbox, consistência de estoque sob concorrência.
- notes/ — notas de referência menores, cada uma registrando o raciocínio por trás de uma decisão técnica pontual (ex.: por que a busca do catálogo virou uma query nativa).
Monólito modular. Um único deploy, seis bounded contexts (identity, catalog, estoque,
pedidos, pagamento, notificação) com fronteiras impostas pelo Spring Modulith e verificadas
em teste — nenhum módulo acessa os internals de outro, só a API pública que ele decide expor.
DDD tático e hexagonal são aplicados seletivamente, só onde há invariante real para proteger
(Pedidos, Pagamento e o núcleo pequeno de Estoque); os módulos de apoio permanecem
simples/CRUD de propósito. Razão completa em ADR-0001.
- Java 21 · Spring Boot (Web MVC, Security, Data JPA, Validation)
- PostgreSQL com Flyway para migrations (inclui busca full-text via
tsvector/GIN) - Spring Modulith para fronteiras de módulo verificadas em build
- FusionAuth com OAuth2/OIDC e sessão no Spring Security para autenticação
- Vavr (
Either) para erros de negócio como valor, em vez de exceção — ver ADR-0004 - springdoc-openapi + Scalar para documentação interativa da API
- Testcontainers (Postgres real em teste de integração)
- Spotless com formatador Eclipse JDT (tabs) — ver ADR-0005
Em desenvolvimento incremental por fatia vertical. Hoje:
identity— inicia login e cadastro hospedados no FusionAuth e expõe a sessão atual. Credenciais e login social são geridos pelo FusionAuth.catalog— domínio, persistência e casos de uso de vendedores/categorias/produtos, com busca pública combinável (categoria + faixa de preço + full-text). Ainda sem camada HTTP própria.estoque,pedidos,pagamento,notificação— ainda não implementados; o desenho está em design/nucleo-pedido-pagamento-estoque.md, escrito antes da construção.
Pré-requisitos: Java 21 (ver .sdkmanrc), PostgreSQL da aplicação e uma Application configurada no FusionAuth com self-service registration habilitado.
cp .env.example .env
# edite .env com as credenciais do Postgres e com FUSIONAUTH_CLIENT_ID/CLIENT_SECRET
./mvnw spring-boot:runA API sobe em http://localhost:8080; documentação interativa em /scalar. Testes de
integração usam Testcontainers e sobem um Postgres descartável automaticamente:
./mvnw testPara aplicar apenas as migrations, sem iniciar a API, use o perfil Maven que
carrega o .env e executa o Flyway:
./mvnw -Pmigrate initializeConfigure as URLs http://localhost:8080/login/oauth2/code/fusionauth e
http://localhost:8080/post-logout nas Authorized Redirect URLs da Application no FusionAuth.
FUSIONAUTH_URL deve ser alcançável pelo navegador e pelo backend. Em produção, defina
SESSION_COOKIE_SECURE=true; use
SESSION_COOKIE_SAME_SITE=none junto com HTTPS se o frontend estiver em outro site e
preencha CORS_ALLOWED_ORIGINS com as origens exatas, separadas por vírgula.
O frontend inicia o fluxo em GET /api/auth/login ou GET /api/auth/register.
Após o callback, o backend redireciona para APP_LOGIN_SUCCESS_URL (por padrão,
/api/auth/me). GET /api/auth/me retorna id, email e name sem tokens.
Antes de POST /api/auth/logout ou de outra chamada de
escrita, obtenha GET /api/auth/csrf e envie o token no header indicado por
headerName. O cookie JSESSIONID deve acompanhar essas requisições. O logout deve ser
submetido como navegação de navegador (por exemplo, um formulário POST), pois a resposta
redireciona para o logout SSO do FusionAuth e depois para APP_POST_LOGOUT_URL. A rota
/post-logout ainda não possui página e retorna 404 por enquanto.
O banco do marketplace não cria tabelas locais de usuários ou credenciais.
sellers.user_id guarda o ID do usuário no FusionAuth (sub do OIDC). Como as
migrations foram renumeradas para um banco novo, recrie o banco de desenvolvimento
se já tiver executado as migrations antigas. O Java Client do FusionAuth não é
necessário neste fluxo; ele pode ser adicionado quando houver operações
administrativas da API REST.
Executar aplicação
mvn spring-boot:run
Aplicar migrações
./mvnw -Pmigrate initialize
Executar o ciclo Maven até a fase de testes limitadas à execução às classes informadas
./mvnw -Dtest=AuthControllerSecurityTest,FusionAuthAuthorizationRequestResolverTest test