- Never include "Co-Authored-By: Claude" or similar AI attribution lines in commits
- Use conventional commit format for organized commit history:
feat: description- New featuresfix: description- Bug fixesperf: description- Performance improvementsdeps: description- Dependency updatesdocs: description- Documentation changesci: description- CI/CD changeschore: description- Other changes
mainbranch: Production - only receives changes via pull requests fromdevdevbranch: Testing/development - all new features and changes go here first
- All new features and changes are committed and pushed to the
devbranch - Test changes thoroughly on
dev - When ready for production, create a pull request from
devtomain - Include a comprehensive changelog in the PR description listing all changes
- After merge, the GitHub Actions workflow builds and pushes the production Docker image
May is a self-hosted vehicle management application built with Flask. It tracks fuel consumption, expenses, maintenance, trips, EV charging, and more.
- Backend: Flask (Python 3.12)
- Database: SQLite with SQLAlchemy ORM
- Frontend: Jinja2 templates with Tailwind CSS
- Charts: Chart.js
- PDF Generation: WeasyPrint
- Production Server: Gunicorn
may/
├── app/
│ ├── __init__.py # App factory, blueprint registration
│ ├── models.py # SQLAlchemy models (User, Vehicle, FuelLog, etc.)
│ ├── routes/ # Blueprint route handlers
│ │ ├── main.py # Dashboard, timeline
│ │ ├── auth.py # Login, register, settings
│ │ ├── vehicles.py # Vehicle CRUD
│ │ ├── fuel.py # Fuel logging
│ │ ├── expenses.py # Expense tracking
│ │ ├── trips.py # Trip logging
│ │ ├── charging.py # EV charging sessions
│ │ ├── stations.py # Fuel stations, price tracking
│ │ └── ...
│ ├── templates/ # Jinja2 templates
│ └── static/ # CSS, JS, images
├── config.py # App configuration, version
├── run.py # App entry point
├── Dockerfile # Container build
├── docker-compose.yml # Docker deployment
└── docker-entrypoint.sh # Handles bind mount permissions
- User: Authentication, preferences, menu visibility settings
- Vehicle: Cars, motorcycles, etc. with fuel type support
- FuelLog: Fuel fill-ups with consumption calculation
- Expense: Maintenance, insurance, tax, etc.
- Trip: Business/personal trip logging for tax purposes
- ChargingSession: EV charging with kWh, SOC%, cost
- AppSettings: Key-value store for app-wide settings (branding, registration toggle)
SQLite database stored at /data/may.db. The project uses Flask-Migrate (Alembic) for database migrations.
# Initialize migrations folder (only once)
flask db init
# Create initial migration from existing models
flask db migrate -m "Initial migration"
# Apply migrations
flask db upgradeWhen you change models:
flask db migrate -m "Description of changes"
flask db upgradeMigrations run automatically on container startup via the entrypoint script.
The project uses GitHub Actions (.github/workflows/docker-build.yml) to automatically build and push Docker images:
- On push to
main,dev, or new tags, the workflow triggers - Builds a multi-platform Docker image (linux/amd64, linux/arm64)
- Pushes to GitHub Container Registry:
ghcr.io/dannymcc/may - Tags:
latestfor main branch,devfor dev branch, version tags (e.g.,v0.3.0) for releases
- Update
APP_VERSIONinconfig.py - Commit the version bump to
dev - Create a pull request from
devtomainwith comprehensive changelog - Merge the PR to
main - Create and push a version tag:
git checkout main git pull origin main git tag v0.X.0 git push origin v0.X.0
- Create the GitHub release with changelog:
gh release create v0.X.0 --title "v0.X.0" --notes "## What's Changed ### New Features - Feature description ### Bug Fixes - Fix description ### Other Changes - Change description"
- GitHub Actions automatically builds and pushes the Docker image with version tag
- Sync
devwithmainafter release:git checkout dev git reset --hard origin/main git push origin dev --force
The container:
- Exposes port 5050 (not 5000)
- Runs as non-root user
mayvia entrypoint script - Handles bind mount permissions automatically
- Health check endpoint:
/health
Example docker-compose.yml for deployment:
services:
may:
image: ghcr.io/dannymcc/may:latest
container_name: may
restart: unless-stopped
ports:
- "5050:5050"
volumes:
- ./data:/app/data
environment:
- SECRET_KEY=your-secret-keyWhen using Caddy as a reverse proxy with May running in Docker:
- Connect both containers to the same Docker network
- Use the container name and internal port:
reverse_proxy may:5050
# Create virtual environment
python -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run development server
python run.pyDefault login: admin / admin