Wheeler Keeper: The Self-Hosted Vehicle Maintenance Tracker That Never Forgets

5 min read
Wheeler Keeper: The Self-Hosted Vehicle Maintenance Tracker That Never Forgets

The Problem With Car Maintenance

You know the feeling. You’re at the petrol station and you notice the little sticker on the windscreen — but you can’t remember if that’s the old interval or the one the mechanic updated last visit. Your oil change was definitely around 15,000 km. Your brake pads were done… last winter? Or the winter before?

Car maintenance is one of those things that desperately needs a log but almost nobody keeps one. Receipts pile up in the glovebox, service books get lost, and memory fades. By the time something feels wrong, you’re already overdue.

Wheeler Keeper is a self-hosted Django web application that solves exactly this. It gives your vehicles a digital memory: every service logged with date, mileage, itemised costs, and a smart notification system that tells you when something is coming due — without you having to remember to check.


What You Can Track

Wheeler Keeper supports five vehicle types: cars, motorcycles, vans, motorhomes, and trucks. Each vehicle entry carries:

  • Make, model, year, and plate
  • Current odometer reading
  • Full maintenance history
  • Upcoming service predictions (by km and/or by months)

The maintenance type catalogue covers nine categories — engine, transmission, brakes, tyres, suspension, electrical, air conditioning, filters, and a catch-all — with default service intervals you can override per vehicle. That last detail matters: a turbocharged engine may need oil every 7,500 km while the manufacturer’s general recommendation says 15,000.

Feature overview: vehicle fleet, maintenance log, cost tracking, and smart alerts

Logging a Service Session

When you visit the workshop, a single maintenance session can contain multiple items. You spent the afternoon at the garage: oil change, air filter, spark plugs. That’s one session with three ItemMantenimiento entries, each with:

  • The maintenance category and type
  • Description of the specific part used (e.g. Mann W712 oil filter, Castrol 5W30 4L)
  • Quantity and unit cost

The session itself carries the workshop name, date, odometer at time of service, and a global labour cost. The cost model separates labour from parts, and supports toggling IVA (21% Spanish VAT) — either included in the prices you enter, or added on top at the totals stage.

FieldDetail
Labour costFlat fee for the workshop’s time
PartsPer-item: quantity × unit price
IVA toggle21% added to subtotal, or already included
SubtotalLabour + all parts
TotalSubtotal ± IVA

This gives you a clear breakdown of what you actually paid for the work versus the parts, which is useful when comparing workshops or budgeting future services.


Smart Notifications Without Cron Jobs

This is the part that makes Wheeler Keeper genuinely clever in its implementation.

Most maintenance reminder apps either require you to remember to open them, or they need an external cron job to fire at scheduled intervals — which in a self-hosted setup means configuring system-level cron, dealing with environment variables in shell context, and debugging silent failures.

Wheeler Keeper takes a different approach: a Django middleware (NotificacionesProgramadasMiddleware) that activates automatically on every incoming request. When a user navigates to any page, the middleware silently checks whether it’s already run a maintenance review for that user today. If not, it scans all vehicles for overdue or upcoming services and fires emails for anything that needs attention.

Notification flow: how middleware triggers emails without cron jobs

The notification logic covers two dimensions — time and mileage — and two urgency levels:

Alert typeTrigger condition
🚨 Overdue by timePast the scheduled service date
🚨 Overdue by mileageVehicle exceeded recommended km
🔧 Upcoming by timeService due within 30 days
🔧 Upcoming by mileageWithin 1,000 km of next service

An anti-spam guard ensures no user receives more than one notification per maintenance type per 24-hour window, tracked via the NotificacionMantenimiento model. Every sent notification is logged with timestamp, alert type, odometer reading, and delivery status.

The practical result: as long as at least one user opens the application occasionally, the notification system runs. No root access required, no cron configuration, no silent failures.


Multi-User System with Approval Workflow

Wheeler Keeper is designed for a small trusted group — family, flatmates, a small fleet manager — not open public registration. New users request access through a registration form, and an administrator approves or rejects each request from the Django admin panel.

The approval workflow supports both manual accounts (username + password) and Google OAuth (via django-allauth). When a Google-authenticated user requests access, the approval step creates both the Django user and the linked social account in one operation. Approved and rejected applicants each receive an email notification.


Deployment: Docker Compose in Two Commands

The entire stack — Django application, PostgreSQL database, and static files — is containerised and managed through Docker Compose. The Makefile wraps the common operations:

make first-time-setup   # interactive guided setup
make install            # build images, run migrations, load default data
make quick-start        # daily start once already configured
make backup-db          # manual PostgreSQL dump

Automated weekly backups run via a shell script (backup-cron.sh) that uses pg_dump, compresses the output, and rotates to keep the last 10 snapshots. An optional system cron entry triggers this on Sundays at 08:00.

The entrypoint.sh waits for PostgreSQL to accept connections before starting the Django process, avoiding the race condition that makes many Docker + database setups fail on first run.


Under the Hood

LayerTechnology
FrameworkDjango
DatabasePostgreSQL (via Docker volume)
AuthenticationDjango auth + django-allauth (Google OAuth)
EmailSMTP (Gmail App Password or any SMTP server)
NotificationsDjango middleware — no external scheduler
ContainerisationDocker + Docker Compose
Static filesDjango collectstatic → served from container
Backupspg_dump + gzip, rotating 10 snapshots

Try It

The live instance is available at wheeler-keeper.box2overtake.com. You can request access directly from the registration page.

To self-host your own instance, the repository contains everything you need — docker-compose.yml, configuration templates, and the full Makefile with commented targets for every operation.

Your car remembers every pothole. Wheeler Keeper remembers everything else.

Suggest an edit

Last modified: 21 Jun 2026