docs: add and refine project documentation #41

Open
McPringle wants to merge 1 commit from McPringle/docs/add-project-documentation into main
5 changed files with 559 additions and 358 deletions

View file

@ -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=

273
CONTAINERS.md Normal file
View file

@ -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 <repository-url>
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)

174
CONTRIBUTING.md Normal file
View file

@ -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 <repository-url>
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.

350
DOCKER.md
View file

@ -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 <repository-url>
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
```

71
README.md Normal file
View file

@ -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.