Skip to main content
Wildo.ai Coming soon

Events and external data

Use external records where your application needs them

Read records from their source or maintain a local copy, according to how the application needs to use them.

External records can be read directly or synchronized into a local copy with application-owned notes.

Use external records where your application needs them

Data can remain in its original system and be read when needed, or become a synchronized part of your application. Wildo supports both choices through resource declarations.

Read-through suits remote reference data. A local copy lets your application add its own fields, attachments and relationships, with freshness determined by the synchronization schedule.

Example — Keep customer accounts and local notes together

An application copies company accounts from Odoo, then lets its users add internal notes. A later synchronization updates the mapped account fields while the application retains the fields it owns.

For engineers

A virtual resource uses persistenceAdapter: HTTP_API with httpApiBinding. Its repository translates supported reads to the external system; ordinary writes are unavailable and it has no local row for extra fields or files. A pipeline declaration belongs to an ordinary local resource and populates that resource through the data-seeding engines.

Both use HttpApiReadClient for provider access, dialect framing and remote calls. A binding declares the provider reference, remote entity, key mapping, tenancy and erasure stance. Those are required semantic decisions, not optional labels.

This full pipeline block is selected from Wonder Todos’ external-customers.resources-config.ts; the surrounding resource factory and operation declarations are omitted:

  externalDataPipeline: {
    binding: {
      dialect: HttpApiTransportDialect.ODOO_JSONRPC,
      providerRef: 'odoo',
      entityRef: 'res.partner',
      keyFields: [{ localField: 'id', remoteField: 'id', codec: HttpApiKeyComponentCodec.INTEGER }],
      tenancy: {
        stance: HttpApiTenancyStance.SINGLE_TENANT_BINDING,
        justification: 'Wonder Todos serves one company, whose Odoo holds one client list; there is no per-tenant partition to push down.',
      },
      erasure: { stance: HttpApiErasureStance.NO_SUBJECT_DATA },
    },
    remoteKeyLocalField: 'odooPartnerRef',
    mapping: [
      { kind: ExternalDataMappingEntryKind.REMOTE_FIELD, remoteField: 'name', localField: 'name' },
      { kind: ExternalDataMappingEntryKind.REMOTE_FIELD, remoteField: 'email', localField: 'email' },
    ],
    // Only companies: Odoo's `res.partner` holds individuals too, and syncing them would make the
    // NO_SUBJECT_DATA erasure stance above false.
    sourceFilter: { is_company: true },
    population: ExternalDataDestinationPopulation.CLOSED,
    orphanPolicy: ExternalDataOrphanPolicy.REPORT,
    // Hourly. Client lists move at human speed, and every run is a round trip to someone else's
    // production system.
    scheduleCron: '0 * * * *',
  },

The closed population means the source supplies the records: this resource declares no caller create operation. Its local internalNote is editable, while imported fields exclude create/update input in the schema. The mapping owns only its declared fields. Register the schema, resource factory and relationships through the shared module, and configure the named provider’s backend access.

Treat synchronization as a population contract

remoteKeyLocalField holds a stable identity derived from the external binding. An extraction that reaches the source’s end selects sync reconciliation; a bounded pass selects upgrade reconciliation and persists its continuation. Reaching the end after resuming does not reconstruct the keys imported by earlier runs.

RequirementSuitable lane
Read the external response on demandVirtual read-through
Add local notes or filesLocal pipeline destination
Avoid remote latency on ordinary readsLocal pipeline destination
Keep no duplicated rowVirtual read-through

Keep REPORT for imports spanning several runs. The final resumed batch can classify earlier imported rows as absent because reconciliation receives that batch’s keys, not the accumulated population; reporting preserves those rows while you inspect the result. Automatic orphan deletion requires a complete population basis. A completed extraction is not a claim that every row passed transformation; inspect rejections and reconciliation results. Set the tenancy stance from the actual source partition, and do not use NO_SUBJECT_DATA for a source containing people’s information.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.