Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a0f08c2
add dev-postgres-powersync environment
Dieterbe Jul 29, 2024
6a23da8
Add a test powersync key pair
rolandgeider Aug 11, 2024
d824037
Update JWT powersync keys
rolandgeider Sep 8, 2024
ff62163
add more startup options
Dieterbe Aug 2, 2024
aa16ad8
fixes/tweaks
Dieterbe Sep 16, 2024
0768da6
Build pg_ivm postgres extension to be used with powersync
rolandgeider Sep 25, 2024
8af9a68
Simplify powersync docker-compose.yml file
rolandgeider Sep 26, 2024
da8b0a7
Add dockerfile for development
rolandgeider Oct 16, 2024
5e4bc42
Move development file to the server repo
rolandgeider Oct 16, 2024
88848c4
cleanup
Dieterbe Oct 12, 2024
024dc14
update sync rules
Dieterbe Oct 12, 2024
ecda257
ivm aliases
Dieterbe Oct 17, 2024
a0c8307
fix
Dieterbe Oct 31, 2024
549437f
Merge branch 'master' into feature/dev-postgres-powersync
rolandgeider Oct 19, 2025
36d6b1e
Post merge fixes...
rolandgeider Oct 19, 2025
964909e
Bump ivm version
rolandgeider Oct 19, 2025
bb518ec
Add exercise tables to sync rules
rolandgeider Oct 24, 2025
ac59782
Update sync rules
rolandgeider Oct 25, 2025
9caca8d
Configure the powersync URL
rolandgeider Nov 4, 2025
bd52d23
Bump mongo version
rolandgeider Nov 4, 2025
282d028
Add missing data buckets
rolandgeider Nov 4, 2025
0b1cbac
When using an android emulator use the internal ip
rolandgeider Nov 23, 2025
d89ae8a
Move the initialization of the replica set to the health check
rolandgeider Feb 20, 2026
69b0676
Add WGER_PORT and DJANGO_COLLECTSTATIC_ON_STARTUP settings to prod.env
rolandgeider Mar 8, 2026
7b6ec8a
Merge branch 'master' into feature/dev-postgres-powersync
rolandgeider Mar 8, 2026
bc63868
Use the "docker.io" prefix for image names for consistency
rolandgeider Mar 12, 2026
638220e
Option doesn't exist anymore
rolandgeider Mar 12, 2026
6346bac
No need to compile pg_ivm, this is not used anymore
rolandgeider Mar 12, 2026
d041bac
Move sync rules to streams, which finally support JOINs
rolandgeider Mar 14, 2026
5eafccd
Cleanup
rolandgeider Mar 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/config/Caddyfile
/docker-compose.override.yml
/dev-postgres/.env
/dev-postgres-powersync/.env
/dev/.env
16 changes: 16 additions & 0 deletions config/dev.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
DJANGO_DEBUG=True
WGER_USE_GUNICORN=False
EXERCISE_CACHE_TTL=30
DJANGO_PERFORM_MIGRATIONS=True
SYNC_EXERCISES_ON_STARTUP=False
DOWNLOAD_EXERCISE_IMAGES_ON_STARTUP=False
DOWNLOAD_EXERCISE_VIDEOS_ON_STARTUP=False
LOAD_ONLINE_FIXTURES_ON_STARTUP=False # a couple of ingredients
AXES_ENABLED=False
DJANGO_STORAGES_STATICFILES_BACKEND=django.contrib.staticfiles.storage.StaticFilesStorage

# These can be generated by following the instructions in the `key-generator` folder
# A temporary key will be used if these are not specified
# --> keys generated with https://github.com/powersync-ja/powersync-jwks-example/blob/main/README.md
POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9
POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9

# When developing on the android emulator
#POWERSYNC_URL=http://10.0.2.2:8080

# Otherwise
POWERSYNC_URL=http://localhost:8080
21 changes: 18 additions & 3 deletions config/prod.env
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ DJANGO_DB_HOST=db
DJANGO_DB_PORT=5432
DJANGO_PERFORM_MIGRATIONS=True # Perform any new database migrations on startup

# postgres://<DJANGO_DB_USER>:<DJANGO_DB_PASSWORD>@<DJANGO_DB_PHOST>:<DJANGO_DB_PORT>/<DJANGO_DB_DATABASE>
PS_PG_URI=postgres://wger:wger@db:5432/wger
PS_MONGO_URI: mongodb://mongo:27017/powersync_wger

#
# Cache
DJANGO_CACHE_BACKEND=django_redis.cache.RedisCache
Expand Down Expand Up @@ -133,6 +137,7 @@ DJANGO_DEBUG=False
WGER_USE_GUNICORN=True
EXERCISE_CACHE_TTL=86400 # in seconds - 24*60*60, 24 hours
SITE_URL=http://localhost
WGER_PORT=8000 # Only change if you have a very different setup and know what you are doing

#
# JWT auth
Expand Down Expand Up @@ -169,6 +174,14 @@ USE_RECAPTCHA=False
# being copied correctly, clearing everything might help
DJANGO_CLEAR_STATIC_FIRST=False

# Whether to collect static files on startup. If this flag is set to false,
# the startup time will be faster as no files need to be processed, however
# in this case you will need to run this step manually with
# "docker compose exec web python3 manage.py collectstatic --no-input"
# after the server has started. Failing to do so might cause important files like
# the react js to get "out of sync" with the backend
DJANGO_COLLECTSTATIC_ON_STARTUP=True

#
# Email
# https://docs.djangoproject.com/en/4.1/topics/email/#smtp-backend
Expand All @@ -185,9 +198,6 @@ FROM_EMAIL='wger Workout Manager <wger@example.com>'
# Needs a working email configuration
# DJANGO_ADMINS=your name,email@example.com

# Whether to compress css and js files into one (of each)
# COMPRESS_ENABLED=True

#
# Django Rest Framework
# The number of proxies in front of the application. In the default configuration
Expand All @@ -208,3 +218,8 @@ GUNICORN_CMD_ARGS="--workers 3 --threads 2 --worker-class gthread --timeout 240"
#
# Prometheus metrics
EXPOSE_PROMETHEUS_METRICS=False


#
# Powersync
PS_PORT=8080
3 changes: 3 additions & 0 deletions dev-postgres-powersync/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copy to .env

WGER_CODEPATH=/path/to/wger/server
78 changes: 78 additions & 0 deletions dev-postgres-powersync/config-powersync/powersync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# yaml-language-server: $schema=../schema/schema.json

# Note that this example uses YAML custom tags for environment variable substitution.
# Using `!env [variable name]` will substitute the value of the environment variable named
# [variable name].
#
# Only environment variables with names starting with `PS_` can be substituted.
#
# e.g. With the environment variable `export PS_MONGO_URI=mongodb://localhost:27017`
# and YAML code:
# uri: !env PS_MONGO_URI
# The YAML will resolve to:
# uri: mongodb://localhost:27017
#
# If using VS Code see the `.vscode/settings.json` definitions which define custom tags.

# migrations:
# # Migrations run automatically by default.
# # Setting this to true will skip automatic migrations.
# # Migrations can be triggered externally by altering the container `command`.
# disable_auto_migration: true

# Settings for telemetry reporting
# See https://docs.powersync.com/self-hosting/telemetry
telemetry:
# Opt out of reporting anonymized usage metrics to PowerSync telemetry service
disable_telemetry_sharing: false

# Settings for source database replication
replication:
# Specify database connection details
# Note only 1 connection is currently supported
# Multiple connection support is on the roadmap
connections:
- type: postgresql
# The PowerSync server container can access the Postgres DB via the DB's service name.
# In this case the hostname is db

# The connection URI or individual parameters can be specified.
# Individual params take precedence over URI params
uri: !env PS_PG_URI

# Or use individual params

# hostname: db # From the Docker Compose service name
# port: 5432
# database: postgres
# username: postgres
# password: mypassword

# SSL settings
sslmode: disable # 'verify-full' (default) or 'verify-ca' or 'disable'
# 'disable' is OK for local/private networks, not for public networks


# Connection settings for sync bucket storage
storage:
type: mongodb
uri: !env PS_MONGO_URI

# The port which the PowerSync API server will listen on
port: !env PS_PORT

# Specify sync rules
sync_rules:
path: sync_rules.yaml

# Client (application end user) authentication settings
client_auth:
# Enable this if using Supabase Auth
# supabase: true
allow_local_jwks: true

# JWKS URIs can be specified here
jwks_uri: !env PS_JWKS_URL

# JWKS audience
audience: ["powersync-dev", "powersync"]
86 changes: 86 additions & 0 deletions dev-postgres-powersync/config-powersync/sync_rules.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# See Documentation for more information:
# https://docs.powersync.com/usage/sync-rules
# Note that changes to this file are not watched.
# The service needs to be restarted for changes to take effect.
# Warning, parameter queries have a limit of 1000 rows (before filtering)!

config:
edition: 3

# For details, see the documentation: https://docs.powersync.com/sync/streams/overview
streams:
core:
auto_subscribe: true
queries:
# Translated from "global" bucket definition.
- SELECT * FROM core_language
- SELECT * FROM core_license
- SELECT * FROM core_repetitionunit
- SELECT * FROM core_weightunit
- SELECT * FROM exercises_exercise
- SELECT * FROM exercises_translation
- SELECT * FROM exercises_alias
- SELECT * FROM exercises_muscle
- SELECT * FROM exercises_exercise_muscles
- SELECT * FROM exercises_exercise_muscles_secondary
- SELECT * FROM exercises_equipment
- SELECT * FROM exercises_exercise_equipment
- SELECT * FROM exercises_exercisecategory
- SELECT * FROM exercises_exerciseimage
- SELECT * FROM exercises_exercisevideo
- SELECT * FROM exercises_variation

user_streams:
auto_subscribe: true
queries:
# Weight
- "SELECT uuid AS id, * FROM weight_weightentry WHERE user_id = auth.user_id()"

# Routines
- "SELECT uuid AS id, * FROM manager_workoutlog WHERE user_id = auth.user_id()"
- "SELECT uuid AS id, * FROM manager_workoutsession WHERE user_id = auth.user_id()"

# Measurements
#- "SELECT uuid AS id, * FROM measurements_category WHERE user_id = auth.user_id()"
- "SELECT * FROM measurements_category WHERE user_id = auth.user_id()"
- |
SELECT
measurements_measurement.*
FROM measurements_measurement
INNER JOIN measurements_category
ON measurements_measurement.category_id = measurements_category.id
WHERE measurements_category.user_id = auth.user_id()

# Nutrition
# note: we are restricted by <=1000 distinct ingredient_id values here
- |
SELECT DISTINCT
nutrition_ingredient.*
FROM
nutrition_ingredient
WHERE
-- ingredients directly logged by the user
nutrition_ingredient.id IN (
SELECT
nutrition_logitem.ingredient_id
FROM
nutrition_logitem
JOIN
nutrition_nutritionplan ON nutrition_logitem.plan_id = nutrition_nutritionplan.id
WHERE
nutrition_nutritionplan.user_id = auth.user_id()
)
OR
-- ingredients added to nutritional plans
nutrition_ingredient.id IN (
SELECT
nutrition_mealitem.ingredient_id
FROM
nutrition_mealitem
JOIN
nutrition_meal ON nutrition_mealitem.meal_id = nutrition_meal.id
JOIN
nutrition_nutritionplan ON nutrition_meal.plan_id = nutrition_nutritionplan.id
WHERE
nutrition_nutritionplan.user_id = auth.user_id()
);
74 changes: 74 additions & 0 deletions dev-postgres-powersync/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: wger-dev-postgres-powersync

services:
web:
build:
pull: true
context: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable}
dockerfile: ./extras/docker/development/Dockerfile
develop:
watch:
- action: sync
path: ${WGER_CODEPATH}
target: /home/wger/src
- action: rebuild
path: ${WGER_CODEPATH}/pyproject.toml
- action: rebuild
path: ${WGER_CODEPATH}/package.json
depends_on:
db:
condition: service_healthy
env_file:
- ../config/prod.env
- ../config/dev.env
ports:
- "8000:8000"

cache:
image: docker.io/redis:latest
expose:
- 6379
healthcheck:
test: redis-cli ping
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped

db:
image: docker.io/postgres:15-alpine
environment:
- POSTGRES_USER=wger
- POSTGRES_PASSWORD=wger
- POSTGRES_DB=wger
volumes:
- postgres-dev-data:/var/lib/postgresql/data/
# automatically import dump
#- ../wger-2026-01-15-1410.dump:/docker-entrypoint-initdb.d/00-init-db.sql:ro
#- ../wger-reset-password.sql:/docker-entrypoint-initdb.d/01-reset-pw.sql:ro
#- ../wger-cleanup.sql:/docker-entrypoint-initdb.d/02-cleanup.sql:ro
ports:
- "5432:5432"
expose:
- 5432
# "-c", "log_statement=all", "-c", "log_min_error_statement=DEBUG1"
command: ["postgres", "-c", "wal_level=logical"]
healthcheck:
test: pg_isready -U wger
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped

volumes:
postgres-dev-data:

networks:
default:
name: wger-dev-network

include:
- path: powersync-services/mongo.yaml
- path: powersync-services/powersync.yaml
24 changes: 24 additions & 0 deletions dev-postgres-powersync/powersync-services/mongo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
services:
# MongoDB Service used internally
mongo:
image: docker.io/mongo:8
command: --replSet rs0 --bind_ip_all --quiet
restart: unless-stopped
ports:
- 27017:27017
volumes:
- mongo_storage:/data/db
healthcheck:
test: |
test $$(mongosh --quiet --eval "
try {
rs.status().ok
} catch {
rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongo:27017'}]}).ok
}
") -eq 1
interval: 60s
start_period: 5s

volumes:
mongo_storage:
Loading