Build an Entity Graph intelligence layer ("Palantir-style ontology") that links disparate map entities (aircraft, vessels, organizations, people) across feeds, but do so using a 100% Open-Source and Self-Hosted Architecture.
Instead of relying on third-party SaaS APIs that have rate limits or require paid keys, we will spin up local intelligence containers that hold bulk data, and aggressively cache external queries using your existing Nginx infrastructure.
Important
Storage & Compute Requirements: Self-hosting intelligence data requires some storage on your Ionos/Epyc server.
- The Yente container (OpenSanctions self-hosted API) downloads about ~1.5GB of global sanctions, PEPs, and corporate data.
- Are you comfortable dedicating a couple of gigabytes of storage on the server for these self-hosted datasets?
Warning
- Do you want the Entity Graph panel to replace the existing OSINT panel when an entity is clicked, or should they be separate tabs/panels?
- We already have an
osiris-cacheNginx container. I plan to modify this Nginx configuration to also cache our outgoing intelligence queries (e.g. Wikidata). Does this align with your vision for the "Self Hosted intelligence sector that also gets caches"?
- Add Yente Service: Add
ghcr.io/opensanctions/yente:latest. Yente is the official open-source, self-hosted API engine for OpenSanctions. It automatically downloads the latest global sanctions and corporate data and serves it locally, meaning we have zero rate limits and no external tracking. - Connect Network: Ensure Next.js can communicate internally with Yente on
http://yente:8000.
- Add OSINT Cache Layer: Configure the existing Nginx container to act as an aggressive forward-cache proxy for external OSINT queries (like Wikidata SPARQL or public ICAO registries). When an entity is queried once, Nginx will cache the ontology data locally so subsequent expansions are instant and don't hit external rate limits.
- Create the ontology resolver endpoint inside Next.js.
- Resolver Logic (Fully Local):
- Next.js receives a request to expand an entity (e.g., an IMO number or Company name).
- It queries the local Yente container to instantly find corporate linkages, executives, and sanction flags.
- It queries external open sources (Wikidata) routed through the local Nginx cache.
- It formats the results into a
{ nodes, links }graph object and sends it to the frontend.
- Create a new sliding side-panel for the UI.
- Integrate
react-force-graph-2d(which usesd3-forceinternally and is already inpackage.json) to render a dynamic, force-directed mini-graph of nodes and links. - Clicking a node in the graph triggers a recursive fetch to the local
/api/entity/expandendpoint to branch out the ontology.
- Add state for
activeEntityGraph(node data and links). - Update the
handleEntityClickcallback to set theactiveEntityand open theEntityGraphPanel.
- Ensure all clickable layers pass a structured object to
onEntityClickcontaining{ type: 'aircraft', id: 'callsign/tail' }or{ type: 'vessel', id: 'IMO' }.
docker-compose up -dto verify the new Yente container spins up and begins downloading the sanctions index.- Click a commercial flight or maritime vessel on
localhost:3000. - Verify the
EntityGraphPanelslides open on the right side. - Verify the force-directed graph automatically expands by querying the local
/api/entity/expandroute. - Inspect the Docker logs to confirm that the API queries are hitting the local Yente container and the Nginx cache rather than external APIs directly.