From ef148ae20e01ad3f355151b4bf13ff704327589b Mon Sep 17 00:00:00 2001 From: Marcus Fihlon Date: Sat, 2 May 2026 17:37:27 +0200 Subject: [PATCH] docs: add and refine project documentation Signed-off-by: Marcus Fihlon --- .env.example | 49 +++++-- CONTAINERS.md | 273 +++++++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 174 ++++++++++++++++++++++++ DOCKER.md | 350 ------------------------------------------------ README.md | 71 ++++++++++ 5 files changed, 559 insertions(+), 358 deletions(-) create mode 100644 CONTAINERS.md create mode 100644 CONTRIBUTING.md delete mode 100644 DOCKER.md create mode 100644 README.md diff --git a/.env.example b/.env.example index 5ee27e4..030b1c1 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,46 @@ -# FitPub Environment Configuration +# FitPub environment configuration +# +# This file mirrors the environment variables referenced by the Spring +# configuration and uses the same effective defaults as the development profile +# where defaults exist. -# Registration Settings -# Leave empty for open registration, or set a password to require it for new signups -REGISTRATION_PASSWORD= +# Spring profile +# Use `prod` for production deployments. +# SPRING_PROFILES_ACTIVE=dev -# Example with password (uncomment to enable): -# REGISTRATION_PASSWORD=my-secret-invite-code-2024 +# Local PostgreSQL / PostGIS +# SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/fitpub +# SPRING_DATASOURCE_USERNAME=fitpub +# SPRING_DATASOURCE_PASSWORD=change_me_in_production -# Other settings -# REGISTRATION_ENABLED=true +# Server +# PORT=8080 + +# Public FitPub URLs # FITPUB_DOMAIN=localhost:8080 # FITPUB_BASE_URL=http://localhost:8080 + +# ActivityPub +# FITPUB_ALLOW_PRIVATE_IPS=false +# FITPUB_FEDERATION_PROTOCOL=https + +# Authentication +# JWT_SECRET=dev-secret-key-change-in-production-must-be-at-least-32-characters-long + +# Registration +# REGISTRATION_ENABLED=true +# Leave empty for open registration, or set a password to require it for new signups +# REGISTRATION_PASSWORD= + +# Storage +# Application default is ${java.io.tmpdir}/fitpub/images +# FITPUB_IMAGES_PATH=/tmp/fitpub/images +# Application default is ${java.io.tmpdir}/fitpub/tiles +# FITPUB_TILE_CACHE_PATH=/tmp/fitpub/tiles + +# Image generation +# OSM_TILES_ENABLED=true + +# Weather +# WEATHER_ENABLED=false +# OPENWEATHERMAP_API_KEY= diff --git a/CONTAINERS.md b/CONTAINERS.md new file mode 100644 index 0000000..88fb585 --- /dev/null +++ b/CONTAINERS.md @@ -0,0 +1,273 @@ +# Container Deployment Guide + +This guide explains how to run FitPub with containers using either Docker or Podman. + +The repository ships a `docker-compose.yml` file. Despite the name, it can also be used with Podman-compatible compose tooling. + +## Supported runtimes + +- Docker Engine with the `docker compose` plugin +- Podman with `podman compose` or another compatible compose frontend + +Examples in this guide use both command styles where that adds clarity: + +```bash +docker compose ... +podman compose ... +``` + +If your environment uses a different compose wrapper, adapt the command prefix accordingly. + +## Quick start + +### 1. Clone the repository + +```bash +git clone +cd fitpub +``` + +### 2. Create an environment file + +```bash +cp .env.example .env +``` + +### 3. Set production values + +At minimum, review and set the following values in `.env`: + +```bash +SPRING_PROFILES_ACTIVE=prod +POSTGRES_DB=fitpub +POSTGRES_USER=fitpub +POSTGRES_PASSWORD=change-this +APP_PORT=8080 +FITPUB_DOMAIN=your-domain.com +FITPUB_BASE_URL=https://your-domain.com +JWT_SECRET=replace-with-a-long-random-secret +``` + +Recommended command for generating secrets for values such as `JWT_SECRET` and `POSTGRES_PASSWORD`: + +```bash +openssl rand -base64 64 +``` + +### 4. Start the stack + +```bash +docker compose up -d --build +podman compose up -d --build +``` + +### 5. Verify the deployment + +FitPub should become available at: + +- Application: `http://localhost:8080` or your configured public URL +- Health check endpoint: `http://localhost:8080/actuator/health` + +## Environment variables used by the container stack + +The compose file expects these variables: + +| Variable | Purpose | Example / default | +|--------------------------|---------------------------------------------|---------------------------| +| `SPRING_PROFILES_ACTIVE` | Spring profile for the app container | `prod` | +| `POSTGRES_DB` | PostgreSQL database name | `fitpub` | +| `POSTGRES_USER` | PostgreSQL user | `fitpub` | +| `POSTGRES_PASSWORD` | PostgreSQL password | set explicitly | +| `POSTGRES_PORT` | Host port for PostgreSQL | `5432` | +| `APP_PORT` | Host port for FitPub | `8080` | +| `FITPUB_DOMAIN` | Public domain used by the app | `your-domain.com` | +| `FITPUB_BASE_URL` | Public base URL | `https://your-domain.com` | +| `JWT_SECRET` | JWT signing secret | set explicitly | +| `JWT_EXPIRATION_MS` | JWT token lifetime | `86400000` | +| `REGISTRATION_PASSWORD` | Optional invite-style registration password | empty | +| `JPA_SHOW_SQL` | Enable SQL logging | `false` | +| `JPA_FORMAT_SQL` | Format SQL logs | `false` | +| `LOG_LEVEL_ROOT` | Root log level | `INFO` | +| `LOG_LEVEL_APP` | App log level | `INFO` | +| `LOG_LEVEL_SPRING` | Spring log level | `INFO` | +| `LOG_LEVEL_HIBERNATE` | Hibernate log level | `WARN` | +| `LOG_LEVEL_FLYWAY` | Flyway log level | `INFO` | + +`.env.example` documents the application-level environment variables and defaults. The compose file adds a smaller set of container-specific variables around database wiring, ports, and log levels. + +## Services + +### `postgres` + +- Image: `postgis/postgis:16-3.4` +- Exposes container port `5432` +- Uses the named volume `postgres_data` +- Runs a `pg_isready` health check + +### `app` + +- Built from the repository `Dockerfile` +- Exposes container port `8080` +- Uses the named volumes `app_uploads` and `app_logs` +- Waits for the database health check before starting +- Publishes a health check on `/actuator/health` + +## Common operations + +### Show logs + +```bash +docker compose logs -f +docker compose logs -f app +docker compose logs -f postgres +``` + +```bash +podman compose logs -f +podman compose logs -f app +podman compose logs -f postgres +``` + +### Restart services + +```bash +docker compose restart +docker compose restart app +``` + +```bash +podman compose restart +podman compose restart app +``` + +### Stop and remove the stack + +```bash +docker compose stop +docker compose down +docker compose down -v +``` + +```bash +podman compose stop +podman compose down +podman compose down -v +``` + +`down -v` removes persistent volumes and deletes database data. + +### Run commands inside containers + +```bash +docker compose exec app bash +docker compose exec postgres psql -U fitpub -d fitpub +``` + +```bash +podman compose exec app bash +podman compose exec postgres psql -U fitpub -d fitpub +``` + +### Rebuild the application image + +```bash +docker compose up -d --build app +docker compose build --no-cache app +``` + +```bash +podman compose up -d --build app +podman compose build --no-cache app +``` + +## Volumes and backups + +The compose stack creates these named volumes: + +- `postgres_data` +- `app_uploads` +- `app_logs` + +Examples with Docker: + +```bash +docker volume ls | grep fitpub +docker volume inspect fitpub_postgres_data +docker run --rm -v fitpub_postgres_data:/data -v "$(pwd)":/backup \ + alpine tar czf /backup/postgres-backup-YYYYMMDD.tar.gz -C /data . +``` + +Examples with Podman: + +```bash +podman volume ls +podman volume inspect fitpub_postgres_data +podman run --rm -v fitpub_postgres_data:/data -v "$(pwd)":/backup \ + docker.io/library/alpine tar czf /backup/postgres-backup-YYYYMMDD.tar.gz -C /data . +``` + +Actual volume names can vary with the compose project name. Inspect the stack locally if your names differ. + +## Health checks and troubleshooting + +### Application health + +```bash +curl http://localhost:8080/actuator/health +``` + +### Database readiness + +```bash +docker compose exec postgres pg_isready -U fitpub +podman compose exec postgres pg_isready -U fitpub +``` + +### Check rendered compose configuration + +```bash +docker compose config +podman compose config +``` + +### Migration issues + +```bash +docker compose exec postgres psql -U fitpub -d fitpub -c \ + "SELECT * FROM flyway_schema_history ORDER BY installed_rank;" +``` + +```bash +podman compose exec postgres psql -U fitpub -d fitpub -c \ + "SELECT * FROM flyway_schema_history ORDER BY installed_rank;" +``` + +### Reset the stack + +```bash +docker compose down -v +docker compose up -d --build +``` + +```bash +podman compose down -v +podman compose up -d --build +``` + +This removes all persisted data. + +## Production notes + +- Set `SPRING_PROFILES_ACTIVE=prod` +- Use strong, unique values for `POSTGRES_PASSWORD` and `JWT_SECRET` +- Put FitPub behind HTTPS via a reverse proxy such as nginx, Traefik, or Caddy +- Back up the database volume regularly +- Review exposed ports and firewall rules +- Keep the container runtime and base images updated + +## Related files + +- [README.md](./README.md) +- [CONTRIBUTING.md](./CONTRIBUTING.md) +- [docker-compose.yml](./docker-compose.yml) +- [Dockerfile](./Dockerfile) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..52c17bf --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,174 @@ +# Contributing to FitPub + +Thanks for contributing to FitPub. + +This document covers the practical workflow for working on the codebase: setting up a local environment, running the application, executing tests, and preparing changes for review. + +## Before you start + +- Read the [README.md](./README.md) for project context +- Check whether an issue already exists for the change you want to make +- Keep changes focused; avoid mixing unrelated refactors with feature work or bug fixes + +## Development environment + +FitPub currently targets: + +- Java 17 +- Maven Wrapper (`./mvnw`) +- PostgreSQL with PostGIS +- Docker or Podman for local services and Testcontainers-based tests + +The repository includes an `.sdkmanrc` file with Java 17 if you use SDKMAN. + +## Local setup + +### 1. Clone the repository + +```bash +git clone +cd fitpub +``` + +### 2. Start PostgreSQL with PostGIS + +The development profile expects a local PostgreSQL instance on port `5432`. + +You can use either Docker or Podman. Example with Docker: + +```bash +docker run -d \ + --name fitpub-postgres \ + -p 5432:5432 \ + -e POSTGRES_DB=fitpub \ + -e POSTGRES_USER=fitpub \ + -e POSTGRES_PASSWORD=change_me_in_production \ + postgis/postgis:16-3.4 +``` + +If you prefer a Compose-based setup, see [CONTAINERS.md](./CONTAINERS.md). The same container layout can also be run with Podman-compatible compose tooling. + +### 3. Optional environment configuration + +The application reads configuration from environment variables, but the development profile already provides sensible defaults for the usual local setup. + +In most cases, you can start the application without setting anything beyond the local PostgreSQL/PostGIS instance. + +If you want to override defaults or configure registration behavior, copy the example file: + +```bash +cp .env.example .env +``` + +Then add or adjust values in `.env` as needed. + +`.env.example` documents the available overrides together with the defaults used for local development. + +For local work, the application defaults to the `dev` profile. For production deployments, set: + +```bash +SPRING_PROFILES_ACTIVE=prod +``` + +## Running the application + +Start the app with the development profile: + +```bash +./mvnw spring-boot:run -Dspring-boot.run.profiles=dev +``` + +By default, the application runs at `http://localhost:8080`. + +The development profile uses: + +- Flyway for schema migrations +- verbose SQL and application logging +- a development JWT secret unless you override it + +## Building + +Create the application artifact with: + +```bash +./mvnw clean package +``` + +## Testing + +Run the full test suite with: + +```bash +./mvnw test +``` + +Important notes: + +- Tests use Testcontainers and require a working local container runtime such as Docker or Podman +- The test configuration provisions PostgreSQL/PostGIS automatically +- Some tests exercise file parsing and integration flows, so the suite is heavier than a pure unit-test run + +To run a single test class or method: + +```bash +./mvnw test -Dtest=ActivityImageServiceTest +./mvnw test -Dtest=ActivityImageServiceTest#testGenerateActivityImage_Manual +``` + +## Database and migrations + +- Database schema changes should go through Flyway migrations in `src/main/resources/db/migration/` +- Do not rely on Hibernate schema generation for persistent changes +- Keep migrations forward-only and review them carefully for compatibility with existing data + +## Code style + +There is no fully codified style toolchain checked into the repository at the moment, so contributors should follow the existing codebase closely. + +In practice, that means: + +- keep naming and package structure consistent with surrounding code +- prefer small, focused controller, service, and repository changes +- add tests for behavior changes and regressions +- avoid incidental formatting churn in unrelated files + +## Pull requests + +When opening a pull request: + +- explain the problem being solved +- describe the behavior change clearly +- mention any schema, API, or federation impact +- include screenshots for UI changes when useful +- call out follow-up work explicitly instead of bundling it into the same PR + +Before submitting, make sure: + +- the application builds successfully +- relevant tests pass locally +- new migrations have been validated +- documentation is updated when behavior or setup changed + +## Commit guidance + +There is no strict commit convention enforced by the repository, but clear history helps review. + +Prefer commits that: + +- have a single purpose +- use descriptive messages +- avoid mixing cleanup with functional changes + +## Security and privacy + +FitPub handles personal activity data, location data, and federation-facing endpoints. + +Please treat the following areas carefully: + +- privacy-zone behavior +- activity visibility rules +- authentication and JWT handling +- ActivityPub request validation and outbound federation logic +- file upload and parsing paths + +If you find a security issue, prefer responsible disclosure over opening a public issue with exploit details. diff --git a/DOCKER.md b/DOCKER.md deleted file mode 100644 index 5d63f07..0000000 --- a/DOCKER.md +++ /dev/null @@ -1,350 +0,0 @@ -# Docker Deployment Guide - -This guide explains how to deploy FitPub using Docker and Docker Compose. - -## Prerequisites - -- Docker Engine 20.10 or later -- Docker Compose 2.0 or later - -## Quick Start - -### 1. Clone the Repository - -```bash -git clone -cd feditrack -``` - -### 2. Create Environment File - -Copy the example environment file and customize it: - -```bash -cp .env.example .env -``` - -### 3. Configure Environment Variables - -Edit `.env` and update the following critical values: - -**Security (REQUIRED):** -```bash -# Generate a secure JWT secret -JWT_SECRET=$(openssl rand -base64 64) - -# Use a strong database password -POSTGRES_PASSWORD=$(openssl rand -base64 32) -``` - -**Domain Configuration (REQUIRED):** -```bash -APP_DOMAIN=your-domain.com -APP_BASE_URL=https://your-domain.com -``` - -### 4. Start the Application - -```bash -# Start all services -docker-compose up -d - -# View logs -docker-compose logs -f - -# Check service status -docker-compose ps -``` - -### 5. Verify Deployment - -The application should be available at: -- Application: http://localhost:8080 -- Health Check: http://localhost:8080/actuator/health - -## Environment Variables - -See `.env.example` for all available configuration options: - -| Variable | Description | Default | -|----------|-------------|---------| -| `POSTGRES_DB` | Database name | fitpub | -| `POSTGRES_USER` | Database user | fitpub | -| `POSTGRES_PASSWORD` | Database password | **MUST CHANGE** | -| `POSTGRES_PORT` | Database port | 5432 | -| `APP_PORT` | Application port | 8080 | -| `APP_DOMAIN` | Your domain name | example.com | -| `APP_BASE_URL` | Full application URL | https://example.com | -| `JWT_SECRET` | JWT signing secret | **MUST CHANGE** | -| `JWT_EXPIRATION_MS` | JWT expiration time | 86400000 (24h) | - -## Docker Compose Services - -### postgres -- **Image:** postgis/postgis:16-3.4 -- **Port:** 5432 (configurable via POSTGRES_PORT) -- **Volume:** `postgres_data` - Persistent database storage -- **Health Check:** PostgreSQL readiness check - -### app -- **Build:** From Dockerfile -- **Port:** 8080 (configurable via APP_PORT) -- **Volumes:** - - `app_uploads` - User uploaded files - - `app_logs` - Application logs -- **Health Check:** Spring Boot Actuator health endpoint -- **Depends On:** postgres (waits for healthy state) - -## Volumes - -Three named volumes are created for data persistence: - -```bash -# List volumes -docker volume ls | grep fitpub - -# Inspect volume -docker volume inspect feditrack_postgres_data - -# Backup database volume -docker run --rm -v feditrack_postgres_data:/data -v $(pwd):/backup \ - alpine tar czf /backup/postgres-backup-$(date +%Y%m%d).tar.gz -C /data . - -# Restore database volume -docker run --rm -v feditrack_postgres_data:/data -v $(pwd):/backup \ - alpine tar xzf /backup/postgres-backup-YYYYMMDD.tar.gz -C /data -``` - -## Common Operations - -### View Logs - -```bash -# All services -docker-compose logs -f - -# Specific service -docker-compose logs -f app -docker-compose logs -f postgres -``` - -### Restart Services - -```bash -# Restart all services -docker-compose restart - -# Restart specific service -docker-compose restart app -``` - -### Stop Services - -```bash -# Stop services (keeps containers) -docker-compose stop - -# Stop and remove containers (keeps volumes) -docker-compose down - -# Stop and remove everything including volumes (DANGER: data loss) -docker-compose down -v -``` - -### Execute Commands in Container - -```bash -# Access app container shell -docker-compose exec app bash - -# Access PostgreSQL CLI -docker-compose exec postgres psql -U fitpub -d fitpub - -# Run SQL query -docker-compose exec postgres psql -U fitpub -d fitpub -c "SELECT version();" -``` - -### Database Operations - -```bash -# Create database backup -docker-compose exec postgres pg_dump -U fitpub fitpub > backup.sql - -# Restore database backup -docker-compose exec -T postgres psql -U fitpub fitpub < backup.sql - -# Check Flyway migration status -docker-compose exec postgres psql -U fitpub -d fitpub -c \ - "SELECT * FROM flyway_schema_history ORDER BY installed_rank;" -``` - -### Rebuild Application - -```bash -# Rebuild and restart app -docker-compose up -d --build app - -# Force rebuild without cache -docker-compose build --no-cache app -docker-compose up -d app -``` - -## Production Deployment - -### Security Checklist - -- [ ] Change `POSTGRES_PASSWORD` to a strong random password -- [ ] Generate secure `JWT_SECRET` using `openssl rand -base64 64` -- [ ] Set correct `APP_DOMAIN` and `APP_BASE_URL` -- [ ] Configure HTTPS/TLS (use reverse proxy like nginx or Traefik) -- [ ] Disable `JPA_SHOW_SQL` and `JPA_FORMAT_SQL` -- [ ] Set appropriate log levels (INFO or WARN for production) -- [ ] Configure firewall rules (only expose necessary ports) -- [ ] Set up regular database backups -- [ ] Configure volume backup strategy -- [ ] Review and restrict network access - -### Reverse Proxy Example (nginx) - -```nginx -server { - listen 80; - server_name your-domain.com; - return 301 https://$server_name$request_uri; -} - -server { - listen 443 ssl http2; - server_name your-domain.com; - - ssl_certificate /path/to/cert.pem; - ssl_certificate_key /path/to/key.pem; - - location / { - proxy_pass http://localhost:8080; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -} -``` - -## Monitoring - -### Health Checks - -```bash -# Application health -curl http://localhost:8080/actuator/health - -# Database health -docker-compose exec postgres pg_isready -U fitpub -``` - -### Resource Usage - -```bash -# Container stats -docker stats - -# Specific container stats -docker stats fitpub-app fitpub-postgres -``` - -## Troubleshooting - -### Application Won't Start - -```bash -# Check logs -docker-compose logs app - -# Check if database is ready -docker-compose ps postgres -docker-compose exec postgres pg_isready -U fitpub - -# Verify environment variables -docker-compose config -``` - -### Database Connection Issues - -```bash -# Check PostgreSQL logs -docker-compose logs postgres - -# Test database connection -docker-compose exec postgres psql -U fitpub -d fitpub -c "SELECT 1;" - -# Check network connectivity -docker-compose exec app ping postgres -``` - -### Migration Failures - -```bash -# Check Flyway schema history -docker-compose exec postgres psql -U fitpub -d fitpub -c \ - "SELECT * FROM flyway_schema_history;" - -# Reset database (DANGER: data loss) -docker-compose down -v -docker-compose up -d -``` - -### Out of Disk Space - -```bash -# Check Docker disk usage -docker system df - -# Clean up unused resources -docker system prune -a --volumes - -# Remove specific volume -docker volume rm feditrack_postgres_data -``` - -## Development Mode - -For local development with live reload: - -```bash -# Use development profile -echo "SPRING_PROFILES_ACTIVE=dev" >> .env - -# Enable SQL logging -echo "JPA_SHOW_SQL=true" >> .env -echo "JPA_FORMAT_SQL=true" >> .env - -# Mount source code for live reload (modify docker-compose.yml) -# Add under app.volumes: -# - ./src:/app/src -``` - -## Scaling - -To run multiple app instances behind a load balancer: - -```bash -# Scale app service -docker-compose up -d --scale app=3 - -# Note: You'll need to configure a load balancer and remove -# the container_name directive from docker-compose.yml -``` - -## Updating - -```bash -# Pull latest code -git pull - -# Rebuild and restart -docker-compose down -docker-compose up -d --build - -# Check migration status -docker-compose logs app | grep -i flyway -``` diff --git a/README.md b/README.md new file mode 100644 index 0000000..8809c86 --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# FitPub + +FitPub is a self-hosted fitness tracking platform for the Fediverse. It lets people upload workout files, review their activities with maps and metrics, and share them through ActivityPub instead of locking them into a closed social network. + +The project is built for people who want to keep control of their training data while still participating in a social graph that reaches Mastodon-compatible platforms and other ActivityPub servers. + +## What FitPub does + +- Imports activity files from GPS devices and training apps +- Supports FIT and GPX uploads +- Publishes activities to followers over ActivityPub +- Provides public, followers-only, and private visibility modes +- Applies privacy zones to protect sensitive start and end locations +- Shows maps, metrics, timelines, and profile pages in a server-rendered web UI +- Includes analytics such as summaries, personal records, achievements, training load, and heatmaps +- Supports batch imports from ZIP archives + +## Why this project exists + +Most fitness platforms combine activity storage, analysis, and social distribution inside one vendor-controlled product. FitPub separates those concerns. You can run your own instance, keep your own data, and still share workouts with people on the wider Fediverse. + +## Stack + +FitPub is built with: + +- Java 17 +- Spring Boot 3 +- Thymeleaf +- PostgreSQL with PostGIS +- Flyway +- ActivityPub-compatible federation + +## Project layout + +- `src/main/java/` - application code +- `src/main/resources/templates/` - server-rendered views +- `src/main/resources/static/` - frontend assets +- `src/main/resources/db/migration/` - Flyway database migrations +- `src/test/` - automated tests +- `CONTAINERS.md` - container deployment notes for Docker- or Podman-based setups + +## Deployment + +FitPub is intended to be self-hosted. + +For container-based deployment, see [CONTAINERS.md](./CONTAINERS.md). + +## Current scope + +The repository already includes: + +- local accounts and authentication +- activity upload and post-processing +- federation endpoints and delivery logic +- social features such as follows, comments, likes, notifications, and timelines +- analytics and heatmap views +- privacy-zone filtering for track data + +## Status + +FitPub is an actively developed public project. The feature set is already substantial, but the codebase is still evolving and interface details may change as the platform matures. + +## Contributing + +Issues and pull requests are welcome. + +For contributor workflow, local setup, build steps, and test execution, see [CONTRIBUTING.md](./CONTRIBUTING.md). + +## License + +No license file is currently present in this repository. Until one is added, reuse terms are not explicitly defined. -- 2.49.1