Skip to content
dg.dev
← all projects

2026 · updated 29 Sept 2026

ixnos-data

Where does the money go? Greek public spending, searchable in Greek or Greeklish.

The problem

Tenders (ΚΗΜΔΗΣ) and spending decisions (Διαύγεια) are already public, but they're hard to search, written in dense administrative Greek, and pushed to nobody. A small business has no easy way to learn that a nearby authority just posted a tender for what it sells.

Paid aggregators exist. I wanted a free, open-source one with a public API, that reads both sources and links a tender to its award, contract and payment.

How it works

  1. ΚΗΜΔΗΣ APIΔιαύγεια API
  2. Python ingestion
  3. PostgreSQL 16
  4. .NET 10 API.NET notifier
  5. Next.js web appEmail digestsPublic API

Four services share one PostgreSQL database and nothing else, so each can fail and deploy on its own. The pipeline fetches, validates and upserts; the API reads with hand-written SQL for search and EF Core for writes; the notifier is a one-shot process run by cron, so a mail outage can never take the site down.

The hard parts

  1. 01

    Greek search that forgives people

    People type «καθαρισμος», «katharismos» or «κλιματηστικών». One normaliser, shared by Python and .NET and tested against the same cases, folds accents, final sigma and Latin look-alike letters. PostgreSQL full-text search with a Greek stemmer handles word forms, trigram similarity handles typos, and phonetic keys handle Greeklish. A set of 56 real queries scores precision@10 of 0.84–1.00, and deploys fail if it drops.

  2. 02

    Two sources, the same money, described differently

    ΚΗΜΔΗΣ states amounts without VAT, Διαύγεια with VAT, and Διαύγεια awards restate ΚΗΜΔΗΣ ones. The two are kept apart, labelled, and joined by VAT number instead of added up. Corrections in Διαύγεια point to the decision they replace by an internal version ID rather than its public number, and the pipeline resolves that in either arrival order.

  3. 03

    Measuring before modelling

    Before any schema, probes pulled six months of ΚΗΜΔΗΣ and three weeks of Διαύγεια: 614,000 records. That's how I learned that titles are cut at 100 characters, that the place of work differs from the authority's address on 15% of notices, that ΚΗΜΔΗΣ answers 404 for days with no records yet, and that some payments are typos over €100 million.

  4. 04

    Alerts that never double-send

    The digest records its deliveries and its checkpoint before sending, so a crash or a rerun can miss at most one email and never repeats one. Sign-in is by emailed link, and only hashes of link, session and API-key tokens are stored.

Decisions and trade-offs

The database is the only integration point

No message bus and no service-to-service calls. It costs some flexibility, but four processes that only share a schema are easy to reason about and run fine on one machine.

Privacy by construction

Public records name sole traders. They appear on the records they're in, never on a page of their own; the API never returns contractor VAT numbers, and the bulk exports carry no contractor data at all.

A static edition with no server

Every three hours a GitHub Actions workflow restores an encrypted working database, fetches new records with the same pipeline, and writes the site as plain files. Alerts become RSS feeds and there's no API, but search, organisation pages and signals all work.

Neutral signals, not accusations

A competitive tender with a single offer, or a direct award just under the legal limit, is marked as worth a second look, with no verdict attached. The reader draws the conclusion.

What it doesn't do yet

  • The full version, with accounts, email alerts and API keys, is built and tested end to end but not deployed yet; the static edition is what's live.
  • The name may still change before launch.