Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# fLOGr

A self-hosted web app for logging your fuel purchases and tracking vehicle fuel economy. Enter each refuel, and fLOGr calculates litres/100km, cost per 100 km, price trends, and per-vehicle comparisons over time.

Built with **Flask** + **SQLite** + **Chart.js**, styled with **Bootstrap 5**. Developed by ThatButcherGuy.

---

## Features at a glance

- **Quick log entry** — enter a refuel on the go (vehicle, fuel, litres, price/L, kilometres, location, optional comments).
- **Edit / delete records** — fix typos or remove a mistaken entry; the vehicle odometer is adjusted automatically.
- **Smart purchase locations** — store each retailer + suburb once and reuse it; rename a location and it updates every past log.
- **Stats & Reports** — summary cards, global statistics, per-vehicle comparison, and interactive charts (economy, price/L, litres, spend by location, monthly spend, fuel price history).
- **Vehicle garage** — manage your vehicles and view detailed per-vehicle stats.
- **Full-tank accuracy** — a "Partial tank" flag lets you log top-ups that are excluded from fuel-economy calculations but still counted in litres/spend.
- **Two-factor authentication (TOTP)** and optional **Authentik (OIDC) SSO**.
- **Scoped API** — generate tokens to let programs (e.g. an AI agent) read your data.
- **Logging & audit trail** — request logs to `docker logs`, plus a per-user **Activity Log** of every data/account change.
- **CSV export** — export your log, optionally filtered.

---

## Quick start (Docker)

### docker-compose.yml

```yaml
services:
  flogr:
    image: docker.io/thatbutcherguy/flogr-docker:latest
    container_name: flogr
    ports:
      - "15001:8080"              # host : container
    volumes:
      - /path/to/flogr/data:/flask-app/data   # persist the SQLite database
    environment:
      - TZ=Australia/Canberra
      - DATABASE_PATH=/flask-app/data/flogr.db
      - PUID=568
      - PGID=568
      - SECRET_KEY=change-me-to-a-long-random-value   # REQUIRED for production
      - LOG_LEVEL=INFO            # DEBUG / INFO / WARNING / ERROR
      # - LOG_FORMAT=json         # uncomment for structured (JSON) logs
      # Optional: Authentik OIDC SSO
      # - AUTHENTIK_CLIENT_ID=********
      # - AUTHENTIK_CLIENT_SECRET=********
      # - AUTHENTIK_ISSUER_URL=https://auth.example.com/application/o/flogr/
    restart: unless-stopped
    networks:
      - flogr

networks:
  flogr:
    external: true
```

The app listens on **port 8080** in the container, mapped to `15001` on the host (behind a reverse proxy if desired).

### Environment variables

| Variable | Default | Description |
|---|---|---|
| `DATABASE_PATH` | `data/flogr.db` | Where the SQLite database is stored. |
| `SECRET_KEY` | | Flask session key. Set a long random value in production. |
| `LOG_LEVEL` | `INFO` | Log verbosity: `DEBUG`, `INFO`, `WARNING`, `ERROR`. |
| `LOG_FORMAT` | `plain` | `json` emits one JSON object per line for log viewers; `plain` is human-readable. |
| `AUTHENTIK_CLIENT_ID` / `_SECRET` / `ISSUER_URL` | (unset) | When all three are set, Authentik OIDC login is enabled. |
| `GUNICORN_*` | | Optional Gunicorn tuning (processes, threads, timeout, bind). |

---

## Using fLOGr

### Authentication

Two login methods, switched per-user from **Settings**:

- **Password login** — default; passwords are hashed with Werkzeug.
- **Authentik (OIDC)** — optional SSO. `Settings → Authentik (OIDC) Login` toggles it per user. If Authentik is unreachable, the login page warns you and you can fall back to your password.

**Two-factor authentication (TOTP)** — enable from Settings, scan the secret into an authenticator app, then enter a code to confirm. Save your **10 recovery codes** (each usable once). 2FA applies to password login; Authentik handles its own MFA.

### Enter a Record (home page)

Once logged in, the home page is a fast refuel entry form.

> **For accurate fuel-economy maths:** fill the tank to the **same level** each time — the fullest point is most repeatable — and log **every** refuel. If you forget one, a close guess is better than nothing. Mark a **partial top-up** as "Partial tank" so it's excluded from L/100km (but still counted in spend/litres).

Fields:
- **Vehicle** — required selection from your Garage.
- **Fuel type** — defaults to the vehicle's fuel; changeable (handy for dual-fuel).
- **Date** — defaults to today, cannot be in the future.
- **Receipt number** — optional.
- **Purchased at** — choose an existing location or add one inline.
- **Litres** — to 2 decimal places.
- **Price per litre** — to 3 decimal places; include any checkout discounts.
- **Kilometres** — how far you drove on the previous tank; added to the vehicle's odometer.
- **Partial tank** — check for a top-up that isn't a full tank.
- **Comments** — optional free text.

For each record fLOGr calculates **sale price** (`litres × price/L`) and **L/100km** (`litres / km × 100`).

### View Log

All your records, newest first. Sortable by any column, searchable, and filterable by vehicle. From here you can **edit** or **delete** entries (odometer adjusts automatically), and **Export CSV** for all records or the selected vehicle.

The page uses **server-side paging** — it loads instantly and fetches one page of records at a time, so it stays responsive even with thousands of entries.

### Locations

Manage your reusable `Retailer Suburb` purchase locations. Renaming a location updates it across all past log entries; you can't delete a location still referenced by logs.

### Garage

Your vehicles (registration, type, make/model, year, odometer). Add, edit or delete vehicles. Click a registration for full vehicle details (useful on small screens where the Garage table is trimmed).

### Stats

A read-only **numbers** overview of your logs, fully driven by the **filter bar** at the top (vehicle, a custom date range, or a **quick period** — All / 7 / 30 / 90 days / 6 / 12 months / YTD / Financial year (AU)). A banner shows exactly what's being viewed (e.g. *"vehicle ABC · date: Year to date"*):

- **Trend vs Previous Period** — when a date filter is active, compares this period against the equivalent prior window (total spend %, economy L/100km change, distance %, avg days/tank) with green/red change badges.
- **Summary cards** — total spend, litres, distance, combined L/100km, cost/100km, avg cost/tank, best/worst economy (label-above-value).
- **Most Recent Fill** — your latest entry, days since, economy, price, cost, location, and **avg days / tank**.
- **Summary table** — totals and averages across the filtered set, plus **Average days per tank**.
- **Vehicle Comparison** — each vehicle's economy, cost/100km, and range per tank.
- **Location Insights** — most spent at, most frequent, cheapest & most expensive avg $/L, best-economy location, and distinct location count in the period.
- **Vehicles** — links to per-vehicle statistics.

All figures use thousands separators, and dollar values include `$`.

### Vehicle Stats

Click a vehicle's registration on the Stats page (or Garage). Shows vehicle details, summary cards (including **days since last fill** and **avg days / tank**), and the last 20 records for that vehicle. Filter the summary to a date range.

### Reports & Charts

The interactive, graphical analysis hub (also via **"Open Reports & Charts"** on the Stats page). Filter by vehicle, location, a custom date range, or a **quick period** (All / 7 / 30 / 90 days / 6 / 12 months / YTD / Financial year (AU)) — charts and summary cards update instantly, client-side:

- Fuel economy (L/100km) and price/L over time (monthly line charts)
- Litres purchased over time (bar)
- Spend by location (doughnut)
- Fuel price history — avg $/L by year (bar)
- Monthly spend, last 12 months (bar)
- Vehicle comparison — economy and cost/100km (bar)

Data is served by `/api/stats`.

> **Stats vs Reports:** Stats is the readable numbers/table view; Reports is the trend/chart view. They cross-link (Stats → "Open Reports & Charts"; Reports → "View Statistics").

### Settings

- **Appearance** — light / dark / auto theme (also the navbar 🌙/☀️🖥️ toggle).
- **Account & Security** — username, email, Authentik toggle, 2FA enable/disable.
- **API Access** — generate/revoke scoped tokens.
- **Activity Log** — your audit trail (see below).

---

## API (token-authenticated)

Generate a scoped token from **Settings → API Access**. Send it as:

```
Authorization: Bearer flogr_...
```

Endpoints:

| Endpoint | Reads | Scope |
|---|---|---|
| `GET /api/logs` | your log entries | `logs` |
| `GET /api/locations` | your locations | `locations` |
| `GET /api/vehicles` | your vehicles | `vehicles` |

Tokens are read-only by default. Each endpoint needs its named scope, or a token may carry `write` (grants access to all). Only a SHA-256 hash of the token is stored — the raw value is shown **once** at creation. Revoke a token anytime from Settings.

---

## Logging & Audit

**Container logging** — the app writes structured logs to stdout, captured by `docker logs flogr` (alongside Gunicorn's access/error streams). Every request is logged with method, path, status, user ID, source IP and duration. `LOG_LEVEL=DEBUG` shows more detail; `LOG_FORMAT=json` emits one JSON object per line for dashboards.

**Activity Log (audit)** — **Settings → Activity Log** keeps an immutable, per-user trail of data and account changes, kept indefinitely for troubleshooting and traceability:

- **Fuel-log entries** capture full before/after field diffs on create and edit, and a full snapshot on delete.
- **Locations, vehicles, API tokens, account settings, and auth events** (login, failed login, logout, registration, 2FA, OIDC) are recorded as concise summaries.
- Each user sees only their **own** entries.

---

## Database schema

A single SQLite database with these tables:

| Table | Purpose |
|---|---|
| `users` | Accounts, password hash, 2FA secret/codes, OIDC flag. |
| `fuel_types` | Lookup of fuel codes (`U91`, `P98`, `DL`, ...). |
| `vehicles` | Each vehicle in a user's Garage (registration, type, make/model, year, odometer). |
| `log` | Every refuel record (`log.location_id` → `locations.id`, `partial_tank` flag). |
| `locations` | Reusable retailer + suburb purchase locations. |
| `api_tokens` | Scoped API tokens (SHA-256 hashes only). |
| `audit_log` | Per-user activity/audit trail. |

---

## Development

- Single persistent clone; releases are git tags (`vX.Y.Z`). Semver: **minor** for features, **patch** for fixes/security.
- Database schema lives in `static/schema.sql` (fresh installs); existing installs get new tables/columns via migrations run at app startup. A schema change needs **both**.
- Run locally: `uv venv && source .venv/bin/activate && uv pip install -r requirements.txt`, then set `DATABASE_PATH`, `SECRET_KEY` and start with `python app.py`.

---

## Wish list

- **User account management** — edit/delete users, email + `is_active`, reset / forgot-password.
- **PDF export** of logs and of reports (charts + stats).
- **Unit-of-measure support** — miles, gallons, MPG, other currencies.
- **Vehicle service tracking** and richer **vehicle profiles** (mods with install dates, photo gallery for insurance).

> ✅ **Done recently:** password strength on registration (min 8 chars), auto-rounding of kilometres on entry, container logging, per-user activity/audit log, and avg-days-per-tank + days-since-last-fill stats.