Skip to main content

Documentation Index

Fetch the complete documentation index at: https://doc.fluximmo.io/llms.txt

Use this file to discover all available pages before exploring further.

Goal

Maintenir une copie locale (PostgreSQL/MySQL/ClickHouse) de toutes les annonces (adverts) sur un périmètre donné, synchronisée en continu sur votre webhook : alerte ADVERT pour le flux post-création + demande de backfill historique pour rattraper le passé.

Scénario

Vous êtes un agrégateur, une marketplace, ou un éditeur data immobilier qui veut :
  • requêter sa BDD locale sans appeler Fluximmo à chaque page vue (latence + coût) ;
  • enrichir les annonces avec ses propres champs (scoring, tags internes, attribution commerciale) ;
  • conserver un historique de prix et de cycle de vie indépendant des sources amont ;
  • reconstruire la vue Property côté client si besoin, en groupant les adverts par propertyFlxId.
L’objectif est d’avoir, à tout instant, la BDD locale en miroir de Fluximmo sur le périmètre choisi, avec un retard < 1 minute sur le flux courant.

Étapes

1

1. Choisir Adverts plutôt que Properties

Pour un cas réplication, adverts est toujours le bon choix :
  • Payload webhook complet : l’objet advert entier est livré dans le webhook, pas uniquement un flxId. Pas besoin de re-fetcher.
  • Suivi inter-portails : un même bien apparaissant sur SeLoger + LeBonCoin = 2 adverts liés au même propertyFlxId.
  • Events : PRICE, REPUBLISHED, UNPUBLISHED sont émis sur l’advert (pas sur la property).
  • Reconstitution Property côté DB : grouper les adverts par propertyFlxId permet de retrouver une vue dédupliquée localement.
Voir Property vs Advert pour les détails.
2

2. Préparer le schéma de table locale

CREATE TABLE adverts (
  flx_id           TEXT PRIMARY KEY,
  property_id      TEXT NOT NULL,           -- racine de la chaîne de dédup
  raw_payload      JSONB NOT NULL,
  price            INTEGER,
  last_modified_at TIMESTAMPTZ NOT NULL,
  is_online        BOOLEAN NOT NULL DEFAULT TRUE,
  unpublished_at   TIMESTAMPTZ,
  created_at       TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at       TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_adverts_property ON adverts(property_id);
CREATE INDEX idx_adverts_last_mod ON adverts(last_modified_at);

CREATE TABLE advert_price_history (
  id          BIGSERIAL PRIMARY KEY,
  flx_id      TEXT NOT NULL REFERENCES adverts(flx_id),
  price       INTEGER NOT NULL,
  observed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
L’index idx_adverts_property est ce qui permettra la reconstitution de la vue Property à l’étape 6.
3

3. Demander l'activation de l'alerte ADVERT (création par Fluximmo)

La création d’alertes ADVERT sur webhook se fait sur demande par mail. Écrivez à [email protected] en précisant :
  • Votre clientId
  • Le webhook_url cible (HTTPS public, doit ack en < 1 s)
  • Les filtres souhaités (par exemple : département 75, achat appartement, isOnline: true)
  • Les types de match désirés : ALERT_MATCH_CREATED + ALERT_MATCH_ADVERT_EVENT (créations + events PRICE/REPUBLISHED/UNPUBLISHED)
  • Le volume estimé que votre receiver peut absorber
Une fois l’alerte créée, vous recevez son flxId pour la modifier ultérieurement (en PATCH, jamais en DELETE + recréation).
4

4. Demander le backfill historique sur le même webhook

L’alerte ne fait pas de backfill automatique : elle ne match que les adverts ingérées après sa création. Pour rattraper le passé, écrivez à nouveau à [email protected] en précisant :
  • Le flxId de l’alerte créée à l’étape 3
  • La période de backfill (ex. derniers 30 jours, 6 mois, 2 ans)
  • Le volume estimé que votre receiver peut absorber pendant la rejouage
Le backfill est rejoué sur votre webhook avec le même format de payload que les matches normaux. Votre handler le traite sans changement de code, idempotence via advert.flxId.
5

5. Endpoint webhook : ACK rapide + queue

Le crawler Fluximmo attend un 200 rapide (< 1 s). Toute logique métier doit être différée dans une queue (SQS / RabbitMQ / Redis Streams).
# Pseudocode handler
on POST /webhooks/fluximmo:
    if header.x-webhook-key != EXPECTED_KEY: return 401
    enqueue(request.body)            # SQS, RabbitMQ, Redis Streams
    return 200
6

6. Worker async : UPSERT + diff + reconstitution Property

Le webhook a la shape canonique { data: { created, updated } } :
  • data.created[].adverts[] = AdvertDto complet → UPSERT total côté DB
  • data.updated[].adverts[] = DTO réduit (flxId, currentPrice, isOnline uniquement) → UPDATE partiel + diff vs état stocké pour dériver les events PRICE / REPUBLISHED / UNPUBLISHED
# Pseudocode worker
handle_payload(body):
    # Branche CREATED — AdvertDto complet
    for entry in body.data.created or []:
        for advert in entry.adverts:
            UPSERT INTO adverts (flx_id, property_id, raw_payload, price, last_modified_at, is_online)
                   VALUES (advert.flxId, advert.propertyFlxId, advert, advert.currentPrice.value,
                           advert.lastModifiedAt, advert.isOnline)
            INSERT INTO advert_price_history (flx_id, price, source) VALUES (advert.flxId, advert.currentPrice.value, 'CREATED')

    # Branche UPDATED — DTO réduit, events dérivés client-side
    for entry in body.data.updated or []:
        for advert in entry.adverts:
            prev = SELECT price, is_online FROM adverts WHERE flx_id = advert.flxId
            new_price  = advert.currentPrice.value
            new_online = advert.isOnline

            if prev is None:
                # advert pas en miroir local : log + ignorer (ou alerter pour reconciliation)
                continue

            UPDATE adverts SET price = new_price, is_online = new_online, updated_at = NOW()
                   WHERE flx_id = advert.flxId

            if new_price != prev.price:
                INSERT INTO advert_price_history (flx_id, price, source) VALUES (advert.flxId, new_price, 'PRICE_DERIVED')
            if new_online and not prev.is_online:
                UPDATE adverts SET unpublished_at = NULL WHERE flx_id = advert.flxId
            if not new_online and prev.is_online:
                UPDATE adverts SET unpublished_at = NOW() WHERE flx_id = advert.flxId
Reconstitution de la vue Property côté DB — quand vous voulez interroger votre miroir comme si c’était /properties :
-- Une "Property" = ensemble d'adverts partageant le même property_id
SELECT
  property_id,
  count(*) AS sources_count,
  min(last_modified_at) AS first_seen_at,
  max(last_modified_at) AS last_modified_at,
  bool_or(is_online) AS has_any_online,
  -- prix médian sur les adverts encore en ligne
  percentile_cont(0.5) WITHIN GROUP (ORDER BY price) FILTER (WHERE is_online) AS median_price_online
FROM adverts
WHERE property_id IS NOT NULL
GROUP BY property_id;
7

7. Idempotence + reconciliation

Idempotence : Fluximmo livre parfois 2 fois le même webhook (retries sur timeout). L’UPSERT par flxId rend le worker safe par construction.Reconciliation : si vous suspectez une dérive (panne queue, bug worker, perte webhook), demandez à Fluximmo un nouveau backfill ciblé sur la fenêtre concernée (par mail à [email protected], en précisant la période).
8

8. Préserver l'historique alerte

En pratique : PATCH votre alerte plutôt que DELETE + recréation, pour conserver le lien historique et continuer à recevoir des events sur les adverts déjà matchées.

Architecture / flow

Pièges fréquents

Properties au lieu de Adverts : le webhook properties ne livre que des flxId, pas le payload complet, et n’émet pas d’events PRICE/REPUBLISHED/UNPUBLISHED. Mauvais choix pour une réplication marketplace.
Pas de backfill explicite : l’alerte ne backfille pas seule. Sans étape 4 (demande par mail), vous n’aurez que les annonces créées après la création de l’alerte — trou historique permanent.
Traitement synchrone dans le webhook : un endpoint qui fait INSERT puis 200 peut dépasser 1 s sous charge → timeouts → retries → effet de bord cumulatif. Toujours ACK d’abord, traiter ensuite (étape 5).
Pas d’idempotence : sans UPSERT par flxId, les retries du crawler créent des doublons en BDD locale.
DELETE + recréer l’alerte = perte des events historiques. Toujours PATCH /alerts/{flxId} pour modifier en place.

Pour aller plus loin