🌍 OpenCage Geocoding (endereço → lat/lng)
Documentação KOLOS

🌍 OpenCage Geocoding (endereço → lat/lng)

🎯 Contexto

O onboarding do Player (e a criação de Venue) já aceita latitude/longitude via GPS do navegador, mas nem sempre o usuário permite localização. Precisamos de um fallback confiável para obter coordenadas a partir do endereço, sem expor a chave da API no frontend.

✅ Decisão

  • Usar OpenCage para forward geocoding (endereço → latitude/longitude).
  • Preferência sempre para GPS; OpenCage entra apenas quando lat/lng não forem informados.
  • Implementar no backend com cache para respeitar rate-limit e reduzir custo.
  • Ativar no_record=1 por padrão (privacidade), com opção via .env.

🧩 Implementação

  • Configuração:
    • OPENCAGE_API_KEY via .env
    • config/services.php adiciona services.opencage.*
  • Persistência/cache:
    • Nova tabela geocoding_cache_entries guarda resultados por provider + query_hash (consulta no DB antes de chamar o provedor externo)
    • Privacidade: com OPENCAGE_NO_RECORD=true, o texto do endereço não é persistido
  • Client:
    • Kolos\Shared\Infrastructure\OpenCage\OpenCageGeocodingClient
    • Request para https://api.opencagedata.com/geocode/v1/json com:
      • q (query montada do endereço)
      • limit=1
      • countrycode=br
      • language=pt-BR
      • no_annotations=1
      • no_record=1 (configurável)
    • Cache DB-first em geocoding_cache_entries por hash da query normalizada (consulta o banco antes; só chama OpenCage se não houver cadastro)
  • Fallback aplicado em:
    • RegisterPlayerOnboardingAction (Player)
    • CreateVenueAction (Venue)

▶️ Passos (Sail)

  • Configure a chave no .env:
    • OPENCAGE_API_KEY=...
  • Rode as migrations:
    • sail artisan migrate
  • Rode a suíte:
    • sail artisan test

🧪 Validação

  • Teste automático garante que quando latitude/longitude chegam como null, o sistema chama OpenCage e persiste as coordenadas.
  • Teste adicional garante que a segunda consulta igual não faz nova chamada HTTP (usa o cache no banco).
  • Cenário manual: negar permissão de localização no navegador e completar o cadastro com CEP/endereço.

📌 Impacto

  • Alterados:
    • config/services.php
    • src/Modules/Player/Actions/RegisterPlayerOnboardingAction.php
    • src/Modules/Venue/Actions/CreateVenueAction.php
    • .env.example
    • tests/Feature/Onboarding/RegisterPlayerOnboardingActionTest.php
  • Novos:
    • database/migrations/2026_01_18_120000_create_geocoding_cache_entries_table.php
    • src/Shared/Infrastructure/OpenCage/OpenCageGeocodingClient.php
    • src/Shared/Infrastructure/Geocoding/Models/GeocodingCacheEntry.php
    • src/Shared/DTOs/GeocodedPointData.php
    • tests/Feature/Shared/OpenCageGeocodingClientTest.php