{"id":50329072,"url":"https://github.com/eneas-almeida/bridge","last_synced_at":"2026-05-29T08:30:47.183Z","repository":{"id":328982339,"uuid":"1117830245","full_name":"eneas-almeida/bridge","owner":"eneas-almeida","description":"📜O projeto Bridge é uma arquitetura de microserviços desenvolvida por Enéas Almeida, composta por dois serviços principais que se comunicam via gRPC","archived":false,"fork":false,"pushed_at":"2025-12-26T18:53:54.000Z","size":54,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-28T00:37:11.955Z","etag":null,"topics":["clean-architecture","grpc","java","microservices","spring-boot","webflux"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eneas-almeida.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-16T21:59:08.000Z","updated_at":"2025-12-26T18:53:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/eneas-almeida/bridge","commit_stats":null,"previous_names":["eneas-almeida/bridge"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eneas-almeida/bridge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneas-almeida%2Fbridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneas-almeida%2Fbridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneas-almeida%2Fbridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneas-almeida%2Fbridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eneas-almeida","download_url":"https://codeload.github.com/eneas-almeida/bridge/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneas-almeida%2Fbridge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33644094,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean-architecture","grpc","java","microservices","spring-boot","webflux"],"created_at":"2026-05-29T08:30:41.584Z","updated_at":"2026-05-29T08:30:47.174Z","avatar_url":"https://github.com/eneas-almeida.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bridge - Documentação da Arquitetura\n\n## Visão Geral\n\nO projeto **Bridge** é uma arquitetura de microserviços composta por dois serviços principais que se comunicam via **gRPC**:\n\n- **API Service**: Gateway REST que expõe endpoints HTTP e se comunica com o serviço People via gRPC\n- **People Service**: Serviço backend que fornece dados de usuários via gRPC, com suporte a múltiplas fontes de dados externas (JSONPlaceholder ou DummyJSON)\n\n```\n┌──────────────┐     HTTP/REST      ┌──────────────┐      gRPC       ┌──────────────┐     HTTP      ┌─────────────────┐\n│   Cliente    │ ─────────────────\u003e │  API Service │ ──────────────\u003e │People Service│ ────────────\u003e │ External APIs   │\n│  (Browser)   │                    │  (Port 8081) │                 │ (Port 9090)  │               │ - JSONPlaceholder│\n└──────────────┘                    └──────────────┘                 └──────────────┘               │ - DummyJSON     │\n                                                                                                      └─────────────────┘\n```\n\n---\n\n## Índice\n\n1. [Tecnologias Utilizadas](#tecnologias-utilizadas)\n2. [Arquitetura dos Serviços](#arquitetura-dos-serviços)\n3. [Contrato gRPC](#contrato-grpc)\n4. [Fluxo de Comunicação Detalhado](#fluxo-de-comunicação-detalhado)\n5. [API Service](#api-service)\n6. [People Service](#people-service)\n7. [Configuração e Execução](#configuração-e-execução)\n8. [Endpoints Disponíveis](#endpoints-disponíveis)\n\n---\n\n## Tecnologias Utilizadas\n\n### Comuns a Ambos os Projetos\n- **Java 21**\n- **Spring Boot 3.3.3**\n- **Spring WebFlux** (Programação Reativa)\n- **Project Reactor** (Mono/Flux)\n- **Lombok**\n- **Maven**\n\n**API Service:**\n- **gRPC 1.58.0**\n- **Protocol Buffers 3.24.3**\n\n**People Service:**\n- **gRPC 1.59.0**\n- **Protocol Buffers 3.24.4**\n\n### Específicas do API Service\n- **gRPC Client Spring Boot Starter 2.15.0**\n- **MapStruct 1.5.5** (Mapeamento gRPC Proto para DTOs)\n\n### Específicas do People Service\n- **gRPC Server Spring Boot Starter 2.15.0**\n- **Reactor gRPC 1.2.4** (gRPC Reativo)\n- **MapStruct 1.5.5** (Mapeamento de DTOs)\n- **Logstash Logback Encoder 7.4** (Logging estruturado)\n- **Datadog Trace API 1.30.1** (Observabilidade)\n\n---\n\n## Arquitetura dos Serviços\n\nAmbos os serviços seguem os princípios de **Clean Architecture** com separação clara de responsabilidades:\n\n### Camadas da Arquitetura\n\n```\n┌─────────────────────────────────────────────┐\n│          Presentation/Entrypoint            │\n│  (REST Controllers / gRPC Services)         │\n└────────────────┬────────────────────────────┘\n                 │\n┌────────────────▼────────────────────────────┐\n│           Application Layer                 │\n│         (Services + DTOs)                   │\n└────────────────┬────────────────────────────┘\n                 │\n┌────────────────▼────────────────────────────┐\n│            Domain Layer                     │\n│   (Repository/Client Interfaces)            │\n└────────────────┬────────────────────────────┘\n                 │\n┌────────────────▼────────────────────────────┐\n│        Infrastructure Layer                 │\n│   (Repositories / gRPC Clients/Servers)     │\n│         (HTTP Clients / Mappers)            │\n└─────────────────────────────────────────────┘\n```\n\n---\n\n## Contrato gRPC\n\nO contrato de comunicação entre os serviços é definido através de **Protocol Buffers**.\n\n### Arquivo Proto (`person.proto`)\n\n```protobuf\nsyntax = \"proto3\";\n\noption java_package = \"com.people.grpc\";\noption java_outer_classname = \"ServiceProto\";\n\npackage grpcservice;\n\nservice PeopleService {\n  rpc GetPeople (PeopleRequestGrpc) returns (PeopleResponseGrpc);\n  rpc ListPeople (ListPeopleRequestGrpc) returns (ListPeopleResponseGrpc);\n}\n\nmessage PeopleRequestGrpc {\n  int32 id = 1;\n}\n\nmessage ListPeopleRequestGrpc {}\n\nmessage PeopleResponseGrpc {\n  int32 id = 1;\n  string name = 2;\n  string email = 3;\n}\n\nmessage ListPeopleResponseGrpc {\n  repeated PeopleResponseGrpc people = 1;\n}\n```\n\n### RPCs Disponíveis\n\n| RPC | Request | Response | Descrição |\n|-----|---------|----------|-----------|\n| `GetPeople` | `PeopleRequestGrpc` (id) | `PeopleResponseGrpc` | Busca uma pessoa por ID |\n| `ListPeople` | `ListPeopleRequestGrpc` (vazio) | `ListPeopleResponseGrpc` | Lista todas as pessoas |\n\n---\n\n## Fluxo de Comunicação Detalhado\n\n### Fluxo 1: Buscar Pessoa por ID\n\n```\nCliente              API Service             People Service          External API\n  │                       │                        │                (DummyJSON ou JSONPlaceholder)\n  │ GET /api/peoples/1    │                        │                        │\n  ├──────────────────────\u003e│                        │                        │\n  │                       │ PeopleController       │                        │\n  │                       │        ↓               │                        │\n  │                       │ PeopleService          │                        │\n  │                       │        ↓               │                        │\n  │                       │ PeopleRepository       │                        │\n  │                       │        ↓               │                        │\n  │                       │ PeopleGrpcClient       │                        │\n  │                       │   (MapStruct)          │                        │\n  │                       │                        │                        │\n  │                       │ gRPC: GetPeople(id=1)  │                        │\n  │                       ├───────────────────────\u003e│                        │\n  │                       │                        │ PeopleGrpcService      │\n  │                       │                        │        ↓               │\n  │                       │                        │ PeopleService          │\n  │                       │                        │        ↓               │\n  │                       │                        │ PeopleRepository       │\n  │                       │                        │   (Strategy Pattern)   │\n  │                       │                        │        ↓               │\n  │                       │                        │ DummyClient ou         │\n  │                       │                        │ TypiCodeClient         │\n  │                       │                        │   (MapStruct)          │\n  │                       │                        │                        │\n  │                       │                        │ GET /users/1           │\n  │                       │                        ├───────────────────────\u003e│\n  │                       │                        │                        │\n  │                       │                        │ JSON Response          │\n  │                       │                        │\u003c───────────────────────┤\n  │                       │                        │                        │\n  │                       │                        │ Map to DTO             │\n  │                       │                        │ (PeopleResponse)       │\n  │                       │                        │                        │\n  │                       │ PeopleResponse (gRPC)  │                        │\n  │                       │\u003c───────────────────────┤                        │\n  │                       │                        │                        │\n  │                       │ Map Proto to DTO       │                        │\n  │                       │   (MapStruct)          │                        │\n  │                       │        ↓               │                        │\n  │                       │ PeopleResponse (DTO)   │                        │\n  │                       │                        │                        │\n  │ JSON Response         │                        │                        │\n  │\u003c──────────────────────┤                        │                        │\n```\n\n### Fluxo 2: Listar Todas as Pessoas\n\n```\nCliente              API Service             People Service          External API\n  │                       │                        │                (DummyJSON ou JSONPlaceholder)\n  │ GET /api/peoples      │                        │                        │\n  ├──────────────────────\u003e│                        │                        │\n  │                       │ PeopleController       │                        │\n  │                       │        ↓               │                        │\n  │                       │ PeopleService          │                        │\n  │                       │        ↓               │                        │\n  │                       │ PeopleRepository       │                        │\n  │                       │        ↓               │                        │\n  │                       │ PeopleGrpcClient       │                        │\n  │                       │   (MapStruct)          │                        │\n  │                       │                        │                        │\n  │                       │ gRPC: ListPeople()     │                        │\n  │                       ├───────────────────────\u003e│                        │\n  │                       │                        │ PeopleGrpcService      │\n  │                       │                        │        ↓               │\n  │                       │                        │ PeopleService          │\n  │                       │                        │        ↓               │\n  │                       │                        │ PeopleRepository       │\n  │                       │                        │   (Strategy Pattern)   │\n  │                       │                        │        ↓               │\n  │                       │                        │ DummyClient ou         │\n  │                       │                        │ TypiCodeClient         │\n  │                       │                        │   (MapStruct)          │\n  │                       │                        │                        │\n  │                       │                        │ GET /users             │\n  │                       │                        ├───────────────────────\u003e│\n  │                       │                        │                        │\n  │                       │                        │ JSON Array Response    │\n  │                       │                        │\u003c───────────────────────┤\n  │                       │                        │                        │\n  │                       │                        │ Map to Flux\u003cDTO\u003e       │\n  │                       │                        │   (MapStruct)          │\n  │                       │                        │                        │\n  │                       │ ListPeopleResponse     │                        │\n  │                       │ (repeated gRPC)        │                        │\n  │                       │\u003c───────────────────────┤                        │\n  │                       │                        │                        │\n  │                       │ Map Proto to Flux\u003cDTO\u003e │                        │\n  │                       │   (MapStruct)          │                        │\n  │                       │                        │                        │\n  │ JSON Array Response   │                        │                        │\n  │\u003c──────────────────────┤                        │                        │\n```\n\n---\n\n## API Service\n\n### Estrutura do Projeto\n\n```\napi/\n├── src/main/java/org/api/\n│   ├── presentation/\n│   │   └── controller/\n│   │       └── PeopleControllerImpl.java\n│   ├── application/\n│   │   ├── dto/\n│   │   │   └── PeopleResponse.java\n│   │   └── service/\n│   │       ├── PeopleService.java (Interface)\n│   │       └── PeopleServiceImpl.java\n│   ├── domain/\n│   │   ├── client/\n│   │   │   └── PeopleServiceClient.java (Interface)\n│   │   └── repository/\n│   │       └── PeopleRepository.java (Interface)\n│   └── infrastructure/\n│       ├── client/\n│       │   ├── PeopleServiceGrpcClientImpl.java\n│       │   └── PeopleGrpcMapper.java (MapStruct)\n│       ├── repository/\n│       │   └── PeopleRepositoryImpl.java\n│       └── config/\n│           └── RepositoryConfig.java\n├── src/main/proto/\n│   └── person.proto\n└── src/main/resources/\n    └── application.yml\n```\n\n### Componentes Principais\n\n#### 1. PeopleControllerImpl (`presentation/controller/PeopleControllerImpl.java`)\n\n```java\n@RestController\n@RequestMapping(\"/api/peoples\")\n@RequiredArgsConstructor  // Lombok\npublic class PeopleControllerImpl {\n\n    private final PeopleService peopleService;  // Interface!\n\n    @GetMapping(\"/{id}\")\n    public Mono\u003cPeopleResponse\u003e getPeopleById(@PathVariable int id)\n\n    @GetMapping\n    public Flux\u003cPeopleResponse\u003e listPeople()\n}\n```\n\n**Responsabilidades:**\n- Expor endpoints REST HTTP\n- Receber requisições do cliente\n- Delegar para o serviço de aplicação\n- Retornar DTOs de resposta\n- **Inversão de Dependência:** Injeta interface `PeopleService`, não implementação\n\n#### 2. PeopleService (`application/service/`)\n\n**PeopleService (Interface)**\n```java\npublic interface PeopleService {\n    Mono\u003cPeopleResponse\u003e getById(int id);\n    Flux\u003cPeopleResponse\u003e listAll();\n}\n```\n\n**PeopleServiceImpl**\n```java\n@Service\n@RequiredArgsConstructor  // Lombok\npublic class PeopleServiceImpl implements PeopleService {\n\n    private final PeopleRepository peopleRepository;\n\n    @Override\n    public Mono\u003cPeopleResponse\u003e getById(int id) {\n        return peopleRepository.findById(id);\n    }\n\n    @Override\n    public Flux\u003cPeopleResponse\u003e listAll() {\n        return peopleRepository.findAll();\n    }\n}\n```\n\n**Responsabilidades:**\n- Orquestrar a lógica de negócio\n- Delegar para o repositório\n- Camada de abstração entre controller e infraestrutura\n\n#### 3. PeopleRepositoryImpl (`infrastructure/repository/PeopleRepositoryImpl.java`)\n\n```java\n@RequiredArgsConstructor  // Lombok\npublic class PeopleRepositoryImpl implements PeopleRepository {\n\n    private final PeopleServiceClient peopleClient;\n\n    @Override\n    public Mono\u003cPeopleResponse\u003e findById(int id) {\n        return peopleClient.getPeopleById(id);\n    }\n\n    @Override\n    public Flux\u003cPeopleResponse\u003e findAll() {\n        return peopleClient.listPeople();\n    }\n}\n```\n\n**Responsabilidades:**\n- Implementar a interface `PeopleRepository`\n- Delegar para o cliente gRPC\n- Abstrair a comunicação gRPC\n\n#### 4. PeopleServiceGrpcClientImpl (`infrastructure/client/PeopleServiceGrpcClientImpl.java`)\n\n```java\n@Component\n@RequiredArgsConstructor  // Lombok\npublic class PeopleServiceGrpcClientImpl implements PeopleServiceClient {\n\n    @GrpcClient(\"people-service\")\n    private PeopleServiceGrpc.PeopleServiceBlockingStub peopleServiceStub;\n\n    private final PeopleGrpcMapper peopleGrpcMapper;  // MapStruct!\n\n    @Override\n    public Mono\u003cPeopleResponse\u003e getPeopleById(int id) {\n        return Mono.fromCallable(() -\u003e {\n            ServiceProto.PeopleRequestGrpc request =\n                ServiceProto.PeopleRequestGrpc.newBuilder()\n                    .setId(id)\n                    .build();\n\n            ServiceProto.PeopleResponseGrpc response =\n                peopleServiceStub.getPeople(request);\n\n            return peopleGrpcMapper.toPeopleResponse(response);  // MapStruct\n        })\n        .subscribeOn(Schedulers.boundedElastic());\n    }\n}\n```\n\n**Responsabilidades:**\n- Implementar a interface `PeopleServiceClient`\n- Realizar chamadas gRPC para o People Service\n- Converter chamadas bloqueantes em streams reativos (Mono/Flux)\n- Mapear protobuf messages para DTOs usando **MapStruct**\n\n#### 5. PeopleGrpcMapper (`infrastructure/client/PeopleGrpcMapper.java`)\n\n```java\n@Mapper(\n    componentModel = \"spring\",\n    implementationName = \"PeopleGrpcMapperImpl\"\n)\npublic interface PeopleGrpcMapper {\n\n    @Mapping(target = \"id\", source = \"id\")\n    @Mapping(target = \"name\", source = \"name\")\n    @Mapping(target = \"email\", source = \"email\")\n    PeopleResponse toPeopleResponse(ServiceProto.PeopleResponseGrpc response);\n}\n```\n\n**Responsabilidades:**\n- Mapeamento **type-safe** de gRPC Proto para DTO\n- Geração de código em tempo de compilação via MapStruct\n- Integração com Spring via `componentModel = \"spring\"`\n\n### Configuração (`application.yml`)\n\n```yaml\nserver:\n  port: 8081\n\nspring:\n  application:\n    name: api\n\ngrpc:\n  client:\n    people-service:\n      address: 'static://127.0.0.1:9090'\n      negotiationType: PLAINTEXT\n      enable-keep-alive: true\n      keep-alive-without-calls: true\n      max-inbound-message-size: 4194304  # 4 MB\n```\n\n---\n\n## People Service\n\n### Estrutura do Projeto\n\n```\npeople/\n├── src/main/java/org/people/\n│   ├── PeopleApplication.java\n│   ├── domain/\n│   │   ├── client/\n│   │   │   └── PeopleClient.java (Interface)\n│   │   ├── entity/\n│   │   │   └── People.java\n│   │   ├── enums/\n│   │   │   └── DataSource.java\n│   │   ├── exception/\n│   │   │   ├── PeopleException.java\n│   │   │   ├── BusinessRuleException.java\n│   │   │   ├── ValidationException.java\n│   │   │   └── PeopleNotFoundException.java\n│   │   └── repository/\n│   │       └── PeopleRepository.java (Interface)\n│   ├── application/\n│   │   ├── dto/\n│   │   │   └── PeopleResponse.java\n│   │   └── service/\n│   │       ├── PeopleService.java (Interface)\n│   │       └── PeopleServiceImpl.java\n│   └── infrastructure/\n│       ├── entrypoint/\n│       │   └── grpc/\n│       │       └── PeopleServiceGrpcImpl.java\n│       ├── client/\n│       │   ├── typicode/\n│       │   │   ├── TypiCodeClientImpl.java\n│       │   │   ├── TypiCodeResponse.java\n│       │   │   └── TypiCodeMapper.java (MapStruct)\n│       │   └── dummy/\n│       │       ├── DummyClientImpl.java\n│       │       ├── DummyResponse.java\n│       │       ├── DummyListResponse.java\n│       │       └── DummyMapper.java (MapStruct)\n│       ├── repository/\n│       │   └── PeopleRepositoryImpl.java (Strategy Pattern)\n│       ├── exception/\n│       │   ├── GlobalGrpcExceptionHandler.java\n│       │   ├── ExternalServiceException.java\n│       │   └── InternalServerException.java\n│       ├── logging/\n│       │   ├── Logger.java\n│       │   ├── LogContext.java\n│       │   ├── RequestContext.java\n│       │   └── GrpcLoggingInterceptor.java\n│       └── config/\n│           ├── RepositoryConfig.java\n│           └── client/\n│               ├── TypiCodeClientConfig.java\n│               └── DummyClientConfig.java\n├── src/main/proto/\n│   └── person.proto\n└── src/main/resources/\n    └── application.yml\n```\n\n### Componentes Principais\n\n#### 1. PeopleServiceGrpcImpl (`infrastructure/entrypoint/grpc/PeopleServiceGrpcImpl.java`)\n\n```java\n@GrpcService\n@RequiredArgsConstructor  // Lombok\npublic class PeopleServiceGrpcImpl extends ReactorPeopleServiceGrpc.PeopleServiceImplBase {\n\n    private final PeopleService peopleService;  // Interface!\n\n    @Override\n    public Mono\u003cPeopleResponseGrpc\u003e getPeople(Mono\u003cPeopleRequestGrpc\u003e request) {\n        return request\n            .flatMap(req -\u003e peopleService.getById(req.getId()))\n            .map(people -\u003e PeopleResponseGrpc.newBuilder()\n                .setId(people.getId())\n                .setName(people.getName())\n                .setEmail(people.getEmail())\n                .build());\n    }\n\n    @Override\n    public Mono\u003cListPeopleResponseGrpc\u003e listPeople(Mono\u003cListPeopleRequestGrpc\u003e request) {\n        return request\n            .flatMapMany(req -\u003e peopleService.listAll())\n            .map(people -\u003e PeopleResponseGrpc.newBuilder()\n                .setId(people.getId())\n                .setName(people.getName())\n                .setEmail(people.getEmail())\n                .build())\n            .collectList()\n            .map(peopleList -\u003e ListPeopleResponseGrpc.newBuilder()\n                .addAllPeople(peopleList)\n                .build());\n    }\n}\n```\n\n**Responsabilidades:**\n- Expor serviços gRPC reativos\n- Receber requisições gRPC do API Service\n- Delegar para o serviço de aplicação\n- Mapear DTOs para protobuf messages\n- **Inversão de Dependência:** Injeta interface `PeopleService`, não implementação\n\n#### 2. PeopleService (`application/service/`)\n\n**PeopleService (Interface)**\n```java\npublic interface PeopleService {\n    Mono\u003cPeopleResponse\u003e getById(Integer id);\n    Flux\u003cPeopleResponse\u003e listAll();\n}\n```\n\n**PeopleServiceImpl**\n```java\n@Service\n@RequiredArgsConstructor  // Lombok\npublic class PeopleServiceImpl implements PeopleService {\n\n    private final PeopleRepository peopleRepository;\n\n    @Override\n    public Mono\u003cPeopleResponse\u003e getById(Integer id) {\n        return peopleRepository.findById(id);\n    }\n\n    @Override\n    public Flux\u003cPeopleResponse\u003e listAll() {\n        return peopleRepository.findAll();\n    }\n}\n```\n\n**Responsabilidades:**\n- Orquestrar a lógica de negócio\n- Delegar para o repositório\n- Camada de abstração entre gRPC service e infraestrutura\n\n#### 3. PeopleRepositoryImpl (`infrastructure/repository/PeopleRepositoryImpl.java`)\n\n```java\n@RequiredArgsConstructor  // Lombok\npublic class PeopleRepositoryImpl implements PeopleRepository {\n\n    private final Map\u003cDataSource, PeopleClient\u003e clientStrategies;\n    private final DataSource activeDataSource;\n\n    @Override\n    public Mono\u003cPeopleResponse\u003e findById(Integer id) {\n        return getActiveClient().getPeopleById(id);\n    }\n\n    @Override\n    public Flux\u003cPeopleResponse\u003e findAll() {\n        return getActiveClient().listPeople();\n    }\n\n    private PeopleClient getActiveClient() {\n        return clientStrategies.get(activeDataSource);\n    }\n}\n```\n\n**Responsabilidades:**\n- Implementar o padrão **Strategy** para seleção dinâmica de fonte de dados\n- Gerenciar múltiplas implementações de PeopleClient (TypiCode, Dummy)\n- Rotear requisições para a API externa configurada via `client.active-datasource`\n- Abstrair a complexidade de múltiplas APIs para o serviço\n\n**Configuração (RepositoryConfig.java):**\n```java\n@Configuration\npublic class RepositoryConfig {\n\n    @Bean\n    public PeopleRepository peopleRepository(\n            TypiCodeClientImpl typiCodeClient,\n            DummyClientImpl dummyClient,\n            @Value(\"${client.active-datasource:TYPICODE}\") String activeDataSourceStr) {\n\n        Map\u003cDataSource, PeopleClient\u003e clientStrategies = new HashMap\u003c\u003e();\n        clientStrategies.put(DataSource.TYPICODE, typiCodeClient);\n        clientStrategies.put(DataSource.DUMMY, dummyClient);\n\n        DataSource activeDataSource = DataSource.valueOf(activeDataSourceStr.toUpperCase());\n\n        return new PeopleRepositoryImpl(clientStrategies, activeDataSource);\n    }\n}\n```\n\nA fonte de dados ativa é configurada no `application.yml`:\n```yaml\nclient:\n  active-datasource: DUMMY  # ou TYPICODE\n```\n\n#### 4. TypiCodeClientImpl (`infrastructure/client/typicode/TypiCodeClientImpl.java`)\n\n```java\n@Component\n@RequiredArgsConstructor  // Lombok\npublic class TypiCodeClientImpl implements PeopleClient {\n\n    @Qualifier(\"typiCodeWebClient\")\n    private final WebClient typiCodeWebClient;\n\n    private final TypiCodeMapper mapper;  // MapStruct\n\n    @Override\n    public Mono\u003cPeopleResponse\u003e getPeopleById(Integer id) {\n        return typiCodeWebClient\n            .get()\n            .uri(\"/users/{id}\", id)\n            .retrieve()\n            .bodyToMono(TypiCodeResponse.class)\n            .map(mapper::toPeopleResponse);  // MapStruct\n    }\n\n    @Override\n    public Flux\u003cPeopleResponse\u003e listPeople() {\n        return typiCodeWebClient\n            .get()\n            .uri(\"/users\")\n            .retrieve()\n            .bodyToFlux(TypiCodeResponse.class)\n            .map(mapper::toPeopleResponse);  // MapStruct\n    }\n}\n```\n\n**Responsabilidades:**\n- Implementar a interface PeopleClient para JSONPlaceholder API\n- Realizar chamadas HTTP reativas para `https://jsonplaceholder.typicode.com`\n- Mapear respostas JSON para DTOs usando **MapStruct**\n- Tratamento de erros reativo\n\n**API Externa:** [JSONPlaceholder](https://jsonplaceholder.typicode.com/)\n\n#### 5. TypiCodeMapper (`infrastructure/client/typicode/TypiCodeMapper.java`)\n\n```java\n@Mapper(\n    componentModel = \"spring\",\n    implementationName = \"TypiCodeMapperImpl\"\n)\npublic interface TypiCodeMapper {\n\n    @Mapping(target = \"id\", source = \"id\")\n    @Mapping(target = \"name\", source = \"name\")\n    @Mapping(target = \"email\", source = \"email\")\n    PeopleResponse toPeopleResponse(TypiCodeResponse response);\n}\n```\n\n**Responsabilidades:**\n- Mapeamento **type-safe** de campos da API JSONPlaceholder\n- Geração de código em tempo de compilação via MapStruct\n\n#### 6. DummyClientImpl (`infrastructure/client/dummy/DummyClientImpl.java`)\n\n```java\n@Component\n@RequiredArgsConstructor  // Lombok\npublic class DummyClientImpl implements PeopleClient {\n\n    @Qualifier(\"dummyWebClient\")\n    private final WebClient dummyWebClient;\n\n    private final DummyMapper mapper;  // MapStruct\n\n    @Override\n    public Mono\u003cPeopleResponse\u003e getPeopleById(Integer id) {\n        return dummyWebClient\n            .get()\n            .uri(\"/users/{id}\", id)\n            .retrieve()\n            .bodyToMono(DummyResponse.class)\n            .map(mapper::toPeopleResponse);  // MapStruct\n    }\n\n    @Override\n    public Flux\u003cPeopleResponse\u003e listPeople() {\n        return dummyWebClient\n            .get()\n            .uri(\"/users\")\n            .retrieve()\n            .bodyToMono(DummyListResponse.class)\n            .flatMapMany(response -\u003e Flux.fromIterable(response.users()))\n            .map(mapper::toPeopleResponse);  // MapStruct\n    }\n}\n```\n\n**Responsabilidades:**\n- Implementar a interface PeopleClient para DummyJSON API\n- Realizar chamadas HTTP reativas para `https://dummyjson.com`\n- Mapear respostas JSON para DTOs usando **MapStruct**\n- Combinar firstName e lastName em um único campo name via MapStruct\n- Tratamento de erros reativo\n\n**API Externa:** [DummyJSON](https://dummyjson.com/)\n\n#### 7. DummyMapper (`infrastructure/client/dummy/DummyMapper.java`)\n\n```java\n@Mapper(\n    componentModel = \"spring\",\n    implementationName = \"DummyMapperImpl\"\n)\npublic interface DummyMapper {\n\n    @Mapping(target = \"name\",\n        expression = \"java(response.firstName() + \\\" \\\" + response.lastName())\")\n    @Mapping(target = \"email\", source = \"email\")\n    @Mapping(target = \"id\", source = \"id\")\n    PeopleResponse toPeopleResponse(DummyResponse response);\n}\n```\n\n**Responsabilidades:**\n- Mapeamento **customizado** da API DummyJSON\n- Combinar campos `firstName` e `lastName` em `name` via expressão Java\n- Geração de código em tempo de compilação via MapStruct\n\n### Configuração (`application.yml`)\n\n```yaml\nspring:\n  application:\n    name: people\n\ngrpc:\n  server:\n    port: 9090\n\nclient:\n  active-datasource: TYPICODE  # Options: TYPICODE, DUMMY\n  typicode:\n    base-url: https://jsonplaceholder.typicode.com\n  dummy:\n    base-url: https://dummyjson.com\n```\n\n### APIs Externas Suportadas\n\nO People Service suporta múltiplas APIs externas através do padrão **Strategy**, permitindo trocar facilmente a fonte de dados via configuração.\n\n#### JSONPlaceholder (TYPICODE)\n\n**URL Base:** `https://jsonplaceholder.typicode.com`\n\n**Endpoints utilizados:**\n- `GET /users/{id}` - Buscar usuário por ID\n- `GET /users` - Listar todos os usuários\n\n**Estrutura de resposta:**\n```json\n{\n  \"id\": 1,\n  \"name\": \"Leanne Graham\",\n  \"email\": \"Sincere@april.biz\",\n  \"username\": \"Bret\",\n  \"address\": { ... },\n  \"phone\": \"1-770-736-8031 x56442\",\n  \"website\": \"hildegard.org\",\n  \"company\": { ... }\n}\n```\n\n**Características:**\n- API gratuita e pública para testes\n- 10 usuários disponíveis\n- Campos diretamente mapeados (id, name, email)\n\n#### DummyJSON (DUMMY)\n\n**URL Base:** `https://dummyjson.com`\n\n**Endpoints utilizados:**\n- `GET /users/{id}` - Buscar usuário por ID\n- `GET /users` - Listar todos os usuários\n\n**Estrutura de resposta:**\n```json\n{\n  \"id\": 1,\n  \"firstName\": \"Emily\",\n  \"lastName\": \"Johnson\",\n  \"email\": \"emily.johnson@x.dummyjson.com\",\n  \"phone\": \"+81 965-431-3024\",\n  \"username\": \"emilys\",\n  \"birthDate\": \"1996-5-30\",\n  \"image\": \"https://dummyjson.com/icon/emilys/128\",\n  ...\n}\n```\n\n**Características:**\n- API gratuita com dados realistas\n- Maior quantidade de usuários disponíveis\n- Requer mapeamento customizado (firstName + lastName → name)\n\n#### Seleção de Fonte de Dados\n\nA seleção é feita através da propriedade `client.active-datasource`:\n\n```yaml\n# Para usar JSONPlaceholder\nclient:\n  active-datasource: TYPICODE\n\n# Para usar DummyJSON\nclient:\n  active-datasource: DUMMY\n```\n\nO padrão Strategy permite adicionar novas APIs externas facilmente, bastando:\n1. Criar uma nova implementação de `PeopleClient`\n2. Criar um `Mapper` MapStruct para conversão de respostas\n3. Adicionar um novo valor no enum `DataSource`\n4. Registrar o client no `RepositoryConfig.java`\n5. Configurar a URL base no `application.yml`\n\n---\n\n## Estrutura Maven\n\nO projeto utiliza uma estrutura **Maven Multi-Module** para facilitar o build e o gerenciamento de dependências.\n\n### POM Parent/Aggregator\n\nNa raiz do projeto, existe um `pom.xml` que funciona como **aggregator**, gerenciando os módulos:\n\n```xml\n\u003cgroupId\u003eorg\u003c/groupId\u003e\n\u003cartifactId\u003ebridge\u003c/artifactId\u003e\n\u003cversion\u003e1.0-SNAPSHOT\u003c/version\u003e\n\u003cpackaging\u003epom\u003c/packaging\u003e\n\n\u003cmodules\u003e\n    \u003cmodule\u003eapi\u003c/module\u003e\n    \u003cmodule\u003epeople\u003c/module\u003e\n\u003c/modules\u003e\n```\n\n**Benefícios:**\n- **Build unificado**: `mvn clean install` na raiz compila ambos os serviços\n- **Gerenciamento centralizado**: Versões e configurações podem ser compartilhadas\n- **Ordem de build**: Maven resolve automaticamente a ordem de compilação dos módulos\n\n---\n\n## Configuração e Execução\n\n### Pré-requisitos\n\n- Java 21+\n- Maven 3.6+\n- Conexão com a internet (para acessar JSONPlaceholder)\n\n### Compilação\n\nNa raiz do projeto:\n\n```bash\n# Compilar todos os módulos\nmvn clean install\n\n# Ou compilar individualmente\ncd people\nmvn clean install\n\ncd ../api\nmvn clean install\n```\n\n### Executar os Serviços\n\n**Importante:** O People Service deve ser iniciado ANTES do API Service.\n\n#### 1. Iniciar o People Service\n\n```bash\ncd people\nmvn spring-boot:run\n```\n\nO serviço estará disponível em:\n- gRPC Server: `localhost:9090`\n\n#### 2. Iniciar o API Service\n\n```bash\ncd api\nmvn spring-boot:run\n```\n\nO serviço estará disponível em:\n- REST API: `http://localhost:8081`\n\n### Verificar a Saúde dos Serviços\n\n```bash\n# Verificar People Service (via API Service)\ncurl http://localhost:8081/api/peoples/1\n\n# Listar todas as pessoas\ncurl http://localhost:8081/api/peoples\n```\n\n---\n\n## Endpoints Disponíveis\n\n### API Service (REST)\n\n#### GET /api/peoples/{id}\n\nBusca uma pessoa por ID.\n\n**Request:**\n```http\nGET http://localhost:8081/api/peoples/1\n```\n\n**Response:**\n```json\n{\n  \"id\": 1,\n  \"name\": \"Leanne Graham\",\n  \"email\": \"Sincere@april.biz\"\n}\n```\n\n**Status Codes:**\n- `200 OK`: Pessoa encontrada\n- `500 Internal Server Error`: Erro ao buscar pessoa\n\n---\n\n#### GET /api/peoples\n\nLista todas as pessoas.\n\n**Request:**\n```http\nGET http://localhost:8081/api/peoples\n```\n\n**Response:**\n```json\n[\n  {\n    \"id\": 1,\n    \"name\": \"Leanne Graham\",\n    \"email\": \"Sincere@april.biz\"\n  },\n  {\n    \"id\": 2,\n    \"name\": \"Ervin Howell\",\n    \"email\": \"Shanna@melissa.tv\"\n  }\n]\n```\n\n**Status Codes:**\n- `200 OK`: Lista retornada com sucesso\n- `500 Internal Server Error`: Erro ao listar pessoas\n\n---\n\n## Tratamento de Erros\n\n### API Service\n\nErros são propagados do People Service para o API Service e retornados como HTTP 500.\n\n### People Service\n\nO People Service possui um sistema robusto de tratamento de exceções:\n\n**Hierarquia de Exceções:**\n\n```\nPeopleException (Base)\n├── BusinessRuleException (Regras de negócio)\n├── ValidationException (Validações)\n└── PeopleNotFoundException (Recurso não encontrado)\n\nInfrastructure Exceptions\n├── ExternalServiceException (Erros de serviços externos)\n└── InternalServerException (Erros internos do servidor)\n```\n\n**GlobalGrpcExceptionHandler:**\n- Intercepta todas as exceções dos serviços gRPC\n- Converte exceções de domínio em status codes gRPC apropriados\n- Adiciona contexto e mensagens de erro estruturadas\n- Registra erros no sistema de logging\n\n**Status Codes gRPC Retornados:**\n- `NOT_FOUND`: Quando recurso não é encontrado\n- `INVALID_ARGUMENT`: Para erros de validação\n- `FAILED_PRECONDITION`: Para violações de regras de negócio\n- `UNAVAILABLE`: Quando serviços externos estão indisponíveis\n- `INTERNAL`: Para erros internos não esperados\n\n---\n\n## Observabilidade\n\n### Logs Importantes\n\n**API Service:**\n- Requisições HTTP recebidas\n- Chamadas gRPC realizadas\n- Erros de comunicação\n\n**People Service:**\n- Requisições gRPC recebidas\n- Chamadas HTTP para JSONPlaceholder\n- Erros de integração\n\n### Logging Estruturado (People Service)\n\nO People Service implementa logging estruturado usando **Logstash Logback Encoder**:\n\n**Componentes:**\n- **Logger**: Facade customizado para logging estruturado\n- **LogContext**: Contexto de log com dados da requisição\n- **RequestContext**: Armazena informações de contexto da requisição\n- **GrpcLoggingInterceptor**: Interceptor gRPC para log automático de requisições\n\n**Benefícios:**\n- Logs em formato JSON para fácil parsing\n- Rastreabilidade de requisições com correlation IDs\n- Integração com ferramentas de agregação de logs (ELK Stack, Datadog)\n\n### Monitoramento e Observabilidade\n\n**People Service** possui integração com:\n- **Datadog APM**: Trace distribuído e métricas de aplicação\n- **Logstash**: Logs estruturados em JSON\n- **gRPC Server Reflection**: Introspecção de serviços gRPC\n\n**Ambos os serviços** suportam:\n- Spring Boot Actuator (pode ser adicionado)\n- Métricas Micrometer\n- Health checks\n\n---\n\n## Considerações de Segurança\n\n### Configuração Atual\n\n- **Comunicação gRPC**: PLAINTEXT (sem TLS)\n- **Comunicação HTTP**: Sem autenticação\n\n### Recomendações para Produção\n\n1. Habilitar TLS/SSL para gRPC\n2. Implementar autenticação/autorização (JWT, OAuth2)\n3. Configurar rate limiting\n4. Adicionar circuit breakers (Resilience4j)\n5. Implementar timeouts apropriados\n6. Validar inputs\n\n---\n\n## Próximos Passos\n\n- [ ] Adicionar testes de integração\n- [ ] Implementar circuit breaker para chamadas externas\n- [ ] Adicionar autenticação e autorização\n- [ ] Configurar TLS para gRPC\n- [ ] Adicionar métricas e tracing distribuído\n- [ ] Implementar cache para reduzir chamadas à API externa\n- [ ] Adicionar documentação OpenAPI/Swagger para REST API\n- [ ] Configurar Docker e Docker Compose\n- [ ] Implementar health checks\n\n---\n\n## Referências\n\n### Frameworks e Tecnologias\n- [gRPC Documentation](https://grpc.io/docs/)\n- [Protocol Buffers](https://developers.google.com/protocol-buffers)\n- [Spring WebFlux](https://docs.spring.io/spring-framework/reference/web/webflux.html)\n- [Project Reactor](https://projectreactor.io/docs)\n- [MapStruct](https://mapstruct.org/)\n\n### APIs Externas\n- [JSONPlaceholder API](https://jsonplaceholder.typicode.com/) - API de teste com dados fake\n- [DummyJSON API](https://dummyjson.com/) - API de teste com dados realistas\n\n\u003chr /\u003e\n\n\u003cdiv\u003e\n  \u003csub\u003eConteúdo criado por \u003ca href=\"https://github.com/eneas-almeida\"\u003eEnéas Almeida\u003c/a\u003e\u003c/sub\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feneas-almeida%2Fbridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feneas-almeida%2Fbridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feneas-almeida%2Fbridge/lists"}