owain a9b3da858d
Build and push images / validate (push) Successful in 2s
Build and push images / build-backend (push) Successful in 6s
Build and push images / build-worker (push) Successful in 5s
Build and push images / build-frontend (push) Successful in 5s
Fix five code-review findings: token auth, sync rate-limiting, model drift, FK cascade
- garmin_connect_sync: revert to garth.loads() for token auth — login(tokenstore=)
  dispatches on len>512, treating compact tokens as filesystem paths and forcing a
  full re-login on every sync. Explicitly set display_name from the embedded profile.
- garmin_connect_sync: restore incremental sync for both activities and wellness —
  always re-fetching the full lookback window was generating ~270 Garmin API calls
  per wellness sync run, risking rate-limits. Now uses since-1d when since is set.
  Add 0.25s per-day sleep in sync_wellness as an additional rate-limit guard.
- models/user.py: replace the dropped uq_pr_current UniqueConstraint in
  PersonalRecord.__table_args__ with the partial Index the DB actually has,
  so the model and live schema no longer permanently diverge.
- models/user.py: add ondelete="SET NULL" to Activity.named_route_id FK so the
  DB cascade handles unlinks if routes are deleted outside the API endpoint.
- main.py: add startup migration to re-add activities_named_route_id_fkey with
  ON DELETE SET NULL on existing deployments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 10:30:20 +01:00
2026-06-06 13:23:33 +01:00
2026-06-06 18:10:35 +01:00
2026-06-06 13:23:33 +01:00
2026-06-06 13:23:33 +01:00

MileVault

Self-hosted fitness tracking — Garmin & Strava import, maps, health trends, personal records.


For users — deploy with two files

Once this repo is pushed to Gitea and the Actions workflow has run once, anyone on your network only needs two files to run MileVault. No source code, no cloning.

mkdir milevault && cd milevault

# Download the two deployment files
curl -O https://gitea.yourdomain.com/yourusername/milevault/raw/branch/main/docker-compose.deploy.yml
curl -O https://gitea.yourdomain.com/yourusername/milevault/raw/branch/main/nginx.conf

# Start (images pulled automatically from your Gitea registry)
docker compose -f docker-compose.deploy.yml up -d

Default login: admin / admin
Change ADMIN_PASSWORD in a .env file before exposing to a network (see Configuration below).

To update when a new version is pushed to Gitea:

docker compose -f docker-compose.deploy.yml pull
docker compose -f docker-compose.deploy.yml up -d

For developers — first-time Gitea setup

1. Enable the Gitea container registry

In your Gitea instance (app.ini or admin panel):

[packages]
ENABLED = true

Restart Gitea. The registry is then available at gitea.yourdomain.com.

2. Create a Gitea Actions runner

Gitea Actions needs a runner on your server:

# On the server that will build images
docker run -d \
  --name gitea-runner \
  --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v gitea-runner-data:/data \
  -e GITEA_INSTANCE_URL=https://gitea.yourdomain.com \
  -e GITEA_RUNNER_REGISTRATION_TOKEN=<token from Gitea → Settings → Runners> \
  gitea/act_runner:latest

Get the registration token from: Gitea → Your repo → Settings → Actions → Runners → Create Runner

3. Create a package token

The workflow needs a token to push images to the registry:

  1. Gitea → Your profile → Settings → Applications → Generate Token
  2. Scopes: tick write:package
  3. Copy the token

Then in your repo: Settings → Secrets → Actions → Add Secret

  • Name: PACKAGE_TOKEN
  • Value: the token you just copied

4. Set the registry URL variable

In your repo: Settings → Variables → Actions → Add Variable

  • Name: GITEA_URL
  • Value: gitea.yourdomain.com (no https://)

5. Push the repo

git remote add origin https://gitea.yourdomain.com/yourusername/milevault.git
git push -u origin main

The Actions workflow (.gitea/workflows/build.yml) triggers automatically, builds all three images, and pushes them to your Gitea registry. Check progress under Actions in the Gitea UI.

6. Update docker-compose.deploy.yml

Before the first deploy, replace the placeholder registry URLs in docker-compose.deploy.yml:

gitea.yourdomain.com/yourusername/  →  your actual Gitea host and username

Configuration

Create a .env file next to docker-compose.deploy.yml to override any defaults:

# Admin login
ADMIN_USERNAME=admin
ADMIN_PASSWORD=a_strong_password_here

# Generate with: openssl rand -hex 32
SECRET_KEY=

# Ports
HTTP_PORT=80

# Optional: Mapbox token for satellite tiles
VITE_MAPBOX_TOKEN=

# Optional: PocketID passkey auth
POCKETID_ISSUER=
POCKETID_CLIENT_ID=
POCKETID_CLIENT_SECRET=

Docker Compose picks up .env automatically.


If your Gitea registry requires authentication to pull

If your Gitea instance is private, add a pull secret on the deploy machine:

docker login gitea.yourdomain.com
# enter your Gitea username and password (or a read:package token)

Docker stores the credentials in ~/.docker/config.json and uses them automatically on docker compose pull.


Repo structure

.gitea/workflows/build.yml   ← Gitea Actions: builds & pushes images on push to main
docker-compose.yml           ← dev/build compose (builds from source)
docker-compose.deploy.yml    ← production compose (pulls pre-built images)
nginx.conf                   ← standalone nginx config for deploy compose
backend/                     ← FastAPI + Celery worker
frontend/                    ← React + Vite
nginx/nginx.conf             ← nginx config for dev compose
docker/init.sql              ← DB init (enables TimescaleDB extension)
S
Description
No description provided
Readme 1.5 MiB
Languages
JavaScript 49.3%
Python 47.1%
Shell 3.1%
CSS 0.2%
Dockerfile 0.2%