- HTML 44.1%
- Python 31.3%
- TypeScript 21.1%
- Shell 1.3%
- Just 1%
- Other 1.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
ci / ci (push) Successful in 3m55s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
| .claude/skills/project-handbook | ||
| .forgejo/workflows | ||
| backend | ||
| browser | ||
| docs | ||
| fixtures | ||
| frontend | ||
| installer | ||
| prompts/extract-rule | ||
| proxy | ||
| schemas | ||
| scripts | ||
| seeds | ||
| spikes | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| .gitleaks.toml | ||
| .yamllint.yaml | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| compose.yaml | ||
| DESIGN_SPEC.md | ||
| install.sh | ||
| justfile | ||
| LICENSE | ||
| openapi.json | ||
| README.md | ||
| ruff.toml | ||
| RUN.md | ||
| SPEC_SPEC.md | ||
Ölkurs
Ölkurs is a self-hosted heating-oil price tracker for one household. Several times a day it fetches the price of Heizöl EL from the vendor pages you configure, for the order amounts and postal codes you care about, keeps every observation as a time series, shows the development with moving averages, and pushes prices or charts to your phone through ntfy or Telegram — so you can decide when to fill the tank.
What it does
- Fetches vendor price calculators: plain pages, forms and JSON endpoints, or JavaScript-only pages through a headless browser; per order amount, postal code and product.
- Normalises every price to EUR per 100 l including VAT and keeps the raw text for auditing.
- Refuses doubtful values: no price, an implausible price or an unconfirmed jump of more than 25 % produces no sample; samples are never changed afterwards.
- Shows the price history with dashed moving averages over days or samples, and the lowest, highest and latest price with the time each was observed.
- Notifies on a schedule, on a price change, on a new low or high, or when the price crosses an average — as numbers or as a chart — via ntfy or Telegram, never twice for the same event.
- Keeps snapshots of every response, so extraction rules are fixed against stored pages, not by asking the vendor again, and is polite to vendors (identifying User-Agent, interval floor, one request per series).
The interface and the handbook are German; the handbook is also available in English.
Requirements
A Linux host with Docker and the compose plugin. The installer offers to
install just, the command menu. Everything else runs in containers.
Installation
git clone ssh://git@fj16.bastler.space:223/markusw/oelkurs.git
cd oelkurs
./install.sh
The installer asks for the public URL, the time zone, whether to enable the headless browser for JavaScript-only
vendors, and the reverse proxy: the bundled Caddy (automatic HTTPS for a public hostname) or your own Caddy,
Traefik, nginx or Apache, in Docker or on the host. It writes .env, compose.override.yaml and, for your own
proxy, a ready-to-include configuration in deploy/proxy/, then builds and starts everything, creates the first
login, imports the example sources and checks that the site answers.
Re-running ./install.sh is safe: the current settings are the defaults and secrets are kept. For a
non-interactive install:
cp installer/answers.example.toml answers.toml # edit it
./install.sh --answers answers.toml
Details for every question and proxy: handbook, Administration → Installation and Reverse proxy.
Running
Open the public URL (default http://localhost:8094) and sign in. Under Quellen you see the example sources (LEU Energie, esyoil); Jetzt abrufen fetches prices right away, the Übersicht shows them. Under Kanäle & Regeln you connect ntfy or Telegram.
| Command | What it does |
|---|---|
just ps / just logs worker |
state of the services / what the worker does |
just fetch-now leu |
fetch a source now and print the result |
just extract-test leu 3000l |
re-run the extraction rule on the last stored page |
just backup / just restore <file> |
database dump and snapshot archive / restore a dump |
just upgrade |
back up, rebuild, migrate, restart, verify |
just install-proxy [--undo] |
copy the generated snippet into your proxy and reload it (asks first) |
just --list shows every command; RUN.md explains them.
Documentation
- Handbook: served at
/docs/(German, English); sources indocs/src/content/docs/. - Specification: DESIGN_SPEC.md; decisions: docs/decisions/; runbook: RUN.md; changes: CHANGELOG.md.
Development
just test, just check and just ci run the tests and quality gates; E2E_PASSWORD=… just e2e runs the
Playwright suite in the official Playwright container. Stack: Python 3.12 (Django 5.2, DRF, APScheduler),
PostgreSQL 16, React 19 with TypeScript and Vite, Caddy, Astro Starlight.
Licence
Copyright 2026 Markus Walther. Licensed under the GNU Affero General Public License v3.0. If you run a modified version as a network service, you must offer its source code to its users.