I build the tools fraud investigators search with.

I'm David Valor, a full-stack engineer. Since 2021 I've kept an open-source intelligence (OSINT) investigation platform in production: one search queries 15 sources, a graph connects what they return, and an AI assistant reads it.

Available for remote roles and projects. Venezuela, GMT−4.

One search, 15 sources

    Fictional data. The real product belongs to Grupo Analytiko and its cases are confidential.

    15
    external sources queried by a single search
    1,800+
    commits of mine in the OSINT codebase since 2021
    11
    cloud services behind one API
    5
    years keeping the same system in production

    Teams I've built for

    • SIP Consulting
    • Smart Compliance
    • Aictive
    • Gestoy
    • Hello Mundo

    Grupo Analytiko / SIP Consulting. Angular, Node.js and TypeScript, MongoDB, Neo4j, Socket.IO, Google Cloud Run.

    In production: skuld.analytiko.app

    An investigator types a name, a phone number or a username. The platform queries sanctions lists, official gazettes, court rulings, social networks and the web at the same time, and draws what it finds as a graph they can keep exploring.

    A relationship graph from the real product, with dozens of nodes fanning out from three centres
    A real graph from production. Blurred on purpose: the names belong to a case.

    How one search travels

    1. Confirm the connectionThe browser asks for an acknowledgement before it sends anything that costs credits.
    2. Fan outOne adapter per source. All leave in parallel and none waits for another.
    3. Stream backEach result arrives over a socket, tagged with its search id, as soon as it exists.
    4. Draw the graphEach result becomes a typed node. The type declares which searches it can trigger next.
    5. Charge onceOne search uses one credit, even if a source fails or the page has to reconnect.

    An assistant that reads the graph

    I added a conversational assistant over the relationship graph. The model filtering runs on the server, so the investigator asks in plain language and the model only sees the nodes of the case that is open.

    Tested against the real thing

    I wrote the project's first end-to-end suite with Playwright: it exercises all 15 search APIs on a deployed environment. At the August 2026 production close-out the project ran 1,149 backend tests and 359 frontend tests.

    Web results in about a second

    I packaged the web crawler into a single Cloud Run image to stop paying for the external service. Search used to take over 30 seconds and sometimes came back empty; it now answers in about 1 second, and each page's content is fetched later, when the investigator adds it to the graph.

    What a search costs

    I measured it over 30 days in 2026: a full search across every source costs 5.5 US cents in infrastructure, and a search on a person costs 0.2 cents. Three sources account for 96% of that cost, which shows where to optimize.

    What broke in production, and how I fixed it

    Watch each failure happen step by step, then switch the fix on. All three are real.

    BrowserAPISources

    Grupo Analytiko, for banking anti-fraud teams. Angular, Node.js and TypeScript, MongoDB aggregations, SQL Server, Python.

    In production: demo.sipconsulting.net

    A fraud case is thousands of transfers. Analyst draws them as a graph of accounts and answers the questions an analyst asks: who moves the most, who connects everyone, and where the money stops.

      Eight fictional accounts. The rankings are computed in your browser with the same definitions the analysis endpoints use.

      Questions an agent can ask too

      Each ranking is an endpoint with an exact definition. That lets an AI agent run the first pass on a case with the same queries the analyst uses, and makes every conclusion auditable.

      Data that arrives on its own

      I built the scheduled ingestion of operations and rates that feeds the analysis. For confidentiality I don't show the client or its data.

      Grupo Analytiko. Third-party due diligence (Diligence Plus). Angular 18, Angular Material, Node.js and TypeScript, Google Cloud Run.

      In production: ddr.analytiko.app

      Before signing with a supplier, a client or a partner, someone in compliance has to check them. DDR looks them up in sanctions, watchlists, lists of politically exposed persons (PEP) and the news, and shows what matched and why, so a person makes the call.

      What you hand in

      Name
      Orinoco Trading, C.A.
      Document
      J-00000712-4
      Keywords
      imports, customs

      What DDR checks

      • Sanctions lists
      • Watchlists
      • Politically exposed persons
      • News, classified with AI

      What you get back

      Complete report as a PDFEvery match with its reason and source, a folio and a QR to verify it

      Fictional document and company. Below you can open the report in three scenarios.

      Fictional counterparties, folios and news. The status wording is the one the product uses.

      The AI flags, a person decides

      Lists are checked with no AI at all. For news, a small model classifies each item and estimates whether it is about the same person, with the reason written down. A larger model steps in only when that identity is doubtful. No news item changes the report status.

      A certificate anyone can verify

      Each check produces a PDF with a folio and a QR code. Whoever receives it scans the code and confirms the certificate is authentic, without seeing the result. Every check is written to the audit log with the document masked.

      I built the sources too

      Several of the sources the platform queries are services of their own. Two have public code.

      Sanctions screening

      Node.js, MongoDB, AWS Lambda. Code on GitHub

      It loads the OpenSanctions open data into MongoDB and serves it as an API. Search ignores accents and case, because a misspelled name must not let a sanctioned person through. Doubtful matches go to a model that writes down its reason for the audit trail.

        Official gazettes

        Python, OCR. Code on GitHub

        It downloads the PDFs of Venezuela's Official Gazette archive, extracts the text page by page and indexes it. A search by name then finds appointments, companies and penalties published years ago in scanned documents.

        GACETA OFICIAL N.º 00.000   14 de marzo de 2016

        …se designa al ciudadano JOSÉ Á. PEÑALVER como director de la sociedad mercantil ORINOCO TRADING, C.A.…

        1. DownloadScanned PDF, 48 pages
        2. Read (OCR)Text extracted page by page
        3. IndexEvery page becomes searchable by name
        4. Hit"penalver" → 2016 gazette, page 14

        Fictional document. Real gazettes are in Spanish.

        Court rulings

        People extraction, search service on Cloud Run

        It extracts the people named in supreme court decisions and makes them searchable by name, so a court record shows up in the same graph as every other finding.

        …vista la demanda interpuesta por CARIBE LOGISTICS, C.A. contra el ciudadano EDUARDO MARCANO, asistido por la abogada MARÍA URDANETA, esta Sala declara…

        Fictional ruling. Tap or point at a name to see where it appears.

        Other work

        Compliance, computer vision, logistics and AI automation.

        David Valor

        About

        I've been developing software since 2017 and integrating generative AI into products since 2023. I work across the whole delivery: the interface, the APIs, the integrations, the tests and what breaks in production.

        My core stack is TypeScript, Node.js, Python, Angular and React, on Google Cloud and AWS. What I know best is the domain: fraud investigation, sanctions and compliance.

        Does your team investigate fraud or run customer checks (KYC)?

        Tell me which sources you check by hand today and what keeps breaking. I reply within one business day.