Opplook
Acceso anticipado

Cómo está construido Opplook.

Opplook ayuda a agencias y freelancers a decidir a qué negocios locales contactar y con qué argumentos. Lo construyo yo solo, Israel Pereira, desde enero de 2026, y todavía está en desarrollo.

El repositorio es privado, así que aquí enseño la arquitectura y las decisiones, incluido lo que aún no está hecho.

Ver el producto

En desarrollo · Proyecto en solitario

tests en 39 archivos
~550
señales de puntuación
17
jobs de CI
5
migraciones
26

47 commits entre el 7 de enero y el 8 de octubre de 2026.

Stack

API en Laravel, pensada para que cualquier frontend la consuma.

Backend
PHP ^8.4, Laravel ^13.0, Sanctum ^4.3 (Bearer). API-first.
Frontend
Separado en otro repositorio. El anterior (Angular 18) está archivado; hay uno nuevo planificado.
Datos y colas
MySQL en producción, SQLite en tests. Cola con driver database (Redis planificado, sin hacer).
Servicios externos
Stripe (con cliente propio, StripeApiClient), Google Places API (New), Nominatim / OpenStreetMap.
Testing
PHPUnit ^12.5, Paratest y Mockery.
Análisis estático
Larastan nivel 6 sobre app, config, database y routes con baseline, y phpstan-strict.neon nivel 8 sobre los directorios nuevos. phpat para reglas de arquitectura. Laravel Pint.

Arquitectura

Un job orquesta el pipeline de búsqueda y cada paso externo queda detrás de un contrato.

ProcessSearchJobUn job encadena todo el pipeline de búsqueda.
  1. 1

    Geocodificar la zona

    Nominatim / OpenStreetMap convierte la zona en coordenadas.

    GeocodingInterface

  2. 2

    Buscar negocios

    Google Places API (New) devuelve los negocios de la zona.

    GooglePlacesInterface

  3. 3

    Elegibilidad · capa 1

    Lista de tipos de lugar bloqueados y rechazo de dominios públicos (.gov, .edu).

    BusinessEligibilityService

  4. 4

    Relevancia · capa 2

    Relevancia del negocio según el sector que vende el usuario.

    SectorRelevanceService

  5. 5

    Puntuación

    17 señales ponderadas dan una puntuación de oportunidad de 0 a 100.

    SignalDetectorService

  6. 6

    Auditoría de la web

    HTTPS, viewport móvil, formulario, CTA, WhatsApp, analítica, plataforma, TTFB y SEO.

    WebAuditJob

Servicio externo, detrás de un contratoLógica propia

Contratos y gemelas fake

Cada servicio externo vive detrás de una interfaz y tiene una gemela fake. Un flag de configuración decide cuál se enlaza en el service provider.

  • GeocodingInterface

    Nominatim / OpenStreetMap · gemela Fake*

  • GooglePlacesInterface

    Google Places API (New) · gemela Fake*

  • WebAuditInterface

    WebAuditService · gemela FakeWebAuditService

Capas de app/

  • Contracts
  • Providers
  • Services
  • Jobs
  • Models
  • Http/Controllers/Api
  • Domain (Shared, Billing)

Reglas de arquitectura con phpat: los controladores no dependen de infraestructura, HTTP ni base de datos.

Los errores de la API usan un envoltorio uniforme {success, code, message} (ApiErrorCode y ApiException). La auditoría web incluye también heurísticas para detectar píxeles de SEM y anuncios en redes, documentadas como tales: son aproximadas.

Motor de señales

Cada negocio recibe una puntuación de oportunidad de 0 a 100 a partir de señales ponderadas.

17 señales ponderadas

  • no_website
  • low_reviews
  • very_low_reviews
  • no_phone
  • low_rating
  • incomplete_profile
  • low_quality_website_url
  • no_https
  • no_mobile_viewport
  • no_contact_form
  • no_cta
  • no_whatsapp
  • no_analytics
  • website_platform_wix_or_free
  • too_many_reviews
  • high_rating
  • complete_profile

Los tres últimos, con borde discontinuo, son señales negativas o neutras: restan puntos o no suman.

Etiquetas y sub-puntuaciones

hot_opportunity
≥ 80
has_potential
≥ 60
needs_investigation
≥ 40
low_priority
< 40

Junto a la puntuación se calculan una visibility_score y una contact_readiness_score. Hay dos tablas de pesos, V1 y V2, detrás del flag SCORING_V2_ENABLED, con la misma forma de API.

Otros motores

  • ProfileFitService · encaje con lo que vende la agencia
  • ReasonToContactGenerator · motivo para contactar
  • ServiceRecommendationEngine · servicio recomendado
  • LeadQualityScorer · calidad del lead

Puertas de calidad y CI

Se ejecuta en cada push y en cada pull request. composer qa lanza lo mismo en local.

  1. 1

    Composer

    composer validate --strict y composer audit.

  2. 2

    Lint

    Pint y comprobación de TODOs.

  3. 3

    Stan

    Larastan con las dos configuraciones y un guard que impide que crezca el baseline.

  4. 4

    Tests · SQLite

    Suite completa en paralelo.

  5. 5

    Tests · MySQL

    Suite completa con migrate:fresh sobre MySQL.

  • Larastan nivel 6 con baseline, más nivel 8 estricto en el código nuevo.
  • Tests de arquitectura con phpat: los controladores no dependen de infraestructura, HTTP ni base de datos, ni llaman a HTTP o usan sleep directamente.
  • Http::preventStrayRequests() falla cualquier llamada HTTP sin simular.

Decisiones y por qué

Lo que cambié o fijé, y la razón.

  1. El giro del producto

    La propuesta del 14 de septiembre de 2026 cambió Opplook de listas de leads que se desbloqueaban con créditos a una herramienta de ventas por suscripción para agencias de marketing y diseño web y freelancers de España.

    El modelo anterior tenía el cliente equivocado, chocaba con las condiciones de Google Maps Platform (almacenar y exportar contenido de Places), era difícil de poner precio y no tenía puertas de calidad.

  2. Puertas de calidad antes que funciones

    La fase 0 fue Pint, Larastan, Paratest, CI y la subida a PHP 8.4 y Laravel 13. El código heredado tenía tests que fallaban y tests que llamaban a la red real, así que no se podía confiar en nada de lo que se construyera encima.

  3. Contratos y fakes para cada servicio externo

    Cada servicio externo (GooglePlacesInterface, GeocodingInterface, WebAuditInterface) tiene una gemela Fake* enlazada por configuración. Http::preventStrayRequests() hace fallar cualquier llamada HTTP no simulada en los tests: ninguna prueba toca la red por accidente.

    app/Providers/WebAuditServiceProvider.php
    $fakeMode = config('webaudit.fake_mode', false);$class = $fakeMode ? FakeWebAuditService::class : WebAuditService::class;$this->app->singleton(WebAuditInterface::class, $class);
  4. Scoring V2 detrás de un feature flag

    Las dos tablas de pesos, V1 y V2, conviven detrás de SCORING_V2_ENABLED y devuelven la misma forma de API. V2 sube el peso de los fallos detectados en la auditoría web, que son más fáciles de vender que un simple «no tiene web», sin cambiar el contrato.

    app/Services/SignalDetectorService.php
    'no_website' => 15,                      // Lowered: harder sell than web-audit gaps'no_https' => 30,                        // Raised: SSL upsell is easy + urgent'no_mobile_viewport' => 25,              // Raised: mobile-first is now a baseline requirement'no_analytics' => 22,                    // Raised: GA/GTM pitch — easy and recurring'no_whatsapp' => 18,                     // Raised: primary ES/LATAM contact channel// Señales NEGATIVAS (filtros) - RESTAN puntos'too_many_reviews' => -10,'high_rating' => -5,
  5. Idempotencia en la facturación

    Checkout y cancelación usan la cabecera X-Idempotency-Key, y los cambios de créditos pasan por un servicio de libro mayor (ledger). Un reintento no puede cobrar ni descontar dos veces.

  6. Una única fuente de verdad para los planes

    Planificado, no hecho: un archivo de configuración con una interfaz de repositorio y una instantánea de derechos por suscripción.

Hecho y planificado

Separado a propósito: lo que existe hoy y lo que todavía no.

Hecho

  • Autenticación con Sanctum.
  • Búsqueda geolocalizada con Nominatim y Google Places.
  • Filtro de elegibilidad y relevancia en dos capas.
  • Puntuación por señales V1/V2, sub-puntuaciones y etiquetas.
  • Auditoría web con heurísticas de SEO, SEM y anuncios en redes.
  • Encaje de perfil, motivo de contacto y recomendación de servicios.
  • Facturación con Stripe y webhooks.
  • CI y puertas de análisis estático.
  • Cambio de nombre a Opplook y envoltorio uniforme de errores por código.

Planificado, sin hacer

  • Workspaces y equipos.
  • Planes de suscripción.
  • Guiones y mensajes con IA (contrato LlmClient).
  • Informes white-label para compartir, con seguimiento de aperturas.
  • Pipeline.
  • Radar semanal de zonas.
  • Redis, Horizon y Sentry.
  • Nueva aplicación de frontend.
  • Retirar el código heredado de créditos, desbloqueo y exportación.

Esto es lo que hay detrás. Ahora, el producto.

Mira cómo se ve Opplook o pide acceso anticipado.