← All Work

Fastest Lap Times (FLT)

A community-driven lap time tracking web app.

An adjacent technical build focused on Python ingestion, SQL schema design, process automation, and authenticated data-product thinking.

Python Flask SQLite Steam OAuth INI Parsing Custom SQL Schema Blueprints
Type Personal project
Role Sole developer
Stack Python · Flask · SQLite · Steam API

The Problem

Assetto Corsa stores personal best lap times in flat .ini files scattered across local directories — one per car/track combination. There's no built-in way to query across them, compare progress over time, or explore split data in aggregate.

The only way to review your times is to open files manually or rely on an in-game menu that shows one car/track at a time with no history.

The Solution

FLT is a full-stack Flask application built around a Python harvester that reads game files, normalizes the data, and loads it into a custom SQLite schema. A web interface then exposes the data through browseable catalog views, per-session time breakdowns, and split analysis — all behind Steam OAuth so only the account owner can access it.

The key insight was treating the game's output directory as a data source: build a proper ETL pipeline on top of flat files, design a schema that supports meaningful queries, and serve it through a web app that feels like a real product.

How It Works

  • The harvester scans the Assetto Corsa output directory, locates personalbest.ini and laps.ini files, and parses them into structured payloads
  • Split times are correlated to personal bests by matching lap times across files
  • Parsed data is submitted to the app via a CLI submitter and written into a custom SQL schema designed for per-car, per-track, and cross-session querying
  • Steam OAuth handles authentication: users sign in with their Steam account, and the app verifies identity against the Steam OpenID endpoint before granting access
  • A catalog blueprint provides car and track browse views; a times blueprint handles per-lap detail and split breakdowns
  • Custom Jinja filters handle slug-to-display-name formatting for cars and tracks

What It Demonstrates

  • End-to-end product thinking: raw files → ETL → structured schema → authenticated web UI
  • Custom SQL schema design to support queries that the raw source data makes impossible
  • Third-party OAuth integration with Steam OpenID — not just username/password auth
  • Flask application factory pattern with blueprint-based feature organization
  • Separating data ingestion (harvester CLI) from data serving (web app)