pc part picker for car parts
  • PHP 67%
  • Dart 27.1%
  • C++ 2.8%
  • CMake 2.1%
  • Swift 0.3%
  • Other 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-05-14 17:38:33 -04:00
.github/workflows publish a GitHub Release alongside the GHCR image push 2026-05-08 10:57:28 -04:00
apis mobile-v0.6.2 — notes, multi-select service log 2026-05-14 17:37:49 -04:00
core mobile-v0.6.2 — notes, multi-select service log 2026-05-14 17:37:49 -04:00
cron read config from env vars first, .env file as fallback 2026-05-07 12:19:15 -04:00
deploy collapse stack to phpcar (Apache + mod_php) + mysql, single HTTP endpoint 2026-05-07 14:15:13 -04:00
docker use php.ini-production and harden forgot.php against null security_question 2026-05-07 14:47:42 -04:00
garage v2.3.2 — Lists nav, notes, multi-select service log 2026-05-14 17:13:36 -04:00
login replace navbar logout with profile dropdown (My Account / Logout) 2026-05-08 10:32:55 -04:00
mobile mobile-v0.6.2 — notes, multi-select service log 2026-05-14 17:37:49 -04:00
navbar v2.3.2 — Lists nav, notes, multi-select service log 2026-05-14 17:13:36 -04:00
parts v2.3.2 — Lists nav, notes, multi-select service log 2026-05-14 17:13:36 -04:00
sql v2.3.2 — Lists nav, notes, multi-select service log 2026-05-14 17:13:36 -04:00
.dockerignore collapse stack to phpcar (Apache + mod_php) + mysql, single HTTP endpoint 2026-05-07 14:15:13 -04:00
.env.example collapse stack to phpcar (Apache + mod_php) + mysql, single HTTP endpoint 2026-05-07 14:15:13 -04:00
.gitignore add mileage estimation, maintenance email alerts, and editable schedules 2026-05-06 19:33:40 -04:00
composer.json add JSON v1 API, JWT auth, and FCM push for mobile clients 2026-05-07 11:49:21 -04:00
index.php v2.3.0 — parts list builder + community catalog 2026-05-09 20:47:23 -04:00
README.md collapse stack to phpcar (Apache + mod_php) + mysql, single HTTP endpoint 2026-05-07 14:15:13 -04:00

CarPartPicker

Track maintenance, estimate mileage, get reminded before something breaks.

PHP · MySQL · Apache · Tailwind · PHPMailer · NHTSA + Edmunds APIs


🚗 What it does

  • Garage — store every vehicle you own, decoded from a VIN via the NHTSA vPIC API and pinned to a year/make/model.
  • Maintenance schedules — auto-generated per vehicle from the Edmunds maintenance API when an API key is set, with a sensible hardcoded fallback. Every interval is editable per car.
  • Mileage estimation — once you've logged at least one service, the app derives a daily-mileage rate from the (date, mileage) data points and projects today's odometer reading without you needing to update it manually.
  • Status engine — every schedule item is classified Overdue, Due Soon, or Good based on the projected mileage and per-vehicle thresholds you control in Vehicle Settings.
  • Daily email alerts — a cron-driven script emails you the morning a service goes due-soon or overdue, with one consolidated message per vehicle. De-duped via a maintenance_alerts table so you're not pinged twice.
  • Dashboard rings — at-a-glance circular gauges show the five items closest to needing attention, color-coded by urgency.

📸 Screenshots

Drop captures into docs/screenshots/ and they'll render here.

docs/screenshots/
  ├─ dashboard.png
  ├─ maintenance.png
  └─ alert-email.png

🧱 Tech stack

Layer Used
Language PHP 8.2 (PDO, prepared statements throughout)
Database MySQL 8
Web server Apache 2.4 + mod_php (single container, port 80) — TLS terminated at your upstream reverse proxy
Frontend Server-rendered PHP + Tailwind via CDN
Mail PHPMailer over SMTP (Gmail app-password by default)
3rd-party NHTSA vPIC, Edmunds Vehicle/Maintenance, Google OAuth

🛠 Quick start (Docker)

You need: Docker + Docker Compose, a Google OAuth client (for login), and any other API keys you want to use.

There are two ways to run the stack: pull the prebuilt image from GHCR (faster, no build toolchain needed), or build from source (when you're hacking on the code).

Each v* tag pushed to this repo is built and published to the GitHub Container Registry by the workflow in .github/workflows/release.yml.

Want the smallest possible deploy? See deploy/ for a standalone two-file setup (compose + .env) that doesn't require cloning the source. The instructions below assume you've cloned the repo.

1. Clone and configure

git clone https://github.com/Code-Liberation-Front/CarPartPicker.git
cd CarPartPicker
cp .env.example .env             # one file: docker compose + app env

Edit .env — set DB_PASSWORD / DB_PASS (same value in both fields), drop in your Google OAuth credentials, generate a JWT_SECRET (openssl rand -hex 48), and add SMTP creds if you want email alerts. Optionally pin a version by uncommenting APP_IMAGE in .env:

APP_IMAGE=ghcr.io/code-liberation-front/carpartpicker:v1.0.0

If the package is private, log in to GHCR first with a PAT that has read:packages scope:

echo $GITHUB_TOKEN | docker login ghcr.io -u <your-github-user> --password-stdin

Public packages don't need this step.

2. Pull and start

docker compose -f docker/docker-compose.yml --env-file .env pull
docker compose -f docker/docker-compose.yml --env-file .env up -d

Option B — Build from source

Same .env setup as Option A, then build the image locally instead of pulling:

docker compose -f docker/docker-compose.yml --env-file .env up -d --build

Either way, two services come up:

Container Image Role
phpcar ghcr.io/code-liberation-front/carpartpicker:latest (or local build) Apache 2.4 + mod_php 8.2, blocks /core, /vendor, etc., serves HTTP on ${HTTP_PORT}
mysql mysql:8.0 Database (data persists in the db_data volume)

TLS is meant to be handled by your existing reverse proxy (Caddy/nginx/Traefik). Point it at <host>:<HTTP_PORT>. Example Caddy snippet:

https://car.example.com {
    reverse_proxy <host>:8080
}

To upgrade later, bump APP_IMAGE in .env (or just re-pull :latest) and run:

docker compose -f docker/docker-compose.yml --env-file .env pull phpcar
docker compose -f docker/docker-compose.yml --env-file .env up -d phpcar

3. Bootstrap the database (first run only)

docker exec -i mysql mysql -uroot -p"$DB_ROOT_PASSWORD" car < sql/setup.sql
docker exec -i mysql mysql -uroot -p"$DB_ROOT_PASSWORD" car < sql/migrate_estimated_mileage.sql
docker exec -i mysql mysql -uroot -p"$DB_ROOT_PASSWORD" car < sql/migrate_threshold_settings.sql

The first file creates all tables; the two migrations add the mileage-estimation columns and per-vehicle threshold columns introduced after the initial schema.

4. Open it

http://localhost:8080

Sign in with Google, add a vehicle, log a service, and you're off.


⚙️ Configuration

A single .env at the repo root drives both docker compose and the PHP app — compose passes the app keys straight into the phpcar container, no separate in-image config file required. (If a legacy core/.env exists, it is still read as a fallback so older deployments keep working.)

Host-side keys (used by docker compose only)

Key Default Purpose
HTTP_PORT 8080 Host port that phpcar binds to. Point your upstream reverse proxy here.
APP_IMAGE :latest Pin a specific image tag for reproducible deploys.
DB_ROOT_PASSWORD / DB_PASSWORD (required) MySQL provisioning passwords.

App keys (passed into the phpcar container as env vars)

Key Required? Purpose
DB_HOST, DB_NAME, DB_USER, DB_PASS, DB_CHARSET DB connection. DB_HOST=mysql with the bundled compose.
JWT_SECRET for /apis/v1/* HS256 signing key for the mobile API. Must be ≥32 chars. Generate with openssl rand -hex 48.
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET / GOOGLE_REDIRECT_URI for login Web OAuth flow. The redirect URI must match what's registered in Google Cloud and end with /login/google-callback.php.
GOOGLE_OAUTH_ANDROID_CLIENT_ID for mobile sign-in Android OAuth client ID. Verified against the ID token in apis/v1/auth/google.php.
EDMUNDS_API_KEY optional If set, OEM maintenance schedules are pulled per vehicle. Without it, the app uses hardcoded defaults.
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM / SMTP_FROM_NAME optional Daily alert emails. Leave blank to disable mail.
APP_URL optional Public URL used in the "Log this service" CTA on alert emails.
FCM_PROJECT_ID / FCM_SERVICE_ACCOUNT_PATH optional FCM push notifications. Bind-mount the service-account JSON into the container — see deploy/README.md.

📬 Daily email alerts

The script cron/maintenance_alerts.php:

  1. Refreshes every vehicle's daily-mileage rate and projected odometer.
  2. Re-runs the maintenance status check using the projected mileage.
  3. For each item that just flipped to due_soon or overdue, inserts a row into maintenance_alerts (INSERT IGNORE keyed on vehicle/schedule/severity) and emails the owner if SMTP is configured.
  4. Clears maintenance_alerts rows whose item is no longer flagged — so the next time the same service goes due, the user is re-notified.

Schedule it on the host crontab (crontab -e):

0 7 * * * docker exec phpcar php /var/www/html/cron/maintenance_alerts.php >> ~/cpp-cron.log 2>&1

A manual run is fine for testing:

docker exec phpcar php /var/www/html/cron/maintenance_alerts.php

🌐 Production deployment

The same compose stack drives production — the only differences are config:

  1. TLS / domain. Terminate TLS at your existing reverse proxy (Caddy/nginx/Traefik). Point it at <host>:<HTTP_PORT>. Example Caddy: https://cars.example.com { reverse_proxy <host>:8080 }.
  2. DNS. Point your domain's A record at the reverse-proxy host (not necessarily the carpartpicker host).
  3. Google OAuth. In the Google Cloud console, add https://cars.example.com/login/google-callback.php to the authorized redirect URIs. Set GOOGLE_REDIRECT_URI in .env to the same URL, and APP_URL=https://cars.example.com.
  4. SMTP. Generate a Gmail app password (2FA must be enabled) and put it in SMTP_PASS. Use the same address for SMTP_USER / SMTP_FROM.
  5. Edmunds API key (optional). Sign up at the Edmunds developer portal and drop the key in EDMUNDS_API_KEY — every vehicle's maintenance schedule will be richer.
  6. Backups. The MySQL data lives in the db_data named volume. Snapshot it with docker run --rm -v cpp_db_data:/data alpine tar -C /data -czf - . > backup.tgz.

📁 Project layout

.
├── apis/             ← server-side adapters: NHTSA VIN decoder, Edmunds maintenance lookup
├── core/             ← shared PHP: DB singleton, session, env-driven mailer, mileage helpers
├── cron/             ← cron-only entrypoints (daily alert sender)
├── docker/           ← Dockerfile, docker-compose.yml, Apache vhost config
├── garage/           ← user-facing pages (vehicle list, detail dashboard, add)
├── login/            ← email + Google OAuth login flow
├── navbar/           ← shared header partial
├── sql/              ← setup.sql + migration files
├── index.php         ← marketing/home page
└── README.md         ← you're here

🗺 Roadmap / known gaps

  • Move the daily alert cron into the compose stack as a sibling service so deployment doesn't require host-side crontab editing.
  • The image speaks plain HTTP; if you don't already have a reverse proxy, document a one-shot path (e.g. Cloudflare Tunnel or a local Caddy container snippet).
  • Capture screenshots into docs/screenshots/ for the README preview block.
  • Test suite. There isn't one yet.

📜 License

Add your preferred license here (MIT / Apache-2.0 / GPL-3.0). The project ships without one by default — until you add a LICENSE file, all rights are reserved.