2026-03-06 15:04:27 +00:00
2026-03-06 14:51:26 +00:00
2026-03-06 14:51:26 +00:00
2026-03-06 14:51:26 +00:00
2026-03-06 12:25:07 +00:00
2026-03-06 14:51:26 +00:00
2026-03-06 14:51:26 +00:00
2026-03-06 14:51:26 +00:00

House ELO Ranking

A pairwise comparison tool that lets you rank houses using the ELO rating system. Built to rank Funda listings during a personal house search, but adaptable to any listing dataset stored in PostgreSQL.

Two listings are shown side-by-side. You pick the one you prefer, and both receive updated ELO ratings. Over time this produces a reliable ranking of all listings based on your personal preferences.

Features

  • Matchmaking weighted-random pairing that avoids recent duplicates and favours less-compared listings
  • ELO ratings standard ELO formula with configurable K-factor
  • Rankings sorted table of all sampled listings by ELO
  • History browse every comparison you have made
  • Statistics total comparisons, ELO distribution chart, aggregates
  • Image carousel listing photos pulled from a JSON column in the database

Architecture

┌──────────┐        ┌──────────┐        ┌────────────┐
│ Frontend │──nginx──│ Backend  │────────│ PostgreSQL │
│ React/TS │  :80   │ FastAPI  │  :5432 │            │
└──────────┘        └──────────┘        └────────────┘
Layer Stack
Frontend React 18, TypeScript, Vite, Tailwind CSS
Backend FastAPI, SQLAlchemy, Pydantic, Python 3.12, uv
Database PostgreSQL (external, not managed by this project)
Infra Docker Compose, nginx reverse proxy

Requirements

  • Docker and Docker Compose
  • An existing PostgreSQL database with the tables described below
  • uv (for local development outside Docker)

Database schema

The application reads listings from a configurable schema/table and manages its own ELO tables. The required structures are:

Listings table (read-only, provided by you)

The table configured via LISTINGS_SCHEMA / LISTINGS_TABLE must contain at least these columns:

Column Type Description
global_id text Unique listing identifier
tiny_id text Short identifier
url text Listing URL
title text Listing title
city text City name
postcode text Postal code
province text Province
neighbourhood text Neighbourhood name
municipality text Municipality
latitude numeric Latitude
longitude numeric Longitude
object_type text e.g. apartment, house
house_type text e.g. upstairs, detached
offering_type text e.g. buy, rent
construction_type text e.g. existing, new
construction_year text Year of construction
energy_label text Energy label (A, B, …)
living_area integer Living area in m²
plot_area integer Plot area in m²
bedrooms integer Number of bedrooms
rooms integer Total rooms
has_garden boolean Garden present
has_balcony boolean Balcony present
has_solar_panels boolean Solar panels present
has_heat_pump boolean Heat pump present
has_roof_terrace boolean Roof terrace present
is_energy_efficient boolean Energy efficient
is_monument boolean Monument status
current_price integer Price in euros
status text e.g. available, sold
price_per_sqm numeric Price per m²
publication_date text Publication date

Sample listings table

The schema configured via ELO_SCHEMA must contain a sample_listings table with a global_id column. Only listings present in this table are shown during comparisons and ranking.

Images table (optional)

The table configured via IMAGES_SCHEMA / IMAGES_TABLE must contain:

Column Type Description
global_id text Listing identifier
raw_json jsonb Must contain a photo_urls key with a list of image URLs

ELO tables (auto-managed)

The application creates and manages ratings and comparisons tables inside the ELO_SCHEMA. These are created automatically on first run via SQLAlchemy ORM.

Getting started

1. Clone and configure

git clone https://github.com/<you>/house-elo-ranking.git
cd house-elo-ranking
cp .env.example .env
# Edit .env with your database credentials and schema names

2. Run with Docker

make build
make up

The frontend is available at http://localhost:8888 (or whatever FRONTEND_PORT you set).

3. Local development

make install          # install Python deps
make test             # run unit tests
make lint             # lint Python + SQL
make format           # auto-format code

Environment variables

Variable Default Description
POSTGRES_HOST localhost PostgreSQL host
POSTGRES_PORT 5432 PostgreSQL port
POSTGRES_USER postgres Database user
POSTGRES_PASSWORD postgres Database password
POSTGRES_DB postgres Database name
DATABASE_URL Full connection string (overrides above)
LISTINGS_SCHEMA marts Schema containing the listings table
LISTINGS_TABLE funda_listings Table name for listings
ELO_SCHEMA elo Schema for ELO rating tables
IMAGES_SCHEMA raw_funda Schema for the images table
IMAGES_TABLE listing_details Table containing raw_json with photos
ELO_K_FACTOR 32 ELO K-factor (higher = bigger swings)
ELO_DEFAULT_RATING 1500 Starting ELO for unrated listings
FRONTEND_PORT 8888 Port the frontend is served on

Makefile commands

make help       Show all available commands
make install    Install backend dependencies
make lint       Run all linters (ruff + sqlfluff)
make format     Auto-format Python and SQL
make test       Run unit tests
make build      Build Docker images
make up         Start services
make down       Stop services
make logs       Tail service logs
make clean      Remove caches and build artifacts

Project structure

├── .env.example                 # Environment variable template
├── .github/workflows/ci.yaml   # CI pipeline (lint + test)
├── .pre-commit-config.yaml      # Pre-commit hooks
├── Makefile                     # Developer commands
├── docker-compose.yaml          # Container orchestration
├── backend/
│   ├── Dockerfile
│   ├── pyproject.toml           # Python deps and tool config
│   ├── .sqlfluff                # SQL linter config
│   ├── app/
│   │   ├── config.py            # Settings and SQL loader
│   │   ├── database.py          # DB engine and session
│   │   ├── elo.py               # ELO calculation
│   │   ├── main.py              # FastAPI application
│   │   ├── models.py            # SQLAlchemy ORM models
│   │   ├── queries.py           # Shared query helpers
│   │   ├── schemas.py           # Pydantic request/response models
│   │   ├── routers/             # API route handlers
│   │   └── sql/                 # SQL query templates
│   └── tests/                   # Unit tests
└── frontend/
    ├── Dockerfile
    ├── nginx.conf               # Reverse proxy config
    └── src/                     # React application

License

MIT

Description
Frontend for subjective rankings of Funda listings
Readme MIT 122 KiB
Languages
Python 48.2%
TypeScript 45.3%
Makefile 4.1%
HTML 1.5%
Dockerfile 0.9%